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 zz_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 = zz_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 |
zz_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 |
zz_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 |
zz_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 |
zz_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 > ZZ_MAXLEN) { |
408 |
ErrMsg_LongSymbol(); |
409 |
break; |
410 |
} |
411 |
zz_lval.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 |
zz_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 = zz_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 |
zz_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 |
zz_lval.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 |
zz_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 = zz_line; |
557 |
zz_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 = zz_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 |
zz_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 |
zz_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 |
zz_lval.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 |
zz_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 |
zz_lval.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 |
zz_lval.int_value = atol(yytext); |
686 |
return INTEGER_T; |
687 |
} |
688 |
|
689 |
<INITIAL>{real} { |
690 |
/* A real number. Defn near top of file. |
691 |
*/ |
692 |
zz_lval.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 >ZZ_MAXLEN) { |
700 |
ErrMsg_LongID(); |
701 |
break; |
702 |
} |
703 |
zz_lval.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 |
zz_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 zz_wrap(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 |
zz_wrap(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 zz_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 |
zz_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 |
zz_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 |
zz_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 |
zz_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(zz_in,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 |
zz_line, |
1094 |
yytext, |
1095 |
ZZ_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 |
zz_line, |
1107 |
yytext, |
1108 |
ZZ_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()), zz_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()), zz_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 |
zz_line); |
1150 |
} |