1 %{ 2 /* 3 * Lexer for states. 4 * Copyright (c) 1997-1998 Markku Rossi. 5 * 6 * Author: Markku Rossi <mtr@iki.fi> 7 */ 8 9 /* 10 * This file is part of GNU Enscript. 11 * 12 * Enscript is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation, either version 3 of the License, or 15 * (at your option) any later version. 16 * 17 * Enscript is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with Enscript. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 /* 27 * $Id: lex.l,v 1.1.1.1 2003/03/05 07:25:52 mtr Exp $ 28 */ 29 30 #include "defs.h" 31 #include "gram.h" 32 33 static void eat_comment (); 34 static char *read_string ___P ((unsigned int *len_return)); 35 static void read_regexp ___P ((Node *node)); 36 %} 37 38 real [+-]?[0-9]+\.[0-9]*|[+-]?\.[0-9]+ 39 integer [+-]?[0-9]+ 40 symbol [a-zA-Z_][a-zA-Z_0-9]*|\$. 41 42 %% 43 44 "/*" { eat_comment (); } 45 [ \t\r\f] { ; } 46 \n { linenum++; } 47 48 \" { yylval.node = node_alloc (nSTRING); 49 yylval.node->u.str.data 50 = read_string (&yylval.node->u.str.len); 51 return tSTRING; 52 } 53 54 '[^\\]' { yylval.node = node_alloc (nINTEGER); 55 yylval.node->u.integer = yytext[1]; 56 return tINTEGER; 57 } 58 59 '\\.' { yylval.node = node_alloc (nINTEGER); 60 switch (yytext[2]) 61 { 62 case 'n': 63 yylval.node->u.integer = '\n'; 64 break; 65 66 case 't': 67 yylval.node->u.integer = '\t'; 68 break; 69 70 case 'v': 71 yylval.node->u.integer = '\v'; 72 break; 73 74 case 'b': 75 yylval.node->u.integer = '\b'; 76 break; 77 78 case 'r': 79 yylval.node->u.integer = '\r'; 80 break; 81 82 case 'f': 83 yylval.node->u.integer = '\f'; 84 break; 85 86 case 'a': 87 yylval.node->u.integer = '\a'; 88 break; 89 90 default: 91 yylval.node->u.integer = yytext[2]; 92 break; 93 } 94 95 return tINTEGER; 96 } 97 98 \/ { yylval.node = node_alloc (nREGEXP); 99 read_regexp (yylval.node); 100 return tREGEXP; 101 } 102 103 "BEGIN" { return tBEGIN; } 104 "END" { return tEND; } 105 "div" { return tDIV; } 106 "else" { return tELSE; } 107 "extends" { return tEXTENDS; } 108 "for" { return tFOR; } 109 "if" { return tIF; } 110 "local" { return tLOCAL; } 111 "namerules" { return tNAMERULES; } 112 "return" { return tRETURN; } 113 "start" { return tSTART; } 114 "startrules" { return tSTARTRULES; } 115 "state" { return tSTATE; } 116 "sub" { return tSUB; } 117 "while" { return tWHILE; } 118 119 "==" { return tEQ; } 120 "!=" { return tNE; } 121 "<=" { return tLE; } 122 ">=" { return tGE; } 123 "&&" { return tAND; } 124 "||" { return tOR; } 125 "++" { return tPLUSPLUS; } 126 "--" { return tMINUSMINUS; } 127 "+=" { return tADDASSIGN; } 128 "-=" { return tSUBASSIGN; } 129 "*=" { return tMULASSIGN; } 130 "div=" { return tDIVASSIGN; } 131 132 {real} { yylval.node = node_alloc (nREAL); 133 yylval.node->u.real = atof (yytext); 134 return tREAL; 135 } 136 {integer} { yylval.node = node_alloc (nINTEGER); 137 yylval.node->u.integer = atoi (yytext); 138 return tINTEGER; 139 } 140 {symbol} { yylval.node = node_alloc (nSYMBOL); 141 yylval.node->u.sym = xstrdup (yytext); 142 return tSYMBOL; 143 } 144 145 . { return yytext[0]; } 146 147 %% 148 149 static void 150 eat_comment () 151 { 152 int c; 153 154 while ((c = input ()) != EOF) 155 { 156 if (c == '\n') 157 linenum++; 158 else if (c == '*') 159 { 160 c = input (); 161 if (c == '/') 162 /* All done. */ 163 return; 164 165 if (c == EOF) 166 { 167 yyerror (_("error: EOF in comment")); 168 break; 169 } 170 unput (c); 171 } 172 } 173 yyerror (_("error: EOF in comment")); 174 } 175 176 177 int 178 yywrap () 179 { 180 return 1; 181 } 182 183 static char * 184 read_string (len_return) 185 unsigned int *len_return; 186 { 187 char *buf = NULL; 188 char *buf2; 189 int buflen = 0; 190 int bufpos = 0; 191 int ch; 192 int done = 0; 193 194 while (!done) 195 { 196 ch = input (); 197 if (ch == '\n') 198 linenum++; 199 200 switch (ch) 201 { 202 case EOF: 203 unexpected_eof: 204 yyerror (_("error: EOF in string constant")); 205 done = 1; 206 break; 207 208 case '"': 209 done = 1; 210 break; 211 212 case '\\': 213 ch = input (); 214 switch (ch) 215 { 216 case 'n': 217 ch = '\n'; 218 break; 219 220 case 't': 221 ch = '\t'; 222 break; 223 224 case 'v': 225 ch = '\v'; 226 break; 227 228 case 'b': 229 ch = '\b'; 230 break; 231 232 case 'r': 233 ch = '\r'; 234 break; 235 236 case 'f': 237 ch = '\f'; 238 break; 239 240 case 'a': 241 ch = '\a'; 242 break; 243 244 case EOF: 245 goto unexpected_eof; 246 break; 247 248 default: 249 if (ch == '0') 250 { 251 int i; 252 int val = 0; 253 254 for (i = 0; i < 3; i++) 255 { 256 ch = input (); 257 if ('0' <= ch && ch <= '7') 258 val = val * 8 + ch - '0'; 259 else 260 { 261 unput (ch); 262 break; 263 } 264 } 265 ch = val; 266 } 267 break; 268 } 269 /* FALLTHROUGH */ 270 271 default: 272 if (bufpos >= buflen) 273 { 274 buflen += 1024; 275 buf = (char *) xrealloc (buf, buflen); 276 } 277 buf[bufpos++] = ch; 278 break; 279 } 280 } 281 282 buf2 = (char *) xmalloc (bufpos + 1); 283 memcpy (buf2, buf, bufpos); 284 buf2[bufpos] = '\0'; 285 xfree (buf); 286 287 *len_return = bufpos; 288 289 return buf2; 290 } 291 292 293 static void 294 read_regexp (node) 295 Node *node; 296 { 297 char *buf = NULL; 298 char *buf2; 299 int buflen = 0; 300 int bufpos = 0; 301 int ch; 302 int done = 0; 303 304 while (!done) 305 { 306 ch = input (); 307 switch (ch) 308 { 309 case EOF: 310 unexpected_eof: 311 yyerror (_("error: EOF in regular expression")); 312 done = 1; 313 break; 314 315 case '/': 316 done = 1; 317 break; 318 319 case '\\': 320 ch = input (); 321 switch (ch) 322 { 323 case '\n': 324 /* Line break. */ 325 linenum++; 326 continue; 327 break; 328 329 case 'n': 330 ch = '\n'; 331 break; 332 333 case 'r': 334 ch = '\r'; 335 break; 336 337 case 'f': 338 ch = '\f'; 339 break; 340 341 case 't': 342 ch = '\t'; 343 break; 344 345 case '/': 346 case '\\': 347 /* Quote these. */ 348 break; 349 350 case EOF: 351 goto unexpected_eof; 352 break; 353 354 default: 355 if (ch == '0') 356 { 357 int i; 358 int val = 0; 359 360 for (i = 0; i < 3; i++) 361 { 362 ch = input (); 363 if ('0' <= ch && ch <= '7') 364 val = val * 8 + ch - '0'; 365 else 366 { 367 unput (ch); 368 break; 369 } 370 } 371 ch = val; 372 } 373 else 374 { 375 /* Pass it through. */ 376 unput (ch); 377 ch = '\\'; 378 } 379 break; 380 } 381 /* FALLTHROUGH */ 382 383 default: 384 if (bufpos >= buflen) 385 { 386 buflen += 1024; 387 buf = (char *) xrealloc (buf, buflen); 388 } 389 buf[bufpos++] = ch; 390 break; 391 } 392 } 393 394 /* Possible options. */ 395 done = 0; 396 while (!done) 397 { 398 ch = input (); 399 switch (ch) 400 { 401 case 'i': 402 /* Case-insensitive regular expression. */ 403 node->u.re.flags |= fRE_CASE_INSENSITIVE; 404 break; 405 406 default: 407 /* Unknown option => this belongs to the next token. */ 408 unput (ch); 409 done = 1; 410 break; 411 } 412 } 413 414 buf2 = (char *) xmalloc (bufpos + 1); 415 memcpy (buf2, buf, bufpos); 416 buf2[bufpos] = '\0'; 417 xfree (buf); 418 419 node->u.re.data = buf2; 420 node->u.re.len = bufpos; 421 } 422 423 424 /* 425 Local variables: 426 mode: c 427 End: 428 */ 429