Blame bc/scan.l

Packit 70b277
/*  This file is part of GNU bc.
Packit 70b277
Packit 70b277
    Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
Packit 70b277
Packit 70b277
    This program is free software; you can redistribute it and/or modify
Packit 70b277
    it under the terms of the GNU General Public License as published by
Packit 70b277
    the Free Software Foundation; either version 3 of the License , or
Packit 70b277
    (at your option) any later version.
Packit 70b277
Packit 70b277
    This program is distributed in the hope that it will be useful,
Packit 70b277
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 70b277
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 70b277
    GNU General Public License for more details.
Packit 70b277
Packit 70b277
    You should have received a copy of the GNU General Public License
Packit 70b277
    along with this program; see the file COPYING.  If not, see
Packit 70b277
    <http://www.gnu.org/licenses>.
Packit 70b277
Packit 70b277
    You may contact the author by:
Packit 70b277
       e-mail:  philnelson@acm.org
Packit 70b277
      us-mail:  Philip A. Nelson
Packit 70b277
                Computer Science Department, 9062
Packit 70b277
                Western Washington University
Packit 70b277
                Bellingham, WA 98226-9062
Packit 70b277
       
Packit 70b277
*************************************************************************/
Packit 70b277
Packit 70b277
/* scan.l: the (f)lex description file for the scanner. */
Packit 70b277
Packit 70b277
%{
Packit 70b277
Packit 70b277
#include "bcdefs.h"
Packit 70b277
#include "bc.h"
Packit 70b277
#include "global.h"
Packit 70b277
#include "proto.h"
Packit 70b277
#include <errno.h>
Packit 70b277
Packit 70b277
/* Using flex, we can ask for a smaller input buffer.  With lex, this
Packit 70b277
   does nothing! */
Packit 70b277
Packit 70b277
#ifdef SMALL_BUF
Packit 70b277
#undef YY_READ_BUF_SIZE
Packit 70b277
#define YY_READ_BUF_SIZE 512
Packit 70b277
#endif
Packit 70b277
Packit 70b277
/* Force . as last for now. */
Packit 70b277
#define DOT_IS_LAST
Packit 70b277
Packit 70b277
/* We want to define our own yywrap. */
Packit 70b277
#undef yywrap
Packit 70b277
int yywrap (void);
Packit 70b277
Packit 70b277
#if defined(LIBEDIT)
Packit 70b277
/* Support for the BSD libedit with history for
Packit 70b277
   nicer input on the interactive part of input. */
Packit 70b277
Packit 70b277
#include <histedit.h>
Packit 70b277
Packit 70b277
/* Have input call the following function. */
Packit 70b277
#undef  YY_INPUT
Packit 70b277
#define YY_INPUT(buf,result,max_size) \
Packit 70b277
		bcel_input((char *)buf, (yy_size_t *)&result, max_size)
Packit 70b277
Packit 70b277
/* Variables to help interface editline with bc. */
Packit 70b277
static const char *bcel_line = (char *)NULL;
Packit 70b277
static int   bcel_len = 0;
Packit 70b277
Packit 70b277
/* bcel_input puts upto MAX characters into BUF with the number put in
Packit 70b277
   BUF placed in *RESULT.  If the yy input file is the same as
Packit 70b277
   stdin, use editline.  Otherwise, just read it.
Packit 70b277
*/
Packit 70b277
Packit 70b277
static void
Packit 70b277
bcel_input (char *buf, yy_size_t  *result, int max)
Packit 70b277
{
Packit 70b277
  ssize_t rdsize;
Packit 70b277
  if (!edit || yyin != stdin)
Packit 70b277
    {
Packit 70b277
      while ( (rdsize = read( fileno(yyin), buf, max )) < 0 )
Packit 70b277
        if (errno != EINTR)
Packit 70b277
	  {
Packit 70b277
	    yyerror( "read() in flex scanner failed" );
Packit 70b277
	    bc_exit (1);
Packit 70b277
	  }
Packit 70b277
      *result = (yy_size_t) rdsize;
Packit 70b277
      return;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Do we need a new string? */
Packit 70b277
  if (bcel_len == 0)
Packit 70b277
    {
Packit 70b277
      bcel_line = el_gets(edit, &bcel_len);
Packit 70b277
      if (bcel_line == NULL) {
Packit 70b277
	/* end of file */
Packit 70b277
	*result = 0;
Packit 70b277
	bcel_len = 0;
Packit 70b277
	return;
Packit 70b277
      }
Packit 70b277
      if (bcel_len != 0)
Packit 70b277
	history (hist, &histev, H_ENTER, bcel_line); 
Packit 70b277
      fflush (stdout);
Packit 70b277
    }
Packit 70b277
Packit 70b277
  if (bcel_len <= max)
Packit 70b277
    {
Packit 70b277
      strncpy (buf, bcel_line, bcel_len);
Packit 70b277
      *result = bcel_len;
Packit 70b277
      bcel_len = 0;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      strncpy (buf, bcel_line, max);
Packit 70b277
      *result = max;
Packit 70b277
      bcel_line += max;
Packit 70b277
      bcel_len -= max;
Packit 70b277
    }
Packit 70b277
}
Packit 70b277
#endif
Packit 70b277
Packit 70b277
#ifdef READLINE
Packit 70b277
/* Support for the readline and history libraries.  This allows
Packit 70b277
   nicer input on the interactive part of input. */
Packit 70b277
Packit 70b277
/* Have input call the following function. */
Packit 70b277
#undef  YY_INPUT
Packit 70b277
#define YY_INPUT(buf,result,max_size) \
Packit 70b277
		rl_input((char *)buf, &result, max_size)
Packit 70b277
Packit 70b277
/* Variables to help interface readline with bc. */
Packit 70b277
static char *rl_line = (char *)NULL;
Packit 70b277
static char *rl_start = (char *)NULL;
Packit 70b277
static int   rl_len = 0;
Packit 70b277
Packit 70b277
/* Definitions for readline access. */
Packit 70b277
extern FILE *rl_instream;
Packit 70b277
Packit 70b277
/* rl_input puts upto MAX characters into BUF with the number put in
Packit 70b277
   BUF placed in *RESULT.  If the yy input file is the same as
Packit 70b277
   rl_instream (stdin), use readline.  Otherwise, just read it.
Packit 70b277
*/
Packit 70b277
Packit 70b277
static void
Packit 70b277
rl_input (char *buf, int *result, int max)
Packit 70b277
{
Packit 70b277
  if (yyin != rl_instream)
Packit 70b277
    {
Packit 70b277
      while ( (*result = read( fileno(yyin), buf, max )) < 0 )
Packit 70b277
        if (errno != EINTR)
Packit 70b277
	  {
Packit 70b277
	    yyerror( "read() in flex scanner failed" );
Packit 70b277
	    bc_exit (1);
Packit 70b277
	  }
Packit 70b277
      return;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Do we need a new string? */
Packit 70b277
  if (rl_len == 0)
Packit 70b277
    {
Packit 70b277
      if (rl_start)
Packit 70b277
	free(rl_start);
Packit 70b277
      rl_start = readline ("");
Packit 70b277
      if (rl_start == NULL) {
Packit 70b277
	/* end of file */
Packit 70b277
	*result = 0;
Packit 70b277
	rl_len = 0;
Packit 70b277
	return;
Packit 70b277
      }
Packit 70b277
      rl_line = rl_start;
Packit 70b277
      rl_len = strlen (rl_line)+1;
Packit 70b277
      if (rl_len != 1)
Packit 70b277
	add_history (rl_line); 
Packit 70b277
      rl_line[rl_len-1] = '\n';
Packit 70b277
      fflush (stdout);
Packit 70b277
    }
Packit 70b277
Packit 70b277
  if (rl_len <= max)
Packit 70b277
    {
Packit 70b277
      strncpy (buf, rl_line, rl_len);
Packit 70b277
      *result = rl_len;
Packit 70b277
      rl_len = 0;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      strncpy (buf, rl_line, max);
Packit 70b277
      *result = max;
Packit 70b277
      rl_line += max;
Packit 70b277
      rl_len -= max;
Packit 70b277
    }
Packit 70b277
}
Packit 70b277
#endif
Packit 70b277
Packit 70b277
#if !defined(READLINE) && !defined(LIBEDIT)
Packit 70b277
Packit 70b277
/* MINIX returns from read with < 0 if SIGINT is  encountered.
Packit 70b277
   In flex, we can redefine YY_INPUT to the following.  In lex, this
Packit 70b277
   does nothing! */
Packit 70b277
#undef  YY_INPUT
Packit 70b277
#define YY_INPUT(buf,result,max_size) \
Packit 70b277
	while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
Packit 70b277
	    if (errno != EINTR) \
Packit 70b277
		YY_FATAL_ERROR( "read() in flex scanner failed" );
Packit 70b277
#endif
Packit 70b277
Packit 70b277
%}
Packit 70b277
DIGIT [0-9A-Z]
Packit 70b277
LETTER [a-z]
Packit 70b277
%s slcomment
Packit 70b277
%%
Packit 70b277
"#"		{
Packit 70b277
 		  if (!std_only)
Packit 70b277
		    BEGIN(slcomment);
Packit 70b277
 		  else
Packit 70b277
		    yyerror ("illegal character: #");
Packit 70b277
		}
Packit 70b277
<slcomment>[^\n]* { BEGIN(INITIAL); }
Packit 70b277
<slcomment>"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); }
Packit 70b277
define return(Define);
Packit 70b277
break  return(Break);
Packit 70b277
quit   return(Quit);
Packit 70b277
length return(Length);
Packit 70b277
return return(Return);
Packit 70b277
for    return(For);
Packit 70b277
if     return(If);
Packit 70b277
while  return(While);
Packit 70b277
sqrt   return(Sqrt);
Packit 70b277
scale  return(Scale);
Packit 70b277
ibase  return(Ibase);
Packit 70b277
obase  return(Obase);
Packit 70b277
auto   return(Auto);
Packit 70b277
else   return(Else);
Packit 70b277
read   return(Read);
Packit 70b277
random return(Random);
Packit 70b277
halt   return(Halt);
Packit 70b277
last   return(Last);
Packit 70b277
void   return(Void); 
Packit 70b277
history {
Packit 70b277
#if defined(READLINE) || defined(LIBEDIT)
Packit 70b277
	  return(HistoryVar);
Packit 70b277
#else
Packit 70b277
	  yylval.s_value = strcopyof(yytext); return(NAME);
Packit 70b277
#endif
Packit 70b277
	}
Packit 70b277
Packit 70b277
warranty return(Warranty);
Packit 70b277
continue return(Continue);
Packit 70b277
print  return(Print);
Packit 70b277
limits return(Limits);
Packit 70b277
"." {
Packit 70b277
#ifdef DOT_IS_LAST
Packit 70b277
       return(Last);
Packit 70b277
#else
Packit 70b277
       yyerror ("illegal character: %s",yytext);
Packit 70b277
#endif
Packit 70b277
    }
Packit 70b277
"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; 
Packit 70b277
					      return((int)yytext[0]); }
Packit 70b277
&& { return(AND); }
Packit 70b277
\|\| { return(OR); }
Packit 70b277
"!" { return(NOT); }
Packit 70b277
"*"|"/"|"%"|"&" { yylval.c_value = yytext[0]; return((int)yytext[0]); }
Packit 70b277
"="|\+=|-=|\*=|\/=|%=|\^=  { yylval.c_value = yytext[0]; return(ASSIGN_OP); }
Packit 70b277
=\+|=-|=\*|=\/|=%|=\^  { 
Packit 70b277
#ifdef OLD_EQ_OP
Packit 70b277
			 char warn_save;
Packit 70b277
			 warn_save = warn_not_std;
Packit 70b277
			 warn_not_std = TRUE;
Packit 70b277
			 ct_warn ("Old fashioned =<op>");
Packit 70b277
			 warn_not_std = warn_save;
Packit 70b277
			 yylval.c_value = yytext[1];
Packit 70b277
#else
Packit 70b277
			 yylval.c_value = '=';
Packit 70b277
			 yyless (1);
Packit 70b277
#endif
Packit 70b277
			 return(ASSIGN_OP);
Packit 70b277
		       }
Packit 70b277
==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); }
Packit 70b277
\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); }
Packit 70b277
"\n" { line_no++; return(ENDOFLINE); }
Packit 70b277
\\\n {  line_no++;  /* ignore a "quoted" newline */ }
Packit 70b277
[ \t]+  { /* ignore spaces and tabs */ }
Packit 70b277
"/*"  {
Packit 70b277
	int c;
Packit 70b277
Packit 70b277
	for (;;)
Packit 70b277
	  {
Packit 70b277
	    while ( ((c=input()) != '*') && (c != EOF)) 
Packit 70b277
	      /* eat it */
Packit 70b277
	      if (c == '\n') line_no++;
Packit 70b277
	    if (c == '*')
Packit 70b277
 	      {
Packit 70b277
		while ( (c=input()) == '*') /* eat it*/;
Packit 70b277
		if (c == '/') break; /* at end of comment */
Packit 70b277
		if (c == '\n') line_no++;
Packit 70b277
	      }
Packit 70b277
	    if (c == EOF)
Packit 70b277
	      {
Packit 70b277
		fprintf (stderr,"EOF encountered in a comment.\n");
Packit 70b277
		break;
Packit 70b277
	      }
Packit 70b277
	  }
Packit 70b277
      }
Packit 70b277
[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); }
Packit 70b277
\"[^\"]*\"  {
Packit 70b277
 	      const char *look;
Packit 70b277
	      int count = 0;
Packit 70b277
	      yylval.s_value = strcopyof(yytext);
Packit 70b277
	      for (look = yytext; *look != 0; look++)
Packit 70b277
		{
Packit 70b277
		  if (*look == '\n') line_no++;
Packit 70b277
		  if (*look == '"')  count++;
Packit 70b277
		}
Packit 70b277
	      if (count != 2) yyerror ("NUL character in string.");
Packit 70b277
	      return(STRING);
Packit 70b277
	    }
Packit 70b277
{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* {
Packit 70b277
	      char *src, *dst;
Packit 70b277
	      int len;
Packit 70b277
	      /* remove a trailing decimal point. */
Packit 70b277
	      len = strlen(yytext);
Packit 70b277
	      if (yytext[len-1] == '.')
Packit 70b277
	        yytext[len-1] = 0;
Packit 70b277
	      /* remove leading zeros. */
Packit 70b277
	      src = yytext;
Packit 70b277
	      dst = yytext;
Packit 70b277
	      while (*src == '0') src++;
Packit 70b277
	      if (*src == 0) src--;
Packit 70b277
	      /* Copy strings removing the newlines. */
Packit 70b277
	      while (*src != 0)
Packit 70b277
		{
Packit 70b277
	          if (*src == '\\')
Packit 70b277
		    {
Packit 70b277
		      src++; src++;
Packit 70b277
		      line_no++;
Packit 70b277
		    }
Packit 70b277
		  if (*src == ',')
Packit 70b277
		    {
Packit 70b277
		      src++;
Packit 70b277
		      ct_warn("Commas in numbers");
Packit 70b277
		    }		    
Packit 70b277
		  else
Packit 70b277
		    *dst++ = *src++;
Packit 70b277
	        }
Packit 70b277
	      *dst = 0;
Packit 70b277
	      yylval.s_value = strcopyof(yytext); 
Packit 70b277
	      return(NUMBER);
Packit 70b277
	    }
Packit 70b277
.       {
Packit 70b277
	  if (yytext[0] < ' ')
Packit 70b277
	    yyerror ("illegal character: ^%c",yytext[0] + '@');
Packit 70b277
	  else
Packit 70b277
	    if (yytext[0] > '~')
Packit 70b277
	      yyerror ("illegal character: \\%03o", (int) yytext[0]);
Packit 70b277
	    else
Packit 70b277
	      yyerror ("illegal character: %s",yytext);
Packit 70b277
	}
Packit 70b277
%%
Packit 70b277
Packit 70b277
Packit 70b277
Packit 70b277
/* This is the way to get multiple files input into lex. */
Packit 70b277
Packit 70b277
int
Packit 70b277
yywrap(void)
Packit 70b277
{
Packit 70b277
  if (!open_new_file ()) return (1);	/* EOF on standard in. */
Packit 70b277
  return (0);          			/* We have more input. */
Packit 70b277
  yyunput(0,NULL);	/* Make sure the compiler think yyunput is used. */
Packit 70b277
}