/[ascend]/trunk/ascend/compiler/scanner.l
ViewVC logotype

Contents of /trunk/ascend/compiler/scanner.l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2354 - (show annotations) (download)
Sat Jan 8 12:13:27 2011 UTC (9 years, 7 months ago) by jpye
File size: 33154 byte(s)
Working on detection of Lex 'yylex_destroy' capability.
1 %{
2 /* ASCEND modelling environment
3 Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly
4 Copyright (C) 2006, 2010 Carnegie Mellon University
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20 *//** @file
21 ASCEND lexer
22
23 This module is the input file for Flex (Lexical Analyzer
24 Generator). Its goal is to convert a stream of characters into a
25 stream of tokens. It has been defined to be consistent with the
26 routines required by the common compiler-compiler yacc.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 #include "ascend/general/platform.h"
34 #include "ascend/general/ascMalloc.h"
35 #include "ascend/compiler/compiler.h"
36 /* everything between here and the next comment is only here */
37 #include "ascend/compiler/fractions.h"
38 #include "ascend/compiler/dimen.h"
39 #include "ascend/compiler/functype.h"
40 #include "ascend/compiler/func.h"
41 #include "ascend/compiler/expr_types.h"
42 #include "ascend/compiler/stattypes.h"
43 #include "ascend/compiler/fractions.h"
44 #include "ascend/compiler/proc.h"
45 /* because ascParse.h has a nasty union we can't digest without them. */
46 #include "ascend/compiler/ascParse.h"
47 /* these below we actually need */
48 #include "ascend/general/list.h"
49 #include "ascend/compiler/module.h"
50 #include "ascend/compiler/scanner.h"
51 #include "ascend/compiler/symtab.h"
52 #include "ascend/compiler/parser.h"
53
54 #define YY_BREAK
55 /* Defining yybreak as above means that all of our matches must end
56 * in break or return because the normal flex supplied yybreak will
57 * be preempted by our empty one.
58 * In cases where matches contain a conditional return, make sure a
59 * break follows in the failure case.
60 */
61
62 #define ENDTOK 0
63 /* Return value when we reach the end of the input.
64 * This to must be 0 or negative according to yacc
65 */
66
67 #define MAX_REQUIRE_DEPTH 10
68 /* The maximum number of REQUIREd file nesting we will accept.
69 * See RequireStack below.
70 */
71
72 #define WORKBUF_INIT_SIZE 4095
73 /* We need a temporary buffer to copy yytext into before returning
74 * to the scanner (see g_workbuf below).
75 * WORKBUF_INIT_SIZE is the initial size of g_workbuf
76 */
77
78 static unsigned long yy_line = 1;
79 /* The current line number;
80 * every match of newline (\n) needs to ++ this variable.
81 */
82
83 static unsigned long start_line = 0;
84 /* The ine number where an open-comment, open-brace, or
85 * open-double-quote occurs. We use this to help in error reporting.
86 */
87
88 static int CommentNestLevel = 0;
89 /* Nesting level of (* comments *)
90 */
91
92 static int BracesNestLevel = 0;
93 /* Nesting level of {braced} expressions
94 */
95
96 static int MatchedBackslash = 0;
97 /* If this variable is positive, we matched a backslash \ in a DoubleQuote
98 * or BracedText state, and we should call ProcessBackslashes() to
99 * process them.
100 */
101
102 static int RequireIndex = 0;
103 /* The current nesting level of REQUIREd files
104 */
105
106 static YY_BUFFER_STATE RequireStack[MAX_REQUIRE_DEPTH];
107 /* The Flex buffers used for the REQUIREd files
108 */
109
110 static char *g_workbuf = NULL;
111 /* We need a place to keep doubly-quoted-text and braced-text for passing
112 * it back to the parser. yytext will not work since the parser may ask
113 * the scanner to read another token, at which point the value in yytext
114 * gets lost.
115 *
116 * The initial size of g_workbuf is WORKBUF_INIT_SIZE, and g_workbuf
117 * doubles when it needs more space.
118 *
119 * A call to CopyIntoWorkBuffer(yytext,yyleng) will copy yyleng characters
120 * of yytext into the working buffer.
121 *
122 * Note that having a single work buffer will not work if we ever create
123 * yacc productions that scan multiple chunks of doubly-quoted-text and/or
124 * braced-text before acting on them.
125 */
126
127
128 /* Forward declaration of functions
129 * provided at the end of this file.
130 */
131 static int Asc_ScannerPopBuffer(void);
132 static char *CopyIntoWorkBuffer(CONST char *, unsigned long);
133 static int Process_Backslashes(void);
134 static void ErrMsg_BracesEOF(void);
135 static void ErrMsg_CommentEOF(void);
136 static void ErrMsg_DoubleQuoteEOF(void);
137 static void ErrMsg_LongID(void);
138 static void ErrMsg_LongSymbol(void);
139 static void ErrMsg_SymbolEOF(void);
140 static void ErrMsg_SymbolEOL(void);
141 static void ErrMsg_UnexpectedChar(void);
142
143 %}
144
145 %x Comment
146 %x Symbol
147 %x BracedText
148 %x DoubleQuote
149
150 blank [\f\r\t\v ]
151 digit [0-9]
152 letter [a-zA-Z]
153
154 exp ([eE][-+]?{digit}+)
155 real (((({digit}+"."{digit}*)|("."{digit}+)){exp}?)|({digit}+{exp}))
156 integer {digit}+
157 IDChar {letter}({integer}|{letter}|_)*
158
159 %%
160
161 <INITIAL>"<=" { return LEQ_TOK; }
162 <INITIAL>">=" { return GEQ_TOK; }
163 <INITIAL>"<>" { return NEQ_TOK; }
164 <INITIAL>".." { return DOTDOT_TOK; }
165 <INITIAL>"::" { return DBLCOLON_TOK;}
166 <INITIAL>":=" { return ASSIGN_TOK; }
167 <INITIAL>":==" { return CASSIGN_TOK; }
168 <INITIAL>"==" { return BEQ_TOK ; }
169 <INITIAL>"!=" { return BNE_TOK ; }
170
171 <INITIAL>"=" { return '=' ;}
172 <INITIAL>">" { return '>' ;}
173 <INITIAL>"<" { return '<' ;}
174 <INITIAL>"," { return ',' ;}
175 <INITIAL>"." { return '.' ;}
176 <INITIAL>";" { return ';' ;}
177 <INITIAL>":" { return ':' ;}
178 <INITIAL>"[" { return '[' ;}
179 <INITIAL>"]" { return ']' ;}
180 <INITIAL>"(" { return '(' ;}
181 <INITIAL>")" { return ')' ;}
182 <INITIAL>"+" { return '+' ;}
183 <INITIAL>"-" { return '-' ;}
184 <INITIAL>"*" { return '*' ;}
185 <INITIAL>"/" { return '/' ;}
186 <INITIAL>"^" { return '^' ;}
187 <INITIAL>"|" { return '|' ;}
188
189 /**** Reserved Keywords ****/
190
191 <INITIAL>"ADD" { return ADD_TOK ; }
192 <INITIAL>"ALIASES" { return ALIASES_TOK ; }
193 <INITIAL>"AND" { return AND_TOK ; }
194 <INITIAL>"ANY" { return ANY_TOK ; }
195 <INITIAL>"ARE_ALIKE" { return AREALIKE_TOK ; }
196 <INITIAL>"ARE_THE_SAME" { return ARETHESAME_TOK ; }
197 <INITIAL>"ARRAY" { return ARRAY_TOK ; }
198 <INITIAL>"ATOM" { return ATOM_TOK ; }
199 <INITIAL>"BREAK" { return BREAK_TOK ; }
200 <INITIAL>"CALL" { return CALL_TOK ; }
201 <INITIAL>"CARD" { return CARD_TOK ; }
202 <INITIAL>"CASE" { return CASE_TOK ; }
203 <INITIAL>"CHECK" { return CHECK_TOK ; }
204 <INITIAL>"CHOICE" { return CHOICE_TOK ; }
205 <INITIAL>"CONDITIONAL" { return CONDITIONAL_TOK ; }
206 <INITIAL>"CONSTANT" { return CONSTANT_TOK ; }
207 <INITIAL>"CONTINUE" { return CONTINUE_TOK ; }
208 <INITIAL>"CREATE" { return CREATE_TOK ; }
209 <INITIAL>"DATA" { return DATA_TOK ; }
210 <INITIAL>"DECREASING" { return DECREASING_TOK ; }
211 <INITIAL>"DEFAULT" { return DEFAULT_TOK ; }
212 <INITIAL>"DEFINITION" { return DEFINITION_TOK ; }
213 <INITIAL>"DIMENSION" { return DIMENSION_TOK ; }
214 <INITIAL>"DIMENSIONLESS" { return DIMENSIONLESS_TOK ; }
215 <INITIAL>"DO" { return DO_TOK ; }
216 <INITIAL>"ELSE" { return ELSE_TOK ; }
217 <INITIAL>"END" { return END_TOK ; }
218 <INITIAL>"EXPECT" { return EXPECT_TOK ; }
219 <INITIAL>"EXTERNAL" { return EXTERNAL_TOK ; }
220 <INITIAL>"FALSE" { return FALSE_TOK ; }
221 <INITIAL>"FALL_THROUGH" { return FALLTHRU_TOK ; }
222 <INITIAL>"FIX" { return FIX_TOK ; }
223 <INITIAL>"FREE" { return FREE_TOK ; }
224 <INITIAL>"FOR" { return FOR_TOK ; }
225 <INITIAL>"FROM" { return FROM_TOK ; }
226 <INITIAL>"GLOBAL" { return GLOBAL_TOK ; }
227 <INITIAL>"ASSERT" { return ASSERT_TOK ; }
228 <INITIAL>"IF" { return IF_TOK ; }
229 <INITIAL>"IMPORT" { return IMPORT_TOK ; }
230 <INITIAL>"IN" { return IN_TOK ; }
231 <INITIAL>"INCREASING" { return INCREASING_TOK ; }
232 <INITIAL>"INPUT" { return INPUT_TOK ; }
233 <INITIAL>"INTERSECTION" { return INTERSECTION_TOK ; }
234 <INITIAL>"IS_A" { return ISA_TOK ; }
235 <INITIAL>"IS_REFINED_TO" { return ISREFINEDTO_TOK ; }
236 <INITIAL>"MAXIMIZE" { return MAXIMIZE_TOK ; }
237 <INITIAL>"MAX_INTEGER" { return MAXINTEGER_TOK ; }
238 <INITIAL>"MAX_REAL" { return MAXREAL_TOK ; }
239 <INITIAL>"METHOD" { return METHOD_TOK ; }
240 <INITIAL>"METHODS" { return METHODS_TOK ; }
241 <INITIAL>"MINIMIZE" { return MINIMIZE_TOK ; }
242 <INITIAL>"MODEL" { return MODEL_TOK ; }
243 <INITIAL>"NOT" { return NOT_TOK ; }
244 <INITIAL>"NOTES" { return NOTES_TOK ; }
245 <INITIAL>"OF" { return OF_TOK ; }
246 <INITIAL>"OPTION" { return OPTION_TOK ; }
247 <INITIAL>"OR" { return OR_TOK ; }
248 <INITIAL>"OTHERWISE" { return OTHERWISE_TOK ; }
249 <INITIAL>"OUTPUT" { return OUTPUT_TOK ; }
250 <INITIAL>"PROD" { return PROD_TOK ; }
251 <INITIAL>"PROVIDE" { return PROVIDE_TOK ; }
252 <INITIAL>"REFINES" { return REFINES_TOK ; }
253 <INITIAL>"REPLACE" { return REPLACE_TOK ; }
254 <INITIAL>"REQUIRE" { return REQUIRE_TOK ; }
255 <INITIAL>"RETURN" { return RETURN_TOK ; }
256 <INITIAL>"RUN" { return RUN_TOK ; }
257 <INITIAL>"SATISFIED" { return SATISFIED_TOK ; }
258 <INITIAL>"SELECT" { return SELECT_TOK ; }
259 <INITIAL>"SUCH_THAT" { return SUCHTHAT_TOK ; }
260 <INITIAL>"SUM" { return SUM_TOK ; }
261 <INITIAL>"SIZE" { return SIZE_TOK ; }
262 <INITIAL>"SOLVE" { return SOLVE_TOK ; }
263 <INITIAL>"SOLVER" { return SOLVER_TOK ; }
264 <INITIAL>"SWITCH" { return SWITCH_TOK ; }
265 <INITIAL>"STOP" { return STOP_TOK ; }
266 <INITIAL>"THEN" { return THEN_TOK ; }
267 <INITIAL>"TRUE" { return TRUE_TOK ; }
268 <INITIAL>"UNION" { return UNION_TOK ; }
269 <INITIAL>"UNITS" { return UNITS_TOK ; }
270 <INITIAL>"UNIVERSAL" { return UNIVERSAL_TOK ; }
271 <INITIAL>"USE" { return USE_TOK ; }
272 <INITIAL>"VALUE" { return VALUE_TOK ; }
273 <INITIAL>"WHEN" { return WHEN_TOK ; }
274 <INITIAL>"WHERE" { return WHERE_TOK ; }
275 <INITIAL>"WHILE" { return WHILE_TOK ; }
276 <INITIAL>"WILL_BE" { return WILLBE_TOK ; }
277 <INITIAL>"WILL_BE_THE_SAME" { return WILLBETHESAME_TOK ; }
278 <INITIAL>"WILL_NOT_BE_THE_SAME" { return WILLNOTBETHESAME_TOK ; }
279 <INITIAL>"WITH" { return WITH_TOK ; }
280 <INITIAL>"WITH_VALUE" { return WITH_VALUE_T ; }
281
282 /*
283 * Code to handle (* Comments *)
284 *
285 * "(*" puts us into the Comment state. Comments nest, so in the
286 * Comment state we need to look for "(*" that increases the nesting
287 * level and "*)" that will lower it.
288 * Flex is faster if we match as much as possible, so we repeat
289 * patterns with and without the "\n" (although it is more difficult
290 * for the maintainer to understand) to avoid the overhead of a
291 * separate "\n" rule.
292 * Do NOT try to match \(\*+ since that causes "(****)" to parse
293 * incorrectly.
294 */
295
296 <INITIAL>\(\* {
297 /* Match "(" followed by "*" puts us into
298 * the COMMENT state. Don't use \*+ since
299 * that will parse "(***)" incorrectly.
300 * Initialize the nesting level.
301 * Store the current line for ErrMsg use.
302 */
303 BEGIN (Comment);
304 CommentNestLevel = 1;
305 start_line = yy_line;
306 break;
307 }
308 <Comment>\(\*[^*(\n]* {
309 /* Match "(" followed "*" followed by
310 * anything that's not "(" nor "*".
311 * Increase the commment nesting level.
312 */
313 CommentNestLevel++;
314 break;
315 }
316 <Comment>\(\*[^*(\n]*\n {
317 /* Match "(" followed by "*" followed by
318 * anything that's not "(" nor "*".
319 * Increase the commment nesting level.
320 */
321 yy_line++;
322 CommentNestLevel++;
323 break;
324 }
325 <Comment>[^*(\n]*\*+\) {
326 /* Match anything not "*" or "(" followed
327 * by one or more "*"s followed by ")".
328 * This decreases the comment nesting level
329 * and kicks us out if we're back to zero.
330 */
331 CommentNestLevel--;
332 if (CommentNestLevel == 0) {
333 BEGIN (INITIAL);
334 }
335 break;
336 }
337 <Comment>[^*(\n]* {
338 /* Eat anything that's not a "*" nor a "("
339 */
340 break;
341 }
342 <Comment>[^*(\n]*\n {
343 /* Eat anything that's not a "*" nor a "("
344 * that is followed by a newline.
345 * This rule also matches empty line.
346 */
347 yy_line++;
348 break;
349 }
350 <Comment>\(+[^*(\n]* {
351 /* Eat "("s not followed by "*"
352 */
353 break;
354 }
355 <Comment>\(+[^*(\n]*\n {
356 /* Eat "("s not followed by "*" plus a "\n"
357 */
358 yy_line++;
359 break;
360 }
361 <Comment>\*+[^*()\n]* {
362 /* Eat "*"s not followed by ")"
363 */
364 break;
365 }
366 <Comment>\*+[^*()\n]*\n {
367 /* Eat "*" not followed by ")" plus a "\n"
368 */
369 yy_line++;
370 break;
371 }
372 <Comment><<EOF>> {
373 /* An EOF in a Comment means bad nesting.
374 * Print an error and pop back a level
375 * or return ENDTOK if no more input.
376 */
377 ErrMsg_CommentEOF();
378 CommentNestLevel = 0;
379 if ( Asc_ScannerPopBuffer() == 1 ) {
380 return ENDTOK;
381 }
382 break;
383 }
384
385
386 /*
387 * Code to handle 'Symbols'
388 *
389 * Symbols are simple: they are 'singely quoted strings' that
390 * exist on a single line. Look for anything that is not
391 * a quote or a newline to get the text of the symbol.
392 */
393
394 <INITIAL>\' {
395 /* A single quote (') in the INITIAL state
396 * puts us into the Symbol state.
397 */
398 BEGIN (Symbol);
399 break;
400 }
401 <Symbol>[^'\n]*\' {
402 /* Anything that is not a (') nor a newline
403 * followed by a (') is the symbol's text.
404 * Return to the INITIAL state, store the
405 * symbol in the symbol table and return
406 * SYMBOL_TOK to the parser.
407 */
408 BEGIN (INITIAL);
409 /* strip off the final (')
410 */
411 yytext[--yyleng] = '\0';
412 if (yyleng > YY_MAXLEN) {
413 ErrMsg_LongSymbol();
414 break;
415 }
416 zz_lval.sym_ptr = AddSymbolL(yytext,yyleng);
417 return SYMBOL_TOK;
418 }
419 <Symbol>[^'\n]*\n {
420 /* If we find a newline before a ('), the
421 * symbol is unterminated. Print an error
422 * message and return to the INITIAL state.
423 */
424 ErrMsg_SymbolEOL();
425 yy_line++;
426 BEGIN(INITIAL);
427 break;
428 }
429 <Symbol><<EOF>> {
430 /* If we find an EOF before a ('), the
431 * symbol is unterminated. Print an error
432 * message and pop to the previously
433 * REQUIREd file or return ENDTOK if the
434 * pop fails due to no more input.
435 */
436 ErrMsg_SymbolEOF();
437 if ( Asc_ScannerPopBuffer() == 1 ) {
438 return ENDTOK;
439 }
440 break;
441 }
442
443
444 /*
445 * Code to handle "Text in Double Quotes"
446 *
447 * The DoubleQuote state begins with a double quote and ends
448 * with a double quote; double quotes can be included by
449 * escaping them with a backslash (e.g. \"). There is no
450 * nesting level to worry about.
451 * Flex is faster if we match as much as possible, so we repeat
452 * patterns with and without the "\n" (although it is more difficult
453 * for the maintainer to understand) to avoid the overhead of a
454 * separate "\n" rule.
455 * We want to keep the text, so we need to call yymore().
456 */
457
458 <INITIAL>\" {
459 /* A double quote puts us into the
460 * DoubleQuote state. Save the line
461 * number for error reporting.
462 */
463 BEGIN (DoubleQuote);
464 start_line = yy_line;
465 break;
466 }
467 <DoubleQuote>[^\\"\n]*\\. {
468 /* A backslash \ in the DoubleQuote
469 * state protects any character.
470 */
471 MatchedBackslash++;
472 yymore();
473 break;
474 }
475 <DoubleQuote>[^\\"\n]*\\\n {
476 /* A backslash \ in the DoubleQuote
477 * state protects a newline.
478 */
479 MatchedBackslash++;
480 yy_line++;
481 yymore();
482 break;
483 }
484 <DoubleQuote>[^\\"\n]*\" {
485 /* A double quote in the DoubleQuote state
486 * (that is not protected by backslash)
487 * will put us back in the INITIAL state.
488 * Process the string and return DQUOTE_TOK
489 * to the parser.
490 */
491 BEGIN (INITIAL);
492 /* Remove the final double quote
493 */
494 yytext[--yyleng] = '\0';
495 /* Do backslash substitutions on the string
496 * before returing it to the scanner.
497 */
498 if ( MatchedBackslash != 0 ) {
499 Process_Backslashes();
500 MatchedBackslash = 0;
501 }
502 zz_lval.dquote_ptr =
503 CopyIntoWorkBuffer(yytext,yyleng);
504 return DQUOTE_TOK;
505 }
506 <DoubleQuote>[^\\"\n]* {
507 /* Match anything that is not backslash nor
508 * doublequote and add it to the text.
509 */
510 yymore();
511 break;
512 }
513 <DoubleQuote>[^\\"\n]*\n {
514 /* Match anything that is not backslash nor
515 * doublequote and add it to the text.
516 * This also matches an empty line.
517 */
518 yy_line++;
519 yymore();
520 break;
521 }
522 <DoubleQuote><<EOF>> {
523 /* End of File in a DoubleQuote state
524 * means no matching double quote.
525 * Print an error and pop next buffer
526 * off the RequireStack or return ENDTOK
527 * if there is no more input.
528 */
529 ErrMsg_DoubleQuoteEOF();
530 MatchedBackslash = 0;
531 if ( Asc_ScannerPopBuffer() == 1 ) {
532 return ENDTOK;
533 }
534 break;
535 }
536
537
538 /*
539 * Code to handle { Text in Braces }
540 *
541 * "{" puts us into the BracedText state. Braces nest, so
542 * in the BracedText state we need to look for "{" that increases
543 * the nesting level and "}" that will lower it.
544 * Flex is faster if we match as much as possible, so we repeat
545 * patterns with and without the "\n" (although it is more difficult
546 * for the maintainer to understand) to avoid the overhead of a
547 * separate "\n" rule.
548 * We want to keep the text we scan, so we have to call yymore().
549 */
550
551 <INITIAL>\{{blank}*\n { /* A "{" puts us into the BracedText state.
552 * If from the opening "{" to the first
553 * newline is all whitespace, then ignore
554 * it.
555 * Initialize the nesting level.
556 * Save the current line number for
557 * error message reporting.
558 */
559 BEGIN (BracedText);
560 BracesNestLevel = 1;
561 start_line = yy_line;
562 yy_line++;
563 break;
564 }
565 <INITIAL>\{ {
566 /* A "{" puts us into the BracedText state.
567 * Initialize the nesting level.
568 * Save the current line number for
569 * error message reporting.
570 */
571 BEGIN (BracedText);
572 BracesNestLevel = 1;
573 start_line = yy_line;
574 break;
575 }
576 <BracedText>[^\\{}\n]*\\. {
577 /* A backslash \ in the BracedText state
578 * protects any character and does not
579 * affect the Nesting Level.
580 */
581 MatchedBackslash++;
582 yymore();
583 break;
584 }
585 <BracedText>[^\\{}\n]*\\\n {
586 /* A backslash \ in the BracedText state
587 * protects a newline.
588 */
589 MatchedBackslash++;
590 yy_line++;
591 yymore();
592 break;
593 }
594 <BracedText>\{[^\\{}\n]* {
595 /* A "{" in the braces state gets added to
596 * the text and increase the nesting level.
597 */
598 BracesNestLevel++;
599 yymore();
600 break;
601 }
602 <BracedText>\{[^\\{}\n]*\n {
603 /* A "{" in the braces state gets added to
604 * the text and increase the nesting level.
605 */
606 yy_line++;
607 BracesNestLevel++;
608 yymore();
609 break;
610 }
611 <BracedText>[^\\{}\n]*\} {
612 /* A "}" will reduce the nesting level.
613 * If the nesting level is zero, go back to
614 * the INITIAL level, save the text as a
615 * Symbol, do the backslash substitution,
616 * and return BRACEDTEXT_TOK to the
617 * parse; otherwise, add the "}" to the
618 * text and keep scanning.
619 */
620 BracesNestLevel--;
621 if (BracesNestLevel == 0) {
622 BEGIN (INITIAL);
623 /* Remove the final "}"
624 */
625 yytext[--yyleng] = '\0';
626 /* Do backslash substitutions on the text
627 * before returing it to the scanner.
628 */
629 if ( MatchedBackslash != 0 ) {
630 Process_Backslashes();
631 MatchedBackslash = 0;
632 }
633 zz_lval.braced_ptr =
634 CopyIntoWorkBuffer(yytext,yyleng);
635 return BRACEDTEXT_TOK;
636 }
637 yymore();
638 break;
639 }
640 <BracedText>[^\\{}\n]* {
641 /* Match anything that is not "{" nor "}"
642 * nor "\\"(backslash) and add it to text.
643 */
644 yymore();
645 break;
646 }
647 <BracedText>[^\\{}\n]*\n {
648 /* Match anything that is not "{" nor "}"
649 * nor "\\"(backslash) followed by a "\n"
650 * and add it to text.
651 * This also matches an empty line.
652 */
653 yy_line++;
654 yymore();
655 break;
656 }
657 <BracedText><<EOF>> {
658 /* End of File in braces means bad nesting.
659 * Print an error message and pop to the
660 * previously REQUIREd file or return
661 * ENDTOK if no more input.
662 */
663 ErrMsg_BracesEOF();
664 BracesNestLevel = 0;
665 MatchedBackslash = 0;
666 if ( Asc_ScannerPopBuffer() == 1 ) {
667 return ENDTOK;
668 }
669 break;
670 }
671
672
673 /*
674 * Code to handle Miscellaneous types.
675 *
676 */
677
678 <INITIAL>{integer} {
679 /* An integer. Defn near top of file.
680 */
681 zz_lval.int_value = atol(yytext);
682 return INTEGER_TOK;
683 }
684
685 <INITIAL>{integer}/".." {
686 /* An integer as the first number in a
687 * range (need to avoid parsing "1..2"
688 * as the real numbers 1.0 and 0.2).
689 */
690 zz_lval.int_value = atol(yytext);
691 return INTEGER_TOK;
692 }
693
694 <INITIAL>{real} {
695 /* A real number. Defn near top of file.
696 */
697 zz_lval.real_value = atof(yytext);
698 return REAL_TOK;
699 }
700
701 <INITIAL>{IDChar}+ {
702 /* An identifier. Defn near top of file.
703 */
704 if (yyleng >YY_MAXLEN) {
705 ErrMsg_LongID();
706 break;
707 }
708 zz_lval.id_ptr = AddSymbolL(yytext,yyleng);
709 return IDENTIFIER_TOK;
710 }
711
712 <INITIAL>{blank}* {
713 /* Ignore whitespace. */
714 break;
715 }
716 <INITIAL>{blank}*\n {
717 /* Ignore whitespace. */
718 yy_line++;
719 break;
720 }
721
722
723 <INITIAL>. {
724 /* Unknown character. Print error
725 * message and keep going.
726 */
727 ErrMsg_UnexpectedChar();
728 break;
729 }
730
731 <INITIAL><<EOF>> {
732 /* Print an error message if we
733 * reached EOF in the middle of a
734 * type definition. Pop to the
735 * previously REQUIREd file or return
736 * ENDTOK if no more input.
737 */
738 Asc_ErrMsgTypeDefnEOF();
739 if ( Asc_ScannerPopBuffer() == 1 ) {
740 return ENDTOK;
741 }
742 break;
743 }
744
745 %%
746 /*
747 * int yywrap(void);
748 *
749 * This returns 1 if the scanner should stop parsing, or
750 * 0 if the scanner should continue. Flex requires this
751 * function unless %option noyywrap is defined.
752 */
753 int
754 yywrap(void)
755 {
756 return 1;
757 }
758
759
760 /*
761 * See the header file scanner.h for a description of this function.
762 */
763 unsigned long
764 LineNum(void)
765 {
766 return yy_line;
767 }
768
769
770 /*
771 * See the header file scanner.h for a description of this function.
772 */
773 void
774 Asc_ScannerAssignFile(FILE *f, unsigned long linenum)
775 {
776 yyin = f;
777 yy_line = linenum;
778 if ( RequireIndex == 0 ) {
779 yyrestart(f);
780 }
781 }
782
783 /*
784 * See the header file scanner.h for a description of this function.
785 */
786 void
787 Asc_ScannerAssignString(void *yybs, unsigned long linenum, int first)
788 {
789 /* yyin = f; */
790 yy_line = linenum;
791 yy_switch_to_buffer((YY_BUFFER_STATE)yybs);
792 if (first) {
793 BEGIN(INITIAL);
794 }
795 if ( RequireIndex == 0 ) {
796 yyrestart((FILE *)NULL); /* ? ? ? should be reading from a string buffer... */
797 }
798 }
799
800
801 /*
802 * See the header file scanner.h for a description of this function.
803 */
804 int
805 Asc_ScannerPushBuffer(CONST char *filename)
806 {
807 int status; /* status returned from Asc_RequireModule */
808
809 if ( RequireIndex >= MAX_REQUIRE_DEPTH ) {
810 FPRINTF(ASCERR,
811 "Error:\tREQUIRE nested too deeply (%d levels) on line %s:%lu.\n"
812 "\tFile \"%s\" not read.\n",
813 RequireIndex,
814 Asc_ModuleBestName(Asc_CurrentModule()),
815 yy_line,
816 filename);
817 return 1;
818 }
819
820 /* The current Flex buffer is not on the RequireStack yet, so add it
821 * before calling Asc_OpenModule. We need to increment RequireIndex
822 * before calling Asc_OpenModule due to the check in
823 * Asc_ScannerAssignFile.
824 */
825 RequireStack[RequireIndex++] = YY_CURRENT_BUFFER;
826
827 Asc_RequireModule( filename, &status );
828 if( status == 5 ) {
829 /* already required */
830 RequireIndex--;
831 CONSOLE_DEBUG("REQUIREd module \"%s\" already PROVIDEd", filename);
832 return 1;
833 }
834 if( status == 4 ) {
835 /* recursive require */
836 RequireIndex--;
837 ERROR_REPORTER_HERE(ASC_USER_WARNING
838 ,"Recursive REQUIRE for module \"%s\" (ignored)",filename
839 );
840 return 1;
841 }
842 if ( status != 0 ) {
843 /* The open failed. Decrement RequireIndex and print an error.
844 */
845 RequireIndex--;
846 error_reporter(ASC_USER_ERROR
847 ,Asc_ModuleBestName(Asc_CurrentModule()),yy_line,NULL
848 ,"REQUIRE cannot open module \"%s\""
849 ,filename
850 );
851 return 2;
852 }
853
854 /* Asc_OpenModule was successful, so print a message, switch to the
855 * new buffer in the INITIAL state.
856 * SHOULD never reach here with a string buffer as they cannot be
857 * REQUIREd.
858 */
859 Asc_FPrintf(stderr,"REQUIREing file \"%s\"\n", filename);
860 yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
861 BEGIN (INITIAL);
862 return 0;
863 }
864
865
866 /*
867 * int Asc_ScannerPopBuffer()
868 *
869 * When we reach an End Of File (EOF) in the scanner, we call this
870 * function to pop us to the file which REQUIREd the file we just
871 * reached the end of and return 0. If there are no more files on the
872 * RequireStack, return 1.
873 */
874 static int
875 Asc_ScannerPopBuffer(void)
876 {
877 Asc_CloseCurrentModule(); /* the current module may be NULL. */
878 if ( RequireIndex == 0 ) {
879 return 1;
880 }
881
882 yy_delete_buffer(YY_CURRENT_BUFFER);
883 yy_switch_to_buffer( RequireStack[--RequireIndex] );
884 BEGIN(INITIAL);
885 return 0;
886 }
887
888 void Asc_ScannerReleaseStringBuffer(void *yybs)
889 {
890 yy_delete_buffer((YY_BUFFER_STATE)yybs);
891 yy_switch_to_buffer( RequireStack[--RequireIndex] );
892 BEGIN(INITIAL);
893 }
894
895 void *Asc_ScannerCreateStringBuffer(CONST char *string, int len)
896 {
897 /* we hope to god yy_scan_bytes does not change current buffer */
898 YY_BUFFER_STATE yybs;
899 /* push current, don't care its name or type. */
900 RequireStack[RequireIndex++] = YY_CURRENT_BUFFER;
901 yybs = yy_scan_bytes(string, len);
902 assert(yybs);
903 return (void *)yybs;
904 }
905
906 /*
907 * g_workbuf = CopyIntoWorkBuffer(str, len)
908 * char *g_workbuf;
909 * CONST char *str;
910 * unsigned long len;
911 *
912 * Copy the string `str' having length `len' into the Scanner's Working
913 * Buffer g_workbuf and return g_workbuf if successful or NULL if
914 * unsuccessful (due to lack of memory).
915 * If g_workbuf is too short to hold `str', it is repeatably doubled until
916 * either it is big enough or memory is exhausted.
917 * We actually copy len+1 characters of `str' into g_workbuf so that the
918 * final \0 gets copied also.
919 * Global Effects: Modifies the contents of g_workbuf
920 * Possibly changes the address of g_workbuf (on realloc)
921 */
922 static char *
923 CopyIntoWorkBuffer(CONST char *str, unsigned long len)
924 {
925 static size_t g_workbuf_len = WORKBUF_INIT_SIZE; /* length of g_workbuf */
926
927 assert(str[len]=='\0'); /* is this true for all yacc? */
928 len++; /* add one to make sure we have a final '\0' */
929 if (( len >= g_workbuf_len ) || ( g_workbuf == NULL )) {
930 while( len >= g_workbuf_len ) {
931 g_workbuf_len *= 2;
932 }
933 if (g_workbuf == NULL ) {
934 g_workbuf = ASC_NEW_ARRAY(char, g_workbuf_len );
935 } else {
936 g_workbuf = (char*)ascrealloc( (void*)g_workbuf, g_workbuf_len );
937 }
938 if ( g_workbuf == NULL ) {
939 return NULL;
940 }
941 }
942 return strncpy(g_workbuf, str, len); /* does not add a NULL char */
943 }
944
945
946 extern void
947 Asc_DestroyScannerWorkBuffer(void)
948 {
949 if (g_workbuf != NULL) {
950 ascfree(g_workbuf);
951 }
952 g_workbuf = NULL;
953 }
954
955 void Asc_DestroyScannerInputBuffer(void)
956 {
957 if (YY_CURRENT_BUFFER != NULL) {
958 yy_delete_buffer(YY_CURRENT_BUFFER);
959 }
960 #ifdef ASC_HAVE_LEXDESTROY
961 zz_lex_destroy();
962 #endif
963 }
964
965 /*
966 * int Process_Backslashes(void)
967 *
968 * Covert any backslash \ escapes into the correct character.
969 * Operates on and modifies in place the value of yytext; yyleng
970 * is adjusted accordingly. Returns the number of backslash
971 * substitutions made. The following are supported:
972 * \a (alert)
973 * \b (backspace)
974 * \f (formfeed)
975 * \n (newline)
976 * \r (carriage return)
977 * \t (horizontal tab)
978 * \v (vertical tab)
979 * \xhh (hexadecimal hh) ***** NOT IMPLEMENTED *****
980 * \ooo (octal ooo where o == [0-7]) ***** NOT IMPLEMENTED *****
981 * \\n (backslash before newline removes the backslash and newline)
982 * \. (any other char produces that char)
983 */
984 static int
985 Process_Backslashes(void)
986 {
987 int old_index;
988 int new_index;
989 int substitution_count = 0;
990
991 for (old_index=0, new_index=0; old_index<yyleng; old_index++) {
992 if (yytext[old_index] != '\\') {
993 yytext[new_index++] = yytext[old_index];
994 } else {
995 if (++old_index < yyleng) {
996 switch(yytext[old_index]) {
997 case 'a':
998 yytext[new_index++] = '\a';
999 substitution_count++;
1000 break;
1001 case 'b':
1002 yytext[new_index++] = '\b';
1003 substitution_count++;
1004 break;
1005 case 'f':
1006 yytext[new_index++] = '\f';
1007 substitution_count++;
1008 break;
1009 case 'n':
1010 yytext[new_index++] = '\n';
1011 substitution_count++;
1012 break;
1013 case 'r':
1014 yytext[new_index++] = '\r';
1015 substitution_count++;
1016 break;
1017 case 't':
1018 yytext[new_index++] = '\t';
1019 substitution_count++;
1020 break;
1021 case 'v':
1022 yytext[new_index++] = '\v';
1023 substitution_count++;
1024 break;
1025 case 'x':
1026 /* need to add processing for
1027 * hexadecimal numbers \xhh here
1028 */
1029 yytext[new_index++] = yytext[old_index];
1030 substitution_count++;
1031 break;
1032 case '0':
1033 case '1':
1034 case '2':
1035 case '3':
1036 case '4':
1037 case '5':
1038 case '6':
1039 case '7':
1040 /* need to add processing for
1041 * octal numbers \ooo here
1042 */
1043 yytext[new_index++] = yytext[old_index];
1044 substitution_count++;
1045 break;
1046 case '\n':
1047 /* Backslash at the end of the line removes
1048 * the slash and the newline from the result,
1049 * so no futher processing is needed.
1050 */
1051 substitution_count++;
1052 break;
1053 default:
1054 yytext[new_index++] = yytext[old_index];
1055 substitution_count++;
1056 break;
1057 }
1058 }
1059 }
1060 }
1061 yytext[new_index] = '\0';
1062 yyleng = new_index;
1063 return substitution_count;
1064 }
1065
1066
1067 /*
1068 * void ErrMsg_*(void)
1069 *
1070 * The following all print error messages to the file handle ASCERR.
1071 * The type of error is indicated by the function's name and the
1072 * arguments to fprintf.
1073 */
1074 static void
1075 ErrMsg_BracesEOF(void){
1076 error_reporter(ASC_USER_ERROR, Asc_ModuleBestName(Asc_CurrentModule()), start_line, NULL
1077 ,"End of file reached within a unit, data table or explanation. No closing brace "
1078 "found for open brace."
1079 );
1080 }
1081
1082
1083 static void
1084 ErrMsg_CommentEOF(void)
1085 {
1086 FPRINTF(ASCERR,
1087 "Error:\tEnd of file reached within a comment.\n"
1088 "\tNo close-comment found for comment starting on line %s:%lu\n",
1089 Asc_ModuleBestName(Asc_CurrentModule()), start_line);
1090 }
1091
1092
1093 static void
1094 ErrMsg_LongID(void)
1095 {
1096 FPRINTF(ASCERR,
1097 "Error:\tIdentifier too long on line %s:%lu.\n"
1098 "\tIdentifier \"%s\" exceeds the maximum identifier size of %d\n",
1099 Asc_ModuleBestName(Asc_CurrentModule()),
1100 yy_line,
1101 yytext,
1102 YY_MAXLEN);
1103 }
1104
1105
1106 static void
1107 ErrMsg_LongSymbol(void)
1108 {
1109 FPRINTF(ASCERR,
1110 "Error:\tSymbol too long on line %s:%lu.\n"
1111 "\tSymbol %s exceeds the maximum symbol size of %d\n",
1112 Asc_ModuleBestName(Asc_CurrentModule()),
1113 yy_line,
1114 yytext,
1115 YY_MAXLEN);
1116 }
1117
1118
1119 static void
1120 ErrMsg_DoubleQuoteEOF(void)
1121 {
1122 FPRINTF(ASCERR,
1123 "Error:\tEnd of file reached with a double quoted string.\n"
1124 "\tNo close quote found for the open quote on line %s:%lu\n",
1125 Asc_ModuleBestName(Asc_CurrentModule()), start_line);
1126 }
1127
1128
1129 static void
1130 ErrMsg_SymbolEOF(void)
1131 {
1132 FPRINTF(ASCERR,
1133 "Error:\tEnd of file reached within a symbol.\n"
1134 "\tNo close quote found for symbol on line %s:%lu\n",
1135 Asc_ModuleBestName(Asc_CurrentModule()), yy_line);
1136 }
1137
1138
1139 static void
1140 ErrMsg_SymbolEOL(void)
1141 {
1142 FPRINTF(ASCERR,
1143 "Error:\tEnd of line reached within a symbol.\n"
1144 "\tNo close quote found for symbol on line %s:%lu\n",
1145 Asc_ModuleBestName(Asc_CurrentModule()), yy_line);
1146 }
1147
1148 #define ERRCOUNT_UNEXPCHAR 5
1149 static void ErrMsg_UnexpectedChar(){
1150 static int errcount=0;
1151 if(errcount<ERRCOUNT_UNEXPCHAR){
1152 error_reporter(ASC_USER_ERROR
1153 ,Asc_ModuleBestName(Asc_CurrentModule()), yy_line, NULL
1154 ,"Unexpected character '%s' in input (ASCII %d). If you pasted"
1155 " text from another source (a word-processor, web page, etc) be"
1156 " careful that you haven't pasted strange quotes, hyphens, etc."
1157 , yytext, yytext[0]
1158 );
1159 errcount++;
1160 if(errcount==ERRCOUNT_UNEXPCHAR){
1161 ERROR_REPORTER_HERE(ASC_PROG_NOTE
1162 ,"Further reports of this error will be supressed\n"
1163 );
1164 }
1165 }
1166 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22