|
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 |
}
|