1/* $NetBSD: scan.l,v 1.1 2017/04/10 02:28:23 phil Exp $ */ 2 3/* 4 * Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc. 5 * Copyright (C) 2016-2017 Philip A. Nelson. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The names Philip A. Nelson and Free Software Foundation may not be 18 * used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY PHILIP A. NELSON ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL PHILIP A. NELSON OR THE FREE SOFTWARE FOUNDATION BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* scan.l: the (f)lex description file for the scanner. */ 35 36%{ 37 38#include "bcdefs.h" 39#include "bc.h" 40#include "global.h" 41#include "proto.h" 42#include <errno.h> 43 44/* Using flex, we can ask for a smaller input buffer. With lex, this 45 does nothing! */ 46 47#ifdef SMALL_BUF 48#undef YY_READ_BUF_SIZE 49#define YY_READ_BUF_SIZE 512 50#endif 51 52/* Force . as last for now. */ 53#define DOT_IS_LAST 54 55/* We want to define our own yywrap. */ 56#undef yywrap 57int yywrap (void); 58 59#if defined(LIBEDIT) 60/* Support for the BSD libedit with history for 61 nicer input on the interactive part of input. */ 62 63#include <histedit.h> 64 65/* Have input call the following function. */ 66#undef YY_INPUT 67#define YY_INPUT(buf,result,max_size) \ 68 bcel_input((char *)buf, (yy_size_t *)&result, max_size) 69 70/* Variables to help interface editline with bc. */ 71static const char *bcel_line = (char *)NULL; 72static int bcel_len = 0; 73 74/* bcel_input puts upto MAX characters into BUF with the number put in 75 BUF placed in *RESULT. If the yy input file is the same as 76 stdin, use editline. Otherwise, just read it. 77*/ 78 79static void 80bcel_input (char *buf, yy_size_t *result, int max) 81{ 82 ssize_t rdsize; 83 if (!edit || yyin != stdin) 84 { 85 while ( (rdsize = read( fileno(yyin), buf, max )) < 0 ) 86 if (errno != EINTR) 87 { 88 yyerror( "read() in flex scanner failed" ); 89 bc_exit (1); 90 } 91 *result = (yy_size_t) rdsize; 92 return; 93 } 94 95 /* Do we need a new string? */ 96 if (bcel_len == 0) 97 { 98 bcel_line = el_gets(edit, &bcel_len); 99 if (bcel_line == NULL) { 100 /* end of file */ 101 *result = 0; 102 bcel_len = 0; 103 return; 104 } 105 if (bcel_len != 0) 106 history (hist, &histev, H_ENTER, bcel_line); 107 fflush (stdout); 108 } 109 110 if (bcel_len <= max) 111 { 112 strncpy (buf, bcel_line, bcel_len); 113 *result = bcel_len; 114 bcel_len = 0; 115 } 116 else 117 { 118 strncpy (buf, bcel_line, max); 119 *result = max; 120 bcel_line += max; 121 bcel_len -= max; 122 } 123} 124#endif 125 126#ifdef READLINE 127/* Support for the readline and history libraries. This allows 128 nicer input on the interactive part of input. */ 129 130/* Have input call the following function. */ 131#undef YY_INPUT 132#define YY_INPUT(buf,result,max_size) \ 133 rl_input((char *)buf, &result, max_size) 134 135/* Variables to help interface readline with bc. */ 136static char *rl_line = (char *)NULL; 137static char *rl_start = (char *)NULL; 138static int rl_len = 0; 139 140/* Definitions for readline access. */ 141extern FILE *rl_instream; 142 143/* rl_input puts upto MAX characters into BUF with the number put in 144 BUF placed in *RESULT. If the yy input file is the same as 145 rl_instream (stdin), use readline. Otherwise, just read it. 146*/ 147 148static void 149rl_input (char *buf, int *result, int max) 150{ 151 if (yyin != rl_instream) 152 { 153 while ( (*result = read( fileno(yyin), buf, max )) < 0 ) 154 if (errno != EINTR) 155 { 156 yyerror( "read() in flex scanner failed" ); 157 bc_exit (1); 158 } 159 return; 160 } 161 162 /* Do we need a new string? */ 163 if (rl_len == 0) 164 { 165 if (rl_start) 166 free(rl_start); 167 rl_start = readline (""); 168 if (rl_start == NULL) { 169 /* end of file */ 170 *result = 0; 171 rl_len = 0; 172 return; 173 } 174 rl_line = rl_start; 175 rl_len = strlen (rl_line)+1; 176 if (rl_len != 1) 177 add_history (rl_line); 178 rl_line[rl_len-1] = '\n'; 179 fflush (stdout); 180 } 181 182 if (rl_len <= max) 183 { 184 strncpy (buf, rl_line, rl_len); 185 *result = rl_len; 186 rl_len = 0; 187 } 188 else 189 { 190 strncpy (buf, rl_line, max); 191 *result = max; 192 rl_line += max; 193 rl_len -= max; 194 } 195} 196#endif 197 198#if !defined(READLINE) && !defined(LIBEDIT) 199 200/* MINIX returns from read with < 0 if SIGINT is encountered. 201 In flex, we can redefine YY_INPUT to the following. In lex, this 202 does nothing! */ 203#undef YY_INPUT 204#define YY_INPUT(buf,result,max_size) \ 205 while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ 206 if (errno != EINTR) \ 207 YY_FATAL_ERROR( "read() in flex scanner failed" ); 208#endif 209 210%} 211DIGIT [0-9A-Z] 212LETTER [a-z] 213%s slcomment 214%% 215"#" { 216 if (!std_only) 217 BEGIN(slcomment); 218 else 219 yyerror ("illegal character: #"); 220 } 221<slcomment>[^\n]* { BEGIN(INITIAL); } 222<slcomment>"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); } 223define return(Define); 224break return(Break); 225quit return(Quit); 226length return(Length); 227return return(Return); 228for return(For); 229if return(If); 230while return(While); 231sqrt return(Sqrt); 232scale return(Scale); 233ibase return(Ibase); 234obase return(Obase); 235auto return(Auto); 236else return(Else); 237read return(Read); 238random return(Random); 239halt return(Halt); 240last return(Last); 241void return(Void); 242history { 243#if defined(READLINE) || defined(LIBEDIT) 244 return(HistoryVar); 245#else 246 yylval.s_value = strcopyof(yytext); return(NAME); 247#endif 248 } 249 250warranty return(Warranty); 251continue return(Continue); 252print return(Print); 253limits return(Limits); 254"." { 255#ifdef DOT_IS_LAST 256 return(Last); 257#else 258 yyerror ("illegal character: %s",yytext); 259#endif 260 } 261"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; 262 return((int)yytext[0]); } 263&& { return(AND); } 264\|\| { return(OR); } 265"!" { return(NOT); } 266"*"|"/"|"%"|"&" { yylval.c_value = yytext[0]; return((int)yytext[0]); } 267"="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); } 268=\+|=-|=\*|=\/|=%|=\^ { 269#ifdef OLD_EQ_OP 270 char warn_save; 271 warn_save = warn_not_std; 272 warn_not_std = TRUE; 273 ct_warn ("Old fashioned =<op>"); 274 warn_not_std = warn_save; 275 yylval.c_value = yytext[1]; 276#else 277 yylval.c_value = '='; 278 yyless (1); 279#endif 280 return(ASSIGN_OP); 281 } 282==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); } 283\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); } 284"\n" { line_no++; return(ENDOFLINE); } 285\\\n { line_no++; /* ignore a "quoted" newline */ } 286[ \t]+ { /* ignore spaces and tabs */ } 287"/*" { 288 int c; 289 290 for (;;) 291 { 292 while ( ((c=input()) != '*') && (c != EOF)) 293 /* eat it */ 294 if (c == '\n') line_no++; 295 if (c == '*') 296 { 297 while ( (c=input()) == '*') /* eat it*/; 298 if (c == '/') break; /* at end of comment */ 299 if (c == '\n') line_no++; 300 } 301 if (c == EOF) 302 { 303 fprintf (stderr,"EOF encountered in a comment.\n"); 304 break; 305 } 306 } 307 } 308[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); } 309\"[^\"]*\" { 310 const char *look; 311 int count = 0; 312 yylval.s_value = strcopyof(yytext); 313 for (look = yytext; *look != 0; look++) 314 { 315 if (*look == '\n') line_no++; 316 if (*look == '"') count++; 317 } 318 if (count != 2) yyerror ("NUL character in string."); 319 return(STRING); 320 } 321{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* { 322 char *src, *dst; 323 int len; 324 /* remove a trailing decimal point. */ 325 len = strlen(yytext); 326 if (yytext[len-1] == '.') 327 yytext[len-1] = 0; 328 /* remove leading zeros. */ 329 src = yytext; 330 dst = yytext; 331 while (*src == '0') src++; 332 if (*src == 0) src--; 333 /* Copy strings removing the newlines. */ 334 while (*src != 0) 335 { 336 if (*src == '\\') 337 { 338 src++; src++; 339 line_no++; 340 } 341 if (*src == ',') 342 { 343 src++; 344 ct_warn("Commas in numbers"); 345 } 346 else 347 *dst++ = *src++; 348 } 349 *dst = 0; 350 yylval.s_value = strcopyof(yytext); 351 return(NUMBER); 352 } 353. { 354 if (yytext[0] < ' ') 355 yyerror ("illegal character: ^%c",yytext[0] + '@'); 356 else 357 if (yytext[0] > '~') 358 yyerror ("illegal character: \\%03o", (int) yytext[0]); 359 else 360 yyerror ("illegal character: %s",yytext); 361 } 362%% 363 364 365 366/* This is the way to get multiple files input into lex. */ 367 368int 369yywrap(void) 370{ 371 if (!open_new_file ()) return (1); /* EOF on standard in. */ 372 return (0); /* We have more input. */ 373 yyunput(0,NULL); /* Make sure the compiler think yyunput is used. */ 374} 375