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

Contents of /trunk/base/generic/compiler/scanner.l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 661 - (show annotations) (download)
Wed Jun 14 06:20:50 2006 UTC (18 years, 1 month ago) by johnpye
File size: 32473 byte(s)
Cleaned up module.c and some more minor changes to scanner.h and scanner.l commenting.
1 %{
2 /* ASCEND modelling environment
3 Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly
4 Copyright (C) 2006 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 "utilities/ascConfig.h"
34 #include "utilities/ascMalloc.h"
35 #include "compiler/compiler.h"
36 /* everything between here and the next comment is only here */
37 #include "compiler/fractions.h"
38 #include "compiler/dimen.h"
39 #include "compiler/functype.h"
40 #include "compiler/func.h"
41 #include "compiler/types.h"
42 #include "compiler/stattypes.h"
43 #include "compiler/fractions.h"
44 #include "compiler/proc.h"
45 /* because ascParse.h has a nasty union we can't digest without them. */
46 #include "compiler/ascParse.h"
47 /* these below we actually need */
48 #include "general/list.h"
49 #include "compiler/module.h"
50 #include "compiler/scanner.h"
51 #include "compiler/symtab.h"
52 #include "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>"OR" { return OR_TOK ; }
247 <INITIAL>"OTHERWISE" { return OTHERWISE_TOK ; }
248 <INITIAL>"OUTPUT" { return OUTPUT_TOK ; }
249 <INITIAL>"PROD" { return PROD_TOK ; }
250 <INITIAL>"PROVIDE" { return PROVIDE_TOK ; }
251 <INITIAL>"REFINES" { return REFINES_TOK ; }
252 <INITIAL>"REPLACE" { return REPLACE_TOK ; }
253 <INITIAL>"REQUIRE" { return REQUIRE_TOK ; }
254 <INITIAL>"RETURN" { return RETURN_TOK ; }
255 <INITIAL>"RUN" { return RUN_TOK ; }
256 <INITIAL>"SATISFIED" { return SATISFIED_TOK ; }
257 <INITIAL>"SELECT" { return SELECT_TOK ; }
258 <INITIAL>"SUCH_THAT" { return SUCHTHAT_TOK ; }
259 <INITIAL>"SUM" { return SUM_TOK ; }
260 <INITIAL>"SIZE" { return SIZE_TOK ; }
261 <INITIAL>"SWITCH" { return SWITCH_TOK ; }
262 <INITIAL>"STOP" { return STOP_TOK ; }
263 <INITIAL>"THEN" { return THEN_TOK ; }
264 <INITIAL>"TRUE" { return TRUE_TOK ; }
265 <INITIAL>"UNION" { return UNION_TOK ; }
266 <INITIAL>"UNITS" { return UNITS_TOK ; }
267 <INITIAL>"UNIVERSAL" { return UNIVERSAL_TOK ; }
268 <INITIAL>"USE" { return USE_TOK ; }
269 <INITIAL>"VALUE" { return VALUE_TOK ; }
270 <INITIAL>"WHEN" { return WHEN_TOK ; }
271 <INITIAL>"WHERE" { return WHERE_TOK ; }
272 <INITIAL>"WHILE" { return WHILE_TOK ; }
273 <INITIAL>"WILL_BE" { return WILLBE_TOK ; }
274 <INITIAL>"WILL_BE_THE_SAME" { return WILLBETHESAME_TOK ; }
275 <INITIAL>"WILL_NOT_BE_THE_SAME" { return WILLNOTBETHESAME_TOK ; }
276 <INITIAL>"WITH" { return WITH_TOK ; }
277 <INITIAL>"WITH_VALUE" { return WITH_VALUE_T ; }
278
279 /*
280 * Code to handle (* Comments *)
281 *
282 * "(*" puts us into the Comment state. Comments nest, so in the
283 * Comment state we need to look for "(*" that increases the nesting
284 * level and "*)" that will lower it.
285 * Flex is faster if we match as much as possible, so we repeat
286 * patterns with and without the "\n" (although it is more difficult
287 * for the maintainer to understand) to avoid the overhead of a
288 * separate "\n" rule.
289 * Do NOT try to match \(\*+ since that causes "(****)" to parse
290 * incorrectly.
291 */
292
293 <INITIAL>\(\* {
294 /* Match "(" followed by "*" puts us into
295 * the COMMENT state. Don't use \*+ since
296 * that will parse "(***)" incorrectly.
297 * Initialize the nesting level.
298 * Store the current line for ErrMsg use.
299 */
300 BEGIN (Comment);
301 CommentNestLevel = 1;
302 start_line = yy_line;
303 break;
304 }
305 <Comment>\(\*[^*(\n]* {
306 /* Match "(" followed "*" followed by
307 * anything that's not "(" nor "*".
308 * Increase the commment nesting level.
309 */
310 CommentNestLevel++;
311 break;
312 }
313 <Comment>\(\*[^*(\n]*\n {
314 /* Match "(" followed by "*" followed by
315 * anything that's not "(" nor "*".
316 * Increase the commment nesting level.
317 */
318 yy_line++;
319 CommentNestLevel++;
320 break;
321 }
322 <Comment>[^*(\n]*\*+\) {
323 /* Match anything not "*" or "(" followed
324 * by one or more "*"s followed by ")".
325 * This decreases the comment nesting level
326 * and kicks us out if we're back to zero.
327 */
328 CommentNestLevel--;
329 if (CommentNestLevel == 0) {
330 BEGIN (INITIAL);
331 }
332 break;
333 }
334 <Comment>[^*(\n]* {
335 /* Eat anything that's not a "*" nor a "("
336 */
337 break;
338 }
339 <Comment>[^*(\n]*\n {
340 /* Eat anything that's not a "*" nor a "("
341 * that is followed by a newline.
342 * This rule also matches empty line.
343 */
344 yy_line++;
345 break;
346 }
347 <Comment>\(+[^*(\n]* {
348 /* Eat "("s not followed by "*"
349 */
350 break;
351 }
352 <Comment>\(+[^*(\n]*\n {
353 /* Eat "("s not followed by "*" plus a "\n"
354 */
355 yy_line++;
356 break;
357 }
358 <Comment>\*+[^*()\n]* {
359 /* Eat "*"s not followed by ")"
360 */
361 break;
362 }
363 <Comment>\*+[^*()\n]*\n {
364 /* Eat "*" not followed by ")" plus a "\n"
365 */
366 yy_line++;
367 break;
368 }
369 <Comment><<EOF>> {
370 /* An EOF in a Comment means bad nesting.
371 * Print an error and pop back a level
372 * or return ENDTOK if no more input.
373 */
374 ErrMsg_CommentEOF();
375 CommentNestLevel = 0;
376 if ( Asc_ScannerPopBuffer() == 1 ) {
377 return ENDTOK;
378 }
379 break;
380 }
381
382
383 /*
384 * Code to handle 'Symbols'
385 *
386 * Symbols are simple: they are 'singely quoted strings' that
387 * exist on a single line. Look for anything that is not
388 * a quote or a newline to get the text of the symbol.
389 */
390
391 <INITIAL>\' {
392 /* A single quote (') in the INITIAL state
393 * puts us into the Symbol state.
394 */
395 BEGIN (Symbol);
396 break;
397 }
398 <Symbol>[^'\n]*\' {
399 /* Anything that is not a (') nor a newline
400 * followed by a (') is the symbol's text.
401 * Return to the INITIAL state, store the
402 * symbol in the symbol table and return
403 * SYMBOL_TOK to the parser.
404 */
405 BEGIN (INITIAL);
406 /* strip off the final (')
407 */
408 yytext[--yyleng] = '\0';
409 if (yyleng > YY_MAXLEN) {
410 ErrMsg_LongSymbol();
411 break;
412 }
413 zz_lval.sym_ptr = AddSymbolL(yytext,yyleng);
414 return SYMBOL_TOK;
415 }
416 <Symbol>[^'\n]*\n {
417 /* If we find a newline before a ('), the
418 * symbol is unterminated. Print an error
419 * message and return to the INITIAL state.
420 */
421 ErrMsg_SymbolEOL();
422 yy_line++;
423 BEGIN(INITIAL);
424 break;
425 }
426 <Symbol><<EOF>> {
427 /* If we find an EOF before a ('), the
428 * symbol is unterminated. Print an error
429 * message and pop to the previously
430 * REQUIREd file or return ENDTOK if the
431 * pop fails due to no more input.
432 */
433 ErrMsg_SymbolEOF();
434 if ( Asc_ScannerPopBuffer() == 1 ) {
435 return ENDTOK;
436 }
437 break;
438 }
439
440
441 /*
442 * Code to handle "Text in Double Quotes"
443 *
444 * The DoubleQuote state begins with a double quote and ends
445 * with a double quote; double quotes can be included by
446 * escaping them with a backslash (e.g. \"). There is no
447 * nesting level to worry about.
448 * Flex is faster if we match as much as possible, so we repeat
449 * patterns with and without the "\n" (although it is more difficult
450 * for the maintainer to understand) to avoid the overhead of a
451 * separate "\n" rule.
452 * We want to keep the text, so we need to call yymore().
453 */
454
455 <INITIAL>\" {
456 /* A double quote puts us into the
457 * DoubleQuote state. Save the line
458 * number for error reporting.
459 */
460 BEGIN (DoubleQuote);
461 start_line = yy_line;
462 break;
463 }
464 <DoubleQuote>[^\\"\n]*\\. {
465 /* A backslash \ in the DoubleQuote
466 * state protects any character.
467 */
468 MatchedBackslash++;
469 yymore();
470 break;
471 }
472 <DoubleQuote>[^\\"\n]*\\\n {
473 /* A backslash \ in the DoubleQuote
474 * state protects a newline.
475 */
476 MatchedBackslash++;
477 yy_line++;
478 yymore();
479 break;
480 }
481 <DoubleQuote>[^\\"\n]*\" {
482 /* A double quote in the DoubleQuote state
483 * (that is not protected by backslash)
484 * will put us back in the INITIAL state.
485 * Process the string and return DQUOTE_TOK
486 * to the parser.
487 */
488 BEGIN (INITIAL);
489 /* Remove the final double quote
490 */
491 yytext[--yyleng] = '\0';
492 /* Do backslash substitutions on the string
493 * before returing it to the scanner.
494 */
495 if ( MatchedBackslash != 0 ) {
496 Process_Backslashes();
497 MatchedBackslash = 0;
498 }
499 zz_lval.dquote_ptr =
500 CopyIntoWorkBuffer(yytext,yyleng);
501 return DQUOTE_TOK;
502 }
503 <DoubleQuote>[^\\"\n]* {
504 /* Match anything that is not backslash nor
505 * doublequote and add it to the text.
506 */
507 yymore();
508 break;
509 }
510 <DoubleQuote>[^\\"\n]*\n {
511 /* Match anything that is not backslash nor
512 * doublequote and add it to the text.
513 * This also matches an empty line.
514 */
515 yy_line++;
516 yymore();
517 break;
518 }
519 <DoubleQuote><<EOF>> {
520 /* End of File in a DoubleQuote state
521 * means no matching double quote.
522 * Print an error and pop next buffer
523 * off the RequireStack or return ENDTOK
524 * if there is no more input.
525 */
526 ErrMsg_DoubleQuoteEOF();
527 MatchedBackslash = 0;
528 if ( Asc_ScannerPopBuffer() == 1 ) {
529 return ENDTOK;
530 }
531 break;
532 }
533
534
535 /*
536 * Code to handle { Text in Braces }
537 *
538 * "{" puts us into the BracedText state. Braces nest, so
539 * in the BracedText state we need to look for "{" that increases
540 * the nesting level and "}" that will lower it.
541 * Flex is faster if we match as much as possible, so we repeat
542 * patterns with and without the "\n" (although it is more difficult
543 * for the maintainer to understand) to avoid the overhead of a
544 * separate "\n" rule.
545 * We want to keep the text we scan, so we have to call yymore().
546 */
547
548 <INITIAL>\{{blank}*\n { /* A "{" puts us into the BracedText state.
549 * If from the opening "{" to the first
550 * newline is all whitespace, then ignore
551 * it.
552 * Initialize the nesting level.
553 * Save the current line number for
554 * error message reporting.
555 */
556 BEGIN (BracedText);
557 BracesNestLevel = 1;
558 start_line = yy_line;
559 yy_line++;
560 break;
561 }
562 <INITIAL>\{ {
563 /* A "{" puts us into the BracedText state.
564 * Initialize the nesting level.
565 * Save the current line number for
566 * error message reporting.
567 */
568 BEGIN (BracedText);
569 BracesNestLevel = 1;
570 start_line = yy_line;
571 break;
572 }
573 <BracedText>[^\\{}\n]*\\. {
574 /* A backslash \ in the BracedText state
575 * protects any character and does not
576 * affect the Nesting Level.
577 */
578 MatchedBackslash++;
579 yymore();
580 break;
581 }
582 <BracedText>[^\\{}\n]*\\\n {
583 /* A backslash \ in the BracedText state
584 * protects a newline.
585 */
586 MatchedBackslash++;
587 yy_line++;
588 yymore();
589 break;
590 }
591 <BracedText>\{[^\\{}\n]* {
592 /* A "{" in the braces state gets added to
593 * the text and increase the nesting level.
594 */
595 BracesNestLevel++;
596 yymore();
597 break;
598 }
599 <BracedText>\{[^\\{}\n]*\n {
600 /* A "{" in the braces state gets added to
601 * the text and increase the nesting level.
602 */
603 yy_line++;
604 BracesNestLevel++;
605 yymore();
606 break;
607 }
608 <BracedText>[^\\{}\n]*\} {
609 /* A "}" will reduce the nesting level.
610 * If the nesting level is zero, go back to
611 * the INITIAL level, save the text as a
612 * Symbol, do the backslash substitution,
613 * and return BRACEDTEXT_TOK to the
614 * parse; otherwise, add the "}" to the
615 * text and keep scanning.
616 */
617 BracesNestLevel--;
618 if (BracesNestLevel == 0) {
619 BEGIN (INITIAL);
620 /* Remove the final "}"
621 */
622 yytext[--yyleng] = '\0';
623 /* Do backslash substitutions on the text
624 * before returing it to the scanner.
625 */
626 if ( MatchedBackslash != 0 ) {
627 Process_Backslashes();
628 MatchedBackslash = 0;
629 }
630 zz_lval.braced_ptr =
631 CopyIntoWorkBuffer(yytext,yyleng);
632 return BRACEDTEXT_TOK;
633 }
634 yymore();
635 break;
636 }
637 <BracedText>[^\\{}\n]* {
638 /* Match anything that is not "{" nor "}"
639 * nor "\\"(backslash) and add it to text.
640 */
641 yymore();
642 break;
643 }
644 <BracedText>[^\\{}\n]*\n {
645 /* Match anything that is not "{" nor "}"
646 * nor "\\"(backslash) followed by a "\n"
647 * and add it to text.
648 * This also matches an empty line.
649 */
650 yy_line++;
651 yymore();
652 break;
653 }
654 <BracedText><<EOF>> {
655 /* End of File in braces means bad nesting.
656 * Print an error message and pop to the
657 * previously REQUIREd file or return
658 * ENDTOK if no more input.
659 */
660 ErrMsg_BracesEOF();
661 BracesNestLevel = 0;
662 MatchedBackslash = 0;
663 if ( Asc_ScannerPopBuffer() == 1 ) {
664 return ENDTOK;
665 }
666 break;
667 }
668
669
670 /*
671 * Code to handle Miscellaneous types.
672 *
673 */
674
675 <INITIAL>{integer} {
676 /* An integer. Defn near top of file.
677 */
678 zz_lval.int_value = atol(yytext);
679 return INTEGER_TOK;
680 }
681
682 <INITIAL>{integer}/".." {
683 /* An integer as the first number in a
684 * range (need to avoid parsing "1..2"
685 * as the real numbers 1.0 and 0.2).
686 */
687 zz_lval.int_value = atol(yytext);
688 return INTEGER_TOK;
689 }
690
691 <INITIAL>{real} {
692 /* A real number. Defn near top of file.
693 */
694 zz_lval.real_value = atof(yytext);
695 return REAL_TOK;
696 }
697
698 <INITIAL>{IDChar}+ {
699 /* An identifier. Defn near top of file.
700 */
701 if (yyleng >YY_MAXLEN) {
702 ErrMsg_LongID();
703 break;
704 }
705 zz_lval.id_ptr = AddSymbolL(yytext,yyleng);
706 return IDENTIFIER_TOK;
707 }
708
709 <INITIAL>{blank}* {
710 /* Ignore whitespace. */
711 break;
712 }
713 <INITIAL>{blank}*\n {
714 /* Ignore whitespace. */
715 yy_line++;
716 break;
717 }
718
719
720 <INITIAL>. {
721 /* Unknown character. Print error
722 * message and keep going.
723 */
724 ErrMsg_UnexpectedChar();
725 break;
726 }
727
728 <INITIAL><<EOF>> {
729 /* Print an error message if we
730 * reached EOF in the middle of a
731 * type definition. Pop to the
732 * previously REQUIREd file or return
733 * ENDTOK if no more input.
734 */
735 Asc_ErrMsgTypeDefnEOF();
736 if ( Asc_ScannerPopBuffer() == 1 ) {
737 return ENDTOK;
738 }
739 break;
740 }
741
742 %%
743 /*
744 * int yywrap(void);
745 *
746 * This returns 1 if the scanner should stop parsing, or
747 * 0 if the scanner should continue. Flex requires this
748 * function unless %option noyywrap is defined.
749 */
750 int
751 yywrap(void)
752 {
753 return 1;
754 }
755
756
757 /*
758 * See the header file scanner.h for a description of this function.
759 */
760 unsigned long
761 LineNum(void)
762 {
763 return yy_line;
764 }
765
766
767 /*
768 * See the header file scanner.h for a description of this function.
769 */
770 void
771 Asc_ScannerAssignFile(FILE *f, unsigned long linenum)
772 {
773 yyin = f;
774 yy_line = linenum;
775 if ( RequireIndex == 0 ) {
776 yyrestart(f);
777 }
778 }
779
780 /*
781 * See the header file scanner.h for a description of this function.
782 */
783 void
784 Asc_ScannerAssignString(void *yybs, unsigned long linenum, int first)
785 {
786 /* yyin = f; */
787 yy_line = linenum;
788 yy_switch_to_buffer((YY_BUFFER_STATE)yybs);
789 if (first) {
790 BEGIN(INITIAL);
791 }
792 if ( RequireIndex == 0 ) {
793 yyrestart((FILE *)NULL); /* ? ? ? should be reading from a string buffer... */
794 }
795 }
796
797
798 /*
799 * See the header file scanner.h for a description of this function.
800 */
801 int
802 Asc_ScannerPushBuffer(CONST char *filename)
803 {
804 int status; /* status returned from Asc_RequireModule */
805
806 if ( RequireIndex >= MAX_REQUIRE_DEPTH ) {
807 FPRINTF(ASCERR,
808 "Error:\tREQUIRE nested too deeply (%d levels) on line %s:%lu.\n"
809 "\tFile \"%s\" not read.\n",
810 RequireIndex,
811 Asc_ModuleBestName(Asc_CurrentModule()),
812 yy_line,
813 filename);
814 return 1;
815 }
816
817 /* The current Flex buffer is not on the RequireStack yet, so add it
818 * before calling Asc_OpenModule. We need to increment RequireIndex
819 * before calling Asc_OpenModule due to the check in
820 * Asc_ScannerAssignFile.
821 */
822 RequireStack[RequireIndex++] = YY_CURRENT_BUFFER;
823
824 Asc_RequireModule( filename, &status );
825 if( status == 5 ) {
826 /* already required */
827 RequireIndex--;
828 FPRINTF(ASCINF, "REQUIREd module \"%s\" already PROVIDEd\n", filename);
829 return 1;
830 }
831 if( status == 4 ) {
832 /* recursive require */
833 RequireIndex--;
834 FPRINTF(ASCWAR, "Asc-Warn: Recursive REQUIRE for module \"%s\", ignored\n",
835 filename);
836 return 1;
837 }
838 if ( status != 0 ) {
839 /* The open failed. Decrement RequireIndex and print an error.
840 */
841 RequireIndex--;
842 FPRINTF(ASCERR,
843 "Error:\tREQUIRE cannot open module \"%s\" on line %s:%lu\n",
844 filename,
845 Asc_ModuleBestName(Asc_CurrentModule()),
846 yy_line);
847 return 2;
848 }
849
850 /* Asc_OpenModule was successful, so print a message, switch to the
851 * new buffer in the INITIAL state.
852 * SHOULD never reach here with a string buffer as they cannot be
853 * REQUIREd.
854 */
855 Asc_FPrintf(stderr,"REQUIREing file \"%s\"\n", filename);
856 yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
857 BEGIN (INITIAL);
858 return 0;
859 }
860
861
862 /*
863 * int Asc_ScannerPopBuffer()
864 *
865 * When we reach an End Of File (EOF) in the scanner, we call this
866 * function to pop us to the file which REQUIREd the file we just
867 * reached the end of and return 0. If there are no more files on the
868 * RequireStack, return 1.
869 */
870 static int
871 Asc_ScannerPopBuffer(void)
872 {
873 Asc_CloseCurrentModule(); /* the current module may be NULL. */
874 if ( RequireIndex == 0 ) {
875 return 1;
876 }
877
878 yy_delete_buffer(YY_CURRENT_BUFFER);
879 yy_switch_to_buffer( RequireStack[--RequireIndex] );
880 BEGIN(INITIAL);
881 return 0;
882 }
883
884 void Asc_ScannerReleaseStringBuffer(void *yybs)
885 {
886 yy_delete_buffer((YY_BUFFER_STATE)yybs);
887 yy_switch_to_buffer( RequireStack[--RequireIndex] );
888 BEGIN(INITIAL);
889 }
890
891 void *Asc_ScannerCreateStringBuffer(CONST char *string, int len)
892 {
893 /* we hope to god yy_scan_bytes does not change current buffer */
894 YY_BUFFER_STATE yybs;
895 /* push current, don't care its name or type. */
896 RequireStack[RequireIndex++] = YY_CURRENT_BUFFER;
897 yybs = yy_scan_bytes(string, len);
898 assert(yybs);
899 return (void *)yybs;
900 }
901
902 /*
903 * g_workbuf = CopyIntoWorkBuffer(str, len)
904 * char *g_workbuf;
905 * CONST char *str;
906 * unsigned long len;
907 *
908 * Copy the string `str' having length `len' into the Scanner's Working
909 * Buffer g_workbuf and return g_workbuf if successful or NULL if
910 * unsuccessful (due to lack of memory).
911 * If g_workbuf is too short to hold `str', it is repeatably doubled until
912 * either it is big enough or memory is exhausted.
913 * We actually copy len+1 characters of `str' into g_workbuf so that the
914 * final \0 gets copied also.
915 * Global Effects: Modifies the contents of g_workbuf
916 * Possibly changes the address of g_workbuf (on realloc)
917 */
918 static char *
919 CopyIntoWorkBuffer(CONST char *str, unsigned long len)
920 {
921 static size_t g_workbuf_len = WORKBUF_INIT_SIZE; /* length of g_workbuf */
922
923 assert(str[len]=='\0'); /* is this true for all yacc? */
924 len++; /* add one to make sure we have a final '\0' */
925 if (( len >= g_workbuf_len ) || ( g_workbuf == NULL )) {
926 while( len >= g_workbuf_len ) {
927 g_workbuf_len *= 2;
928 }
929 if (g_workbuf == NULL ) {
930 g_workbuf = (char*)ascmalloc( g_workbuf_len );
931 } else {
932 g_workbuf = (char*)ascrealloc( (void*)g_workbuf, g_workbuf_len );
933 }
934 if ( g_workbuf == NULL ) {
935 return NULL;
936 }
937 }
938 return strncpy(g_workbuf, str, len); /* does not add a NULL char */
939 }
940
941
942 extern void
943 Asc_DestroyScannerWorkBuffer(void)
944 {
945 if (g_workbuf != NULL) {
946 ascfree(g_workbuf);
947 }
948 g_workbuf = NULL;
949 }
950
951 void Asc_DestroyScannerInputBuffer(void)
952 {
953 if (YY_CURRENT_BUFFER != NULL) {
954 yy_delete_buffer(YY_CURRENT_BUFFER);
955 }
956 }
957
958 /*
959 * int Process_Backslashes(void)
960 *
961 * Covert any backslash \ escapes into the correct character.
962 * Operates on and modifies in place the value of yytext; yyleng
963 * is adjusted accordingly. Returns the number of backslash
964 * substitutions made. The following are supported:
965 * \a (alert)
966 * \b (backspace)
967 * \f (formfeed)
968 * \n (newline)
969 * \r (carriage return)
970 * \t (horizontal tab)
971 * \v (vertical tab)
972 * \xhh (hexadecimal hh) ***** NOT IMPLEMENTED *****
973 * \ooo (octal ooo where o == [0-7]) ***** NOT IMPLEMENTED *****
974 * \\n (backslash before newline removes the backslash and newline)
975 * \. (any other char produces that char)
976 */
977 static int
978 Process_Backslashes(void)
979 {
980 int old_index;
981 int new_index;
982 int substitution_count = 0;
983
984 for (old_index=0, new_index=0; old_index<yyleng; old_index++) {
985 if (yytext[old_index] != '\\') {
986 yytext[new_index++] = yytext[old_index];
987 } else {
988 if (++old_index < yyleng) {
989 switch(yytext[old_index]) {
990 case 'a':
991 yytext[new_index++] = '\a';
992 substitution_count++;
993 break;
994 case 'b':
995 yytext[new_index++] = '\b';
996 substitution_count++;
997 break;
998 case 'f':
999 yytext[new_index++] = '\f';
1000 substitution_count++;
1001 break;
1002 case 'n':
1003 yytext[new_index++] = '\n';
1004 substitution_count++;
1005 break;
1006 case 'r':
1007 yytext[new_index++] = '\r';
1008 substitution_count++;
1009 break;
1010 case 't':
1011 yytext[new_index++] = '\t';
1012 substitution_count++;
1013 break;
1014 case 'v':
1015 yytext[new_index++] = '\v';
1016 substitution_count++;
1017 break;
1018 case 'x':
1019 /* need to add processing for
1020 * hexadecimal numbers \xhh here
1021 */
1022 yytext[new_index++] = yytext[old_index];
1023 substitution_count++;
1024 break;
1025 case '0':
1026 case '1':
1027 case '2':
1028 case '3':
1029 case '4':
1030 case '5':
1031 case '6':
1032 case '7':
1033 /* need to add processing for
1034 * octal numbers \ooo here
1035 */
1036 yytext[new_index++] = yytext[old_index];
1037 substitution_count++;
1038 break;
1039 case '\n':
1040 /* Backslash at the end of the line removes
1041 * the slash and the newline from the result,
1042 * so no futher processing is needed.
1043 */
1044 substitution_count++;
1045 break;
1046 default:
1047 yytext[new_index++] = yytext[old_index];
1048 substitution_count++;
1049 break;
1050 }
1051 }
1052 }
1053 }
1054 yytext[new_index] = '\0';
1055 yyleng = new_index;
1056 return substitution_count;
1057 }
1058
1059
1060 /*
1061 * void ErrMsg_*(void)
1062 *
1063 * The following all print error messages to the file handle ASCERR.
1064 * The type of error is indicated by the function's name and the
1065 * arguments to fprintf.
1066 */
1067 static void
1068 ErrMsg_BracesEOF(void)
1069 {
1070 FPRINTF(ASCERR,
1071 "Error:\tEnd of file reached within a unit, data table, or "
1072 "explanation.\n"
1073 "\tNo close brace found for open brace on line %s:%lu\n",
1074 Asc_ModuleBestName(Asc_CurrentModule()), start_line);
1075 }
1076
1077
1078 static void
1079 ErrMsg_CommentEOF(void)
1080 {
1081 FPRINTF(ASCERR,
1082 "Error:\tEnd of file reached within a comment.\n"
1083 "\tNo close-comment found for comment starting on line %s:%lu\n",
1084 Asc_ModuleBestName(Asc_CurrentModule()), start_line);
1085 }
1086
1087
1088 static void
1089 ErrMsg_LongID(void)
1090 {
1091 FPRINTF(ASCERR,
1092 "Error:\tIdentifier too long on line %s:%lu.\n"
1093 "\tIdentifier \"%s\" exceeds the maximum identifier size of %d\n",
1094 Asc_ModuleBestName(Asc_CurrentModule()),
1095 yy_line,
1096 yytext,
1097 YY_MAXLEN);
1098 }
1099
1100
1101 static void
1102 ErrMsg_LongSymbol(void)
1103 {
1104 FPRINTF(ASCERR,
1105 "Error:\tSymbol too long on line %s:%lu.\n"
1106 "\tSymbol %s exceeds the maximum symbol size of %d\n",
1107 Asc_ModuleBestName(Asc_CurrentModule()),
1108 yy_line,
1109 yytext,
1110 YY_MAXLEN);
1111 }
1112
1113
1114 static void
1115 ErrMsg_DoubleQuoteEOF(void)
1116 {
1117 FPRINTF(ASCERR,
1118 "Error:\tEnd of file reached with a double quoted string.\n"
1119 "\tNo close quote found for the open quote on line %s:%lu\n",
1120 Asc_ModuleBestName(Asc_CurrentModule()), start_line);
1121 }
1122
1123
1124 static void
1125 ErrMsg_SymbolEOF(void)
1126 {
1127 FPRINTF(ASCERR,
1128 "Error:\tEnd of file reached within a symbol.\n"
1129 "\tNo close quote found for symbol on line %s:%lu\n",
1130 Asc_ModuleBestName(Asc_CurrentModule()), yy_line);
1131 }
1132
1133
1134 static void
1135 ErrMsg_SymbolEOL(void)
1136 {
1137 FPRINTF(ASCERR,
1138 "Error:\tEnd of line reached within a symbol.\n"
1139 "\tNo close quote found for symbol on line %s:%lu\n",
1140 Asc_ModuleBestName(Asc_CurrentModule()), yy_line);
1141 }
1142
1143
1144 static void
1145 ErrMsg_UnexpectedChar()
1146 {
1147 FPRINTF(ASCERR,
1148 "Error:\tUnexpected character \"%s\" in input on line %s:%lu.\n",
1149 yytext,
1150 Asc_ModuleBestName(Asc_CurrentModule()),
1151 yy_line);
1152 }

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