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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2331 - (show annotations) (download)
Thu Dec 23 23:47:12 2010 UTC (13 years, 5 months ago) by jpye
File size: 33120 byte(s)
Fixed memory leaks from Flex (scanner.l). All compiler/test_basics.c complete without memory leaks now.
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 zz_lex_destroy();
961 }
962
963 /*
964 * int Process_Backslashes(void)
965 *
966 * Covert any backslash \ escapes into the correct character.
967 * Operates on and modifies in place the value of yytext; yyleng
968 * is adjusted accordingly. Returns the number of backslash
969 * substitutions made. The following are supported:
970 * \a (alert)
971 * \b (backspace)
972 * \f (formfeed)
973 * \n (newline)
974 * \r (carriage return)
975 * \t (horizontal tab)
976 * \v (vertical tab)
977 * \xhh (hexadecimal hh) ***** NOT IMPLEMENTED *****
978 * \ooo (octal ooo where o == [0-7]) ***** NOT IMPLEMENTED *****
979 * \\n (backslash before newline removes the backslash and newline)
980 * \. (any other char produces that char)
981 */
982 static int
983 Process_Backslashes(void)
984 {
985 int old_index;
986 int new_index;
987 int substitution_count = 0;
988
989 for (old_index=0, new_index=0; old_index<yyleng; old_index++) {
990 if (yytext[old_index] != '\\') {
991 yytext[new_index++] = yytext[old_index];
992 } else {
993 if (++old_index < yyleng) {
994 switch(yytext[old_index]) {
995 case 'a':
996 yytext[new_index++] = '\a';
997 substitution_count++;
998 break;
999 case 'b':
1000 yytext[new_index++] = '\b';
1001 substitution_count++;
1002 break;
1003 case 'f':
1004 yytext[new_index++] = '\f';
1005 substitution_count++;
1006 break;
1007 case 'n':
1008 yytext[new_index++] = '\n';
1009 substitution_count++;
1010 break;
1011 case 'r':
1012 yytext[new_index++] = '\r';
1013 substitution_count++;
1014 break;
1015 case 't':
1016 yytext[new_index++] = '\t';
1017 substitution_count++;
1018 break;
1019 case 'v':
1020 yytext[new_index++] = '\v';
1021 substitution_count++;
1022 break;
1023 case 'x':
1024 /* need to add processing for
1025 * hexadecimal numbers \xhh here
1026 */
1027 yytext[new_index++] = yytext[old_index];
1028 substitution_count++;
1029 break;
1030 case '0':
1031 case '1':
1032 case '2':
1033 case '3':
1034 case '4':
1035 case '5':
1036 case '6':
1037 case '7':
1038 /* need to add processing for
1039 * octal numbers \ooo here
1040 */
1041 yytext[new_index++] = yytext[old_index];
1042 substitution_count++;
1043 break;
1044 case '\n':
1045 /* Backslash at the end of the line removes
1046 * the slash and the newline from the result,
1047 * so no futher processing is needed.
1048 */
1049 substitution_count++;
1050 break;
1051 default:
1052 yytext[new_index++] = yytext[old_index];
1053 substitution_count++;
1054 break;
1055 }
1056 }
1057 }
1058 }
1059 yytext[new_index] = '\0';
1060 yyleng = new_index;
1061 return substitution_count;
1062 }
1063
1064
1065 /*
1066 * void ErrMsg_*(void)
1067 *
1068 * The following all print error messages to the file handle ASCERR.
1069 * The type of error is indicated by the function's name and the
1070 * arguments to fprintf.
1071 */
1072 static void
1073 ErrMsg_BracesEOF(void){
1074 error_reporter(ASC_USER_ERROR, Asc_ModuleBestName(Asc_CurrentModule()), start_line, NULL
1075 ,"End of file reached within a unit, data table or explanation. No closing brace "
1076 "found for open brace."
1077 );
1078 }
1079
1080
1081 static void
1082 ErrMsg_CommentEOF(void)
1083 {
1084 FPRINTF(ASCERR,
1085 "Error:\tEnd of file reached within a comment.\n"
1086 "\tNo close-comment found for comment starting on line %s:%lu\n",
1087 Asc_ModuleBestName(Asc_CurrentModule()), start_line);
1088 }
1089
1090
1091 static void
1092 ErrMsg_LongID(void)
1093 {
1094 FPRINTF(ASCERR,
1095 "Error:\tIdentifier too long on line %s:%lu.\n"
1096 "\tIdentifier \"%s\" exceeds the maximum identifier size of %d\n",
1097 Asc_ModuleBestName(Asc_CurrentModule()),
1098 yy_line,
1099 yytext,
1100 YY_MAXLEN);
1101 }
1102
1103
1104 static void
1105 ErrMsg_LongSymbol(void)
1106 {
1107 FPRINTF(ASCERR,
1108 "Error:\tSymbol too long on line %s:%lu.\n"
1109 "\tSymbol %s exceeds the maximum symbol size of %d\n",
1110 Asc_ModuleBestName(Asc_CurrentModule()),
1111 yy_line,
1112 yytext,
1113 YY_MAXLEN);
1114 }
1115
1116
1117 static void
1118 ErrMsg_DoubleQuoteEOF(void)
1119 {
1120 FPRINTF(ASCERR,
1121 "Error:\tEnd of file reached with a double quoted string.\n"
1122 "\tNo close quote found for the open quote on line %s:%lu\n",
1123 Asc_ModuleBestName(Asc_CurrentModule()), start_line);
1124 }
1125
1126
1127 static void
1128 ErrMsg_SymbolEOF(void)
1129 {
1130 FPRINTF(ASCERR,
1131 "Error:\tEnd of file reached within a symbol.\n"
1132 "\tNo close quote found for symbol on line %s:%lu\n",
1133 Asc_ModuleBestName(Asc_CurrentModule()), yy_line);
1134 }
1135
1136
1137 static void
1138 ErrMsg_SymbolEOL(void)
1139 {
1140 FPRINTF(ASCERR,
1141 "Error:\tEnd of line reached within a symbol.\n"
1142 "\tNo close quote found for symbol on line %s:%lu\n",
1143 Asc_ModuleBestName(Asc_CurrentModule()), yy_line);
1144 }
1145
1146 #define ERRCOUNT_UNEXPCHAR 5
1147 static void ErrMsg_UnexpectedChar(){
1148 static int errcount=0;
1149 if(errcount<ERRCOUNT_UNEXPCHAR){
1150 error_reporter(ASC_USER_ERROR
1151 ,Asc_ModuleBestName(Asc_CurrentModule()), yy_line, NULL
1152 ,"Unexpected character '%s' in input (ASCII %d). If you pasted"
1153 " text from another source (a word-processor, web page, etc) be"
1154 " careful that you haven't pasted strange quotes, hyphens, etc."
1155 , yytext, yytext[0]
1156 );
1157 errcount++;
1158 if(errcount==ERRCOUNT_UNEXPCHAR){
1159 ERROR_REPORTER_HERE(ASC_PROG_NOTE
1160 ,"Further reports of this error will be supressed\n"
1161 );
1162 }
1163 }
1164 }

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