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