1%{ 2/* scan.l: the (f)lex description file for the scanner. */ 3 4/* This file is part of GNU bc. 5 Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License , or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; see the file COPYING. If not, write to 19 The Free Software Foundation, Inc. 20 59 Temple Place, Suite 330 21 Boston, MA 02111 USA 22 23 You may contact the author by: 24 e-mail: philnelson@acm.org 25 us-mail: Philip A. Nelson 26 Computer Science Department, 9062 27 Western Washington University 28 Bellingham, WA 98226-9062 29 30*************************************************************************/ 31 32#include "bcdefs.h" 33#include "bc.h" 34#include "global.h" 35#include "proto.h" 36#include <errno.h> 37 38/* Using flex, we can ask for a smaller input buffer. With lex, this 39 does nothing! */ 40 41#ifdef SMALL_BUF 42#undef YY_READ_BUF_SIZE 43#define YY_READ_BUF_SIZE 512 44#endif 45 46/* Force . as last for now. */ 47#define DOT_IS_LAST 48 49/* We want to define our own yywrap. */ 50#undef yywrap 51_PROTOTYPE(int yywrap, (void)); 52 53#if defined(LIBEDIT) 54/* Support for the BSD libedit with history for 55 nicer input on the interactive part of input. */ 56 57#include <histedit.h> 58 59/* Have input call the following function. */ 60#undef YY_INPUT 61#define YY_INPUT(buf,result,max_size) \ 62 bcel_input((char *)buf, &result, max_size) 63 64/* Variables to help interface editline with bc. */ 65static const char *bcel_line = (char *)NULL; 66static int bcel_len = 0; 67 68 69/* Required to get rid of that ugly ? default prompt! */ 70char * 71null_prompt (EditLine *el) 72{ 73 return ""; 74} 75 76 77/* bcel_input puts upto MAX characters into BUF with the number put in 78 BUF placed in *RESULT. If the yy input file is the same as 79 stdin, use editline. Otherwise, just read it. 80*/ 81 82static void 83bcel_input (buf, result, max) 84 char *buf; 85 int *result; 86 int max; 87{ 88 if (!edit || yyin != stdin) 89 { 90 while ( (*result = read( fileno(yyin), buf, max )) < 0 ) 91 if (errno != EINTR) 92 { 93 yyerror( "read() in flex scanner failed" ); 94 exit (1); 95 } 96 return; 97 } 98 99 /* Do we need a new string? */ 100 if (bcel_len == 0) 101 { 102 bcel_line = el_gets(edit, &bcel_len); 103 if (bcel_line == NULL) { 104 /* end of file */ 105 *result = 0; 106 bcel_len = 0; 107 return; 108 } 109 if (bcel_len != 0) 110 history (hist, &histev, H_ENTER, bcel_line); 111 fflush (stdout); 112 } 113 114 if (bcel_len <= max) 115 { 116 strncpy (buf, bcel_line, bcel_len); 117 *result = bcel_len; 118 bcel_len = 0; 119 } 120 else 121 { 122 strncpy (buf, bcel_line, max); 123 *result = max; 124 bcel_line += max; 125 bcel_len -= max; 126 } 127} 128#endif 129 130#ifdef READLINE 131/* Support for the readline and history libraries. This allows 132 nicer input on the interactive part of input. */ 133 134/* Have input call the following function. */ 135#undef YY_INPUT 136#define YY_INPUT(buf,result,max_size) \ 137 rl_input((char *)buf, &result, max_size) 138 139/* Variables to help interface readline with bc. */ 140static char *rl_line = (char *)NULL; 141static char *rl_start = (char *)NULL; 142static int rl_len = 0; 143 144/* Definitions for readline access. */ 145extern FILE *rl_instream; 146_PROTOTYPE(char *readline, (char *)); 147 148/* rl_input puts upto MAX characters into BUF with the number put in 149 BUF placed in *RESULT. If the yy input file is the same as 150 rl_instream (stdin), use readline. Otherwise, just read it. 151*/ 152 153static void 154rl_input (buf, result, max) 155 char *buf; 156 int *result; 157 int max; 158{ 159 if (yyin != rl_instream) 160 { 161 while ( (*result = read( fileno(yyin), buf, max )) < 0 ) 162 if (errno != EINTR) 163 { 164 yyerror( "read() in flex scanner failed" ); 165 exit (1); 166 } 167 return; 168 } 169 170 /* Do we need a new string? */ 171 if (rl_len == 0) 172 { 173 if (rl_start) 174 free(rl_start); 175 rl_start = readline (""); 176 if (rl_start == NULL) { 177 /* end of file */ 178 *result = 0; 179 rl_len = 0; 180 return; 181 } 182 rl_line = rl_start; 183 rl_len = strlen (rl_line)+1; 184 if (rl_len != 1) 185 add_history (rl_line); 186 rl_line[rl_len-1] = '\n'; 187 fflush (stdout); 188 } 189 190 if (rl_len <= max) 191 { 192 strncpy (buf, rl_line, rl_len); 193 *result = rl_len; 194 rl_len = 0; 195 } 196 else 197 { 198 strncpy (buf, rl_line, max); 199 *result = max; 200 rl_line += max; 201 rl_len -= max; 202 } 203} 204#endif 205 206#if !defined(READLINE) && !defined(LIBEDIT) 207 208/* MINIX returns from read with < 0 if SIGINT is encountered. 209 In flex, we can redefine YY_INPUT to the following. In lex, this 210 does nothing! */ 211#undef YY_INPUT 212#define YY_INPUT(buf,result,max_size) \ 213 while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ 214 if (errno != EINTR) \ 215 YY_FATAL_ERROR( "read() in flex scanner failed" ); 216#endif 217 218%} 219DIGIT [0-9A-F] 220LETTER [a-z] 221%s slcomment 222%% 223"#" { 224 if (!std_only) 225 BEGIN(slcomment); 226 else 227 yyerror ("illegal character: #"); 228 } 229<slcomment>[^\n]* { BEGIN(INITIAL); } 230<slcomment>"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); } 231define return(Define); 232break return(Break); 233quit return(Quit); 234length return(Length); 235return return(Return); 236for return(For); 237if return(If); 238while return(While); 239sqrt return(Sqrt); 240scale return(Scale); 241ibase return(Ibase); 242obase return(Obase); 243auto return(Auto); 244else return(Else); 245read return(Read); 246halt return(Halt); 247last return(Last); 248history { 249#if defined(READLINE) || defined(LIBEDIT) 250 return(HistoryVar); 251#else 252 yylval.s_value = strcopyof(yytext); return(NAME); 253#endif 254 } 255 256warranty return(Warranty); 257continue return(Continue); 258print return(Print); 259limits return(Limits); 260"." { 261#ifdef DOT_IS_LAST 262 return(Last); 263#else 264 yyerror ("illegal character: %s",yytext); 265#endif 266 } 267"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; 268 return((int)yytext[0]); } 269&& { return(AND); } 270\|\| { return(OR); } 271"!" { return(NOT); } 272"*"|"/"|"%" { yylval.c_value = yytext[0]; return((int)yytext[0]); } 273"="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); } 274=\+|=-|=\*|=\/|=%|=\^ { 275#ifdef OLD_EQ_OP 276 char warn_save; 277 warn_save = warn_not_std; 278 warn_not_std = TRUE; 279 warn ("Old fashioned =<op>"); 280 warn_not_std = warn_save; 281 yylval.c_value = yytext[1]; 282#else 283 yylval.c_value = '='; 284 yyless (1); 285#endif 286 return(ASSIGN_OP); 287 } 288==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); } 289\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); } 290"\n" { line_no++; return(ENDOFLINE); } 291\\\n { line_no++; /* ignore a "quoted" newline */ } 292[ \t]+ { /* ignore spaces and tabs */ } 293"/*" { 294 int c; 295 296 for (;;) 297 { 298 while ( ((c=input()) != '*') && (c != EOF)) 299 /* eat it */ 300 if (c == '\n') line_no++; 301 if (c == '*') 302 { 303 while ( (c=input()) == '*') /* eat it*/; 304 if (c == '/') break; /* at end of comment */ 305 if (c == '\n') line_no++; 306 } 307 if (c == EOF) 308 { 309 fprintf (stderr,"EOF encountered in a comment.\n"); 310 break; 311 } 312 } 313 } 314[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); } 315\"[^\"]*\" { 316 unsigned char *look; 317 int count = 0; 318 yylval.s_value = strcopyof(yytext); 319 for (look = yytext; *look != 0; look++) 320 { 321 if (*look == '\n') line_no++; 322 if (*look == '"') count++; 323 } 324 if (count != 2) yyerror ("NUL character in string."); 325 return(STRING); 326 } 327{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* { 328 unsigned char *src, *dst; 329 int len; 330 /* remove a trailing decimal point. */ 331 len = strlen(yytext); 332 if (yytext[len-1] == '.') 333 yytext[len-1] = 0; 334 /* remove leading zeros. */ 335 src = yytext; 336 dst = yytext; 337 while (*src == '0') src++; 338 if (*src == 0) src--; 339 /* Copy strings removing the newlines. */ 340 while (*src != 0) 341 { 342 if (*src == '\\') 343 { 344 src++; src++; 345 line_no++; 346 } 347 else 348 *dst++ = *src++; 349 } 350 *dst = 0; 351 yylval.s_value = strcopyof(yytext); 352 return(NUMBER); 353 } 354. { 355 if (yytext[0] < ' ') 356 yyerror ("illegal character: ^%c",yytext[0] + '@'); 357 else 358 if (yytext[0] > '~') 359 yyerror ("illegal character: \\%03o", (int) yytext[0]); 360 else 361 yyerror ("illegal character: %s",yytext); 362 } 363%% 364 365 366 367/* This is the way to get multiple files input into lex. */ 368 369int 370yywrap() 371{ 372 if (!open_new_file ()) return (1); /* EOF on standard in. */ 373 return (0); /* We have more input. */ 374} 375