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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 390 - (hide annotations) (download)
Thu Mar 30 06:41:17 2006 UTC (16 years, 11 months 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 aw0a 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 johnpye 385 static unsigned long yy_line = 1;
77 aw0a 1 /* 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 johnpye 148 <INITIAL>"ARE_ALIKE" { return AREALIKE_T ; }
194     <INITIAL>"ARE_THE_SAME" { return ARETHESAME_T ; }
195 aw0a 1 <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 johnpye 148 <INITIAL>"CHOICE" { return CHOICE_T ; }
203 aw0a 1 <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 johnpye 183 <INITIAL>"FALL_THROUGH" { return FALLTHRU_T ; }
220     <INITIAL>"FIX" { return FIX_T ; }
221 johnpye 304 <INITIAL>"FREE" { return FREE_T ; }
222 aw0a 1 <INITIAL>"FOR" { return FOR_T ; }
223     <INITIAL>"FROM" { return FROM_T ; }
224     <INITIAL>"GLOBAL" { return GLOBAL_T ; }
225 johnpye 148 <INITIAL>"ASSERT" { return ASSERT_T ; }
226 aw0a 1 <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 johnpye 385 start_line = yy_line;
301 aw0a 1 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 johnpye 385 yy_line++;
317 aw0a 1 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 johnpye 385 yy_line++;
343 aw0a 1 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 johnpye 385 yy_line++;
354 aw0a 1 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 johnpye 385 yy_line++;
365 aw0a 1 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 johnpye 385 if (yyleng > YY_MAXLEN) {
408 aw0a 1 ErrMsg_LongSymbol();
409     break;
410     }
411 johnpye 385 yylval.sym_ptr = AddSymbolL(yytext,yyleng);
412 aw0a 1 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 johnpye 385 yy_line++;
421 aw0a 1 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 johnpye 385 start_line = yy_line;
460 aw0a 1 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 johnpye 385 yy_line++;
476 aw0a 1 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 johnpye 385 yylval.dquote_ptr =
498 aw0a 1 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 johnpye 385 yy_line++;
514 aw0a 1 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 johnpye 385 start_line = yy_line;
557     yy_line++;
558 aw0a 1 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 johnpye 385 start_line = yy_line;
569 aw0a 1 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 johnpye 385 yy_line++;
586 aw0a 1 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 johnpye 385 yy_line++;
602 aw0a 1 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 johnpye 385 yylval.braced_ptr =
629 aw0a 1 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 johnpye 385 yy_line++;
649 aw0a 1 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 johnpye 385 yylval.int_value = atol(yytext);
677 aw0a 1 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 johnpye 385 yylval.int_value = atol(yytext);
686 aw0a 1 return INTEGER_T;
687     }
688    
689     <INITIAL>{real} {
690     /* A real number. Defn near top of file.
691     */
692 johnpye 385 yylval.real_value = atof(yytext);
693 aw0a 1 return REAL_T;
694     }
695    
696     <INITIAL>{IDChar}+ {
697     /* An identifier. Defn near top of file.
698     */
699 johnpye 385 if (yyleng >YY_MAXLEN) {
700 aw0a 1 ErrMsg_LongID();
701     break;
702     }
703 johnpye 385 yylval.id_ptr = AddSymbolL(yytext,yyleng);
704 aw0a 1 return IDENTIFIER_T;
705     }
706    
707     <INITIAL>{blank}* {
708     /* Ignore whitespace. */
709     break;
710     }
711     <INITIAL>{blank}*\n {
712     /* Ignore whitespace. */
713 johnpye 385 yy_line++;
714 aw0a 1 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 johnpye 390 * int yywrap(void);
743 aw0a 1 *
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 johnpye 390 yywrap(void)
750 aw0a 1 {
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 johnpye 385 return yy_line;
762 aw0a 1 }
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 johnpye 385 yy_line = linenum;
773 aw0a 1 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 johnpye 385 yy_line = linenum;
786 aw0a 1 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 johnpye 385 yy_line,
811 aw0a 1 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 johnpye 385 yy_line);
845 aw0a 1 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 johnpye 337 Asc_FPrintf(stderr,"REQUIREing file \"%s\"\n", filename);
854 johnpye 385 yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
855 aw0a 1 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 johnpye 385 yy_line,
1094 aw0a 1 yytext,
1095 johnpye 385 YY_MAXLEN);
1096 aw0a 1 }
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 johnpye 385 yy_line,
1107 aw0a 1 yytext,
1108 johnpye 385 YY_MAXLEN);
1109 aw0a 1 }
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 johnpye 385 Asc_ModuleBestName(Asc_CurrentModule()), yy_line);
1129 aw0a 1 }
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 johnpye 385 Asc_ModuleBestName(Asc_CurrentModule()), yy_line);
1139 aw0a 1 }
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 johnpye 385 yy_line);
1150 aw0a 1 }

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