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

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