diff options
-rwxr-xr-x | LuaSL/build.sh | 15 | ||||
-rw-r--r-- | LuaSL/src/ANSI_C.l | 182 | ||||
-rw-r--r-- | LuaSL/src/ANSI_C.y | 471 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_LSL_tree.c | 246 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_LSL_tree.h | 47 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_lemon_yaccer.y | 103 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_lexer.l | 4 | ||||
-rw-r--r-- | LuaSL/src/btyacc-c.ske | 939 | ||||
-rw-r--r-- | LuaSL/src/fonts/Vera.ttf | bin | 65932 -> 0 bytes | |||
-rw-r--r-- | LuaSL/src/lemon.c | 4898 | ||||
-rw-r--r-- | LuaSL/src/lempar.c | 850 | ||||
-rw-r--r-- | LuaSL/test.lsl | 7 |
12 files changed, 6036 insertions, 1726 deletions
diff --git a/LuaSL/build.sh b/LuaSL/build.sh index 4a026bb..3b6c64c 100755 --- a/LuaSL/build.sh +++ b/LuaSL/build.sh | |||
@@ -51,7 +51,7 @@ names="LuaSL_main LuaSL_compile LuaSL_utilities" | |||
51 | 51 | ||
52 | EDJE_FLAGS="-id images -fd fonts" | 52 | EDJE_FLAGS="-id images -fd fonts" |
53 | 53 | ||
54 | rm -f ../LuaSL ../LuaSL_parser ../*.o *.output *.backup ../*.edj LuaSL_lexer.h LuaSL_lexer.c LuaSL_yaccer.h LuaSL_yaccer.tab.c | 54 | rm -f ../LuaSL ../LuaSL_parser ../*.o *.output *.backup ../*.edj LuaSL_lexer.h LuaSL_lexer.c LuaSL_lemon_yaccer.h LuaSL_lemon_yaccer.c LuaSL_lemon_yaccer.out |
55 | command="edje_cc $EDJE_FLAGS LuaSL.edc ../LuaSL.edj" | 55 | command="edje_cc $EDJE_FLAGS LuaSL.edc ../LuaSL.edj" |
56 | echo $command | 56 | echo $command |
57 | $command | 57 | $command |
@@ -71,27 +71,20 @@ $command | |||
71 | 71 | ||
72 | 72 | ||
73 | 73 | ||
74 | names="LuaSL_LSL_tree LuaSL_lexer LuaSL_yaccer.tab" | 74 | names="LuaSL_LSL_tree LuaSL_lexer LuaSL_lemon_yaccer" |
75 | 75 | ||
76 | LFLAGS="-d" | 76 | LFLAGS="-d" |
77 | 77 | ||
78 | # Hmmm, we have a circular dependencie with the include fiels each of flex and btyacc generate. So run btyacc twice. | 78 | # Hmmm, we have a circular dependencie with the include fiels each of flex and btyacc generate. So run lemon twice? |
79 | |||
80 | # I want to remove -d, coz I want an enum, not a bunch of #defines, but btyacc creates #defines internally anyway. sigh | ||
81 | command="btyacc -d -t -v -b LuaSL_yaccer -S btyacc-c.ske LuaSL_yaccer.y" | ||
82 | echo $command | ||
83 | $command | ||
84 | 79 | ||
85 | command="flex -C --outfile=LuaSL_lexer.c --header-file=LuaSL_lexer.h LuaSL_lexer.l" | 80 | command="flex -C --outfile=LuaSL_lexer.c --header-file=LuaSL_lexer.h LuaSL_lexer.l" |
86 | echo $command | 81 | echo $command |
87 | $command | 82 | $command |
88 | 83 | ||
89 | # I want to remove -d, coz I want an enum, not a bunch of #defines, but btyacc creates #defines internally anyway. sigh | 84 | command="lemon -s LuaSL_lemon_yaccer.y" |
90 | command="btyacc -d -t -v -b LuaSL_yaccer -S btyacc-c.ske LuaSL_yaccer.y" | ||
91 | echo $command | 85 | echo $command |
92 | $command | 86 | $command |
93 | 87 | ||
94 | |||
95 | objects="" | 88 | objects="" |
96 | for i in $names | 89 | for i in $names |
97 | do | 90 | do |
diff --git a/LuaSL/src/ANSI_C.l b/LuaSL/src/ANSI_C.l deleted file mode 100644 index 8a6b435..0000000 --- a/LuaSL/src/ANSI_C.l +++ /dev/null | |||
@@ -1,182 +0,0 @@ | |||
1 | D [0-9] | ||
2 | L [a-zA-Z_] | ||
3 | H [a-fA-F0-9] | ||
4 | E [Ee][+-]?{D}+ | ||
5 | P [Pp][+-]?{D}+ | ||
6 | FS (f|F|l|L) | ||
7 | IS ((u|U)|(u|U)?(l|L|ll|LL)|(l|L|ll|LL)(u|U)) | ||
8 | |||
9 | %{ | ||
10 | #include <stdio.h> | ||
11 | #include "y.tab.h" | ||
12 | |||
13 | void count(void); | ||
14 | %} | ||
15 | |||
16 | %% | ||
17 | "/*" { comment(); } | ||
18 | "//"[^\n]* { /* consume //-comment */ } | ||
19 | |||
20 | |||
21 | "auto" { count(); return(AUTO); } | ||
22 | "_Bool" { count(); return(BOOL); } | ||
23 | "break" { count(); return(BREAK); } | ||
24 | "case" { count(); return(CASE); } | ||
25 | "char" { count(); return(CHAR); } | ||
26 | "_Complex" { count(); return(COMPLEX); } | ||
27 | "const" { count(); return(CONST); } | ||
28 | "continue" { count(); return(CONTINUE); } | ||
29 | "default" { count(); return(DEFAULT); } | ||
30 | "do" { count(); return(DO); } | ||
31 | "double" { count(); return(DOUBLE); } | ||
32 | "else" { count(); return(ELSE); } | ||
33 | "enum" { count(); return(ENUM); } | ||
34 | "extern" { count(); return(EXTERN); } | ||
35 | "float" { count(); return(FLOAT); } | ||
36 | "for" { count(); return(FOR); } | ||
37 | "goto" { count(); return(GOTO); } | ||
38 | "if" { count(); return(IF); } | ||
39 | "_Imaginary" { count(); return(IMAGINARY); } | ||
40 | "inline" { count(); return(INLINE); } | ||
41 | "int" { count(); return(INT); } | ||
42 | "long" { count(); return(LONG); } | ||
43 | "register" { count(); return(REGISTER); } | ||
44 | "restrict" { count(); return(RESTRICT); } | ||
45 | "return" { count(); return(RETURN); } | ||
46 | "short" { count(); return(SHORT); } | ||
47 | "signed" { count(); return(SIGNED); } | ||
48 | "sizeof" { count(); return(SIZEOF); } | ||
49 | "static" { count(); return(STATIC); } | ||
50 | "struct" { count(); return(STRUCT); } | ||
51 | "switch" { count(); return(SWITCH); } | ||
52 | "typedef" { count(); return(TYPEDEF); } | ||
53 | "union" { count(); return(UNION); } | ||
54 | "unsigned" { count(); return(UNSIGNED); } | ||
55 | "void" { count(); return(VOID); } | ||
56 | "volatile" { count(); return(VOLATILE); } | ||
57 | "while" { count(); return(WHILE); } | ||
58 | |||
59 | {L}({L}|{D})* { count(); return(check_type()); } | ||
60 | |||
61 | 0[xX]{H}+{IS}? { count(); return(CONSTANT); } | ||
62 | 0{D}+{IS}? { count(); return(CONSTANT); } | ||
63 | {D}+{IS}? { count(); return(CONSTANT); } | ||
64 | L?'(\\.|[^\\'\n])+' { count(); return(CONSTANT); } | ||
65 | |||
66 | {D}+{E}{FS}? { count(); return(CONSTANT); } | ||
67 | {D}*"."{D}+({E})?{FS}? { count(); return(CONSTANT); } | ||
68 | {D}+"."{D}*({E})?{FS}? { count(); return(CONSTANT); } | ||
69 | 0[xX]{H}+{P}{FS}? { count(); return(CONSTANT); } | ||
70 | 0[xX]{H}*"."{H}+({P})?{FS}? { count(); return(CONSTANT); } | ||
71 | 0[xX]{H}+"."{H}*({P})?{FS}? { count(); return(CONSTANT); } | ||
72 | |||
73 | |||
74 | L?\"(\\.|[^\\"\n])*\" { count(); return(STRING_LITERAL); } | ||
75 | |||
76 | "..." { count(); return(ELLIPSIS); } | ||
77 | ">>=" { count(); return(RIGHT_ASSIGN); } | ||
78 | "<<=" { count(); return(LEFT_ASSIGN); } | ||
79 | "+=" { count(); return(ADD_ASSIGN); } | ||
80 | "-=" { count(); return(SUB_ASSIGN); } | ||
81 | "*=" { count(); return(MUL_ASSIGN); } | ||
82 | "/=" { count(); return(DIV_ASSIGN); } | ||
83 | "%=" { count(); return(MOD_ASSIGN); } | ||
84 | "&=" { count(); return(AND_ASSIGN); } | ||
85 | "^=" { count(); return(XOR_ASSIGN); } | ||
86 | "|=" { count(); return(OR_ASSIGN); } | ||
87 | ">>" { count(); return(RIGHT_OP); } | ||
88 | "<<" { count(); return(LEFT_OP); } | ||
89 | "++" { count(); return(INC_OP); } | ||
90 | "--" { count(); return(DEC_OP); } | ||
91 | "->" { count(); return(PTR_OP); } | ||
92 | "&&" { count(); return(AND_OP); } | ||
93 | "||" { count(); return(OR_OP); } | ||
94 | "<=" { count(); return(LE_OP); } | ||
95 | ">=" { count(); return(GE_OP); } | ||
96 | "==" { count(); return(EQ_OP); } | ||
97 | "!=" { count(); return(NE_OP); } | ||
98 | ";" { count(); return(';'); } | ||
99 | ("{"|"<%") { count(); return('{'); } | ||
100 | ("}"|"%>") { count(); return('}'); } | ||
101 | "," { count(); return(','); } | ||
102 | ":" { count(); return(':'); } | ||
103 | "=" { count(); return('='); } | ||
104 | "(" { count(); return('('); } | ||
105 | ")" { count(); return(')'); } | ||
106 | ("["|"<:") { count(); return('['); } | ||
107 | ("]"|":>") { count(); return(']'); } | ||
108 | "." { count(); return('.'); } | ||
109 | "&" { count(); return('&'); } | ||
110 | "!" { count(); return('!'); } | ||
111 | "~" { count(); return('~'); } | ||
112 | "-" { count(); return('-'); } | ||
113 | "+" { count(); return('+'); } | ||
114 | "*" { count(); return('*'); } | ||
115 | "/" { count(); return('/'); } | ||
116 | "%" { count(); return('%'); } | ||
117 | "<" { count(); return('<'); } | ||
118 | ">" { count(); return('>'); } | ||
119 | "^" { count(); return('^'); } | ||
120 | "|" { count(); return('|'); } | ||
121 | "?" { count(); return('?'); } | ||
122 | |||
123 | [ \t\v\n\f] { count(); } | ||
124 | . { /* Add code to complain about unmatched characters */ } | ||
125 | |||
126 | %% | ||
127 | |||
128 | int yywrap(void) | ||
129 | { | ||
130 | return 1; | ||
131 | } | ||
132 | |||
133 | |||
134 | void comment(void) | ||
135 | { | ||
136 | char c, prev = 0; | ||
137 | |||
138 | while ((c = input()) != 0) /* (EOF maps to 0) */ | ||
139 | { | ||
140 | if (c == '/' && prev == '*') | ||
141 | return; | ||
142 | prev = c; | ||
143 | } | ||
144 | error("unterminated comment"); | ||
145 | } | ||
146 | |||
147 | |||
148 | int column = 0; | ||
149 | |||
150 | void count(void) | ||
151 | { | ||
152 | int i; | ||
153 | |||
154 | for (i = 0; yytext[i] != '\0'; i++) | ||
155 | if (yytext[i] == '\n') | ||
156 | column = 0; | ||
157 | else if (yytext[i] == '\t') | ||
158 | column += 8 - (column % 8); | ||
159 | else | ||
160 | column++; | ||
161 | |||
162 | ECHO; | ||
163 | } | ||
164 | |||
165 | |||
166 | int check_type(void) | ||
167 | { | ||
168 | /* | ||
169 | * pseudo code --- this is what it should check | ||
170 | * | ||
171 | * if (yytext == type_name) | ||
172 | * return TYPE_NAME; | ||
173 | * | ||
174 | * return IDENTIFIER; | ||
175 | */ | ||
176 | |||
177 | /* | ||
178 | * it actually will only return IDENTIFIER | ||
179 | */ | ||
180 | |||
181 | return IDENTIFIER; | ||
182 | } | ||
diff --git a/LuaSL/src/ANSI_C.y b/LuaSL/src/ANSI_C.y deleted file mode 100644 index 28e2ca2..0000000 --- a/LuaSL/src/ANSI_C.y +++ /dev/null | |||
@@ -1,471 +0,0 @@ | |||
1 | %token IDENTIFIER CONSTANT STRING_LITERAL SIZEOF | ||
2 | %token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP | ||
3 | %token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN | ||
4 | %token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN | ||
5 | %token XOR_ASSIGN OR_ASSIGN TYPE_NAME | ||
6 | |||
7 | %token TYPEDEF EXTERN STATIC AUTO REGISTER INLINE RESTRICT | ||
8 | %token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID | ||
9 | %token BOOL COMPLEX IMAGINARY | ||
10 | %token STRUCT UNION ENUM ELLIPSIS | ||
11 | |||
12 | %token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN | ||
13 | |||
14 | %start translation_unit | ||
15 | %% | ||
16 | |||
17 | primary_expression | ||
18 | : IDENTIFIER | ||
19 | | CONSTANT | ||
20 | | STRING_LITERAL | ||
21 | | '(' expression ')' | ||
22 | ; | ||
23 | |||
24 | postfix_expression | ||
25 | : primary_expression | ||
26 | | postfix_expression '[' expression ']' | ||
27 | | postfix_expression '(' ')' | ||
28 | | postfix_expression '(' argument_expression_list ')' | ||
29 | | postfix_expression '.' IDENTIFIER | ||
30 | | postfix_expression PTR_OP IDENTIFIER | ||
31 | | postfix_expression INC_OP | ||
32 | | postfix_expression DEC_OP | ||
33 | | '(' type_name ')' '{' initializer_list '}' | ||
34 | | '(' type_name ')' '{' initializer_list ',' '}' | ||
35 | ; | ||
36 | |||
37 | argument_expression_list | ||
38 | : assignment_expression | ||
39 | | argument_expression_list ',' assignment_expression | ||
40 | ; | ||
41 | |||
42 | unary_expression | ||
43 | : postfix_expression | ||
44 | | INC_OP unary_expression | ||
45 | | DEC_OP unary_expression | ||
46 | | unary_operator cast_expression | ||
47 | | SIZEOF unary_expression | ||
48 | | SIZEOF '(' type_name ')' | ||
49 | ; | ||
50 | |||
51 | unary_operator | ||
52 | : '&' | ||
53 | | '*' | ||
54 | | '+' | ||
55 | | '-' | ||
56 | | '~' | ||
57 | | '!' | ||
58 | ; | ||
59 | |||
60 | cast_expression | ||
61 | : unary_expression | ||
62 | | '(' type_name ')' cast_expression | ||
63 | ; | ||
64 | |||
65 | multiplicative_expression | ||
66 | : cast_expression | ||
67 | | multiplicative_expression '*' cast_expression | ||
68 | | multiplicative_expression '/' cast_expression | ||
69 | | multiplicative_expression '%' cast_expression | ||
70 | ; | ||
71 | |||
72 | additive_expression | ||
73 | : multiplicative_expression | ||
74 | | additive_expression '+' multiplicative_expression | ||
75 | | additive_expression '-' multiplicative_expression | ||
76 | ; | ||
77 | |||
78 | shift_expression | ||
79 | : additive_expression | ||
80 | | shift_expression LEFT_OP additive_expression | ||
81 | | shift_expression RIGHT_OP additive_expression | ||
82 | ; | ||
83 | |||
84 | relational_expression | ||
85 | : shift_expression | ||
86 | | relational_expression '<' shift_expression | ||
87 | | relational_expression '>' shift_expression | ||
88 | | relational_expression LE_OP shift_expression | ||
89 | | relational_expression GE_OP shift_expression | ||
90 | ; | ||
91 | |||
92 | equality_expression | ||
93 | : relational_expression | ||
94 | | equality_expression EQ_OP relational_expression | ||
95 | | equality_expression NE_OP relational_expression | ||
96 | ; | ||
97 | |||
98 | and_expression | ||
99 | : equality_expression | ||
100 | | and_expression '&' equality_expression | ||
101 | ; | ||
102 | |||
103 | exclusive_or_expression | ||
104 | : and_expression | ||
105 | | exclusive_or_expression '^' and_expression | ||
106 | ; | ||
107 | |||
108 | inclusive_or_expression | ||
109 | : exclusive_or_expression | ||
110 | | inclusive_or_expression '|' exclusive_or_expression | ||
111 | ; | ||
112 | |||
113 | logical_and_expression | ||
114 | : inclusive_or_expression | ||
115 | | logical_and_expression AND_OP inclusive_or_expression | ||
116 | ; | ||
117 | |||
118 | logical_or_expression | ||
119 | : logical_and_expression | ||
120 | | logical_or_expression OR_OP logical_and_expression | ||
121 | ; | ||
122 | |||
123 | conditional_expression | ||
124 | : logical_or_expression | ||
125 | | logical_or_expression '?' expression ':' conditional_expression | ||
126 | ; | ||
127 | |||
128 | assignment_expression | ||
129 | : conditional_expression | ||
130 | | unary_expression assignment_operator assignment_expression | ||
131 | ; | ||
132 | |||
133 | assignment_operator | ||
134 | : '=' | ||
135 | | MUL_ASSIGN | ||
136 | | DIV_ASSIGN | ||
137 | | MOD_ASSIGN | ||
138 | | ADD_ASSIGN | ||
139 | | SUB_ASSIGN | ||
140 | | LEFT_ASSIGN | ||
141 | | RIGHT_ASSIGN | ||
142 | | AND_ASSIGN | ||
143 | | XOR_ASSIGN | ||
144 | | OR_ASSIGN | ||
145 | ; | ||
146 | |||
147 | expression | ||
148 | : assignment_expression | ||
149 | | expression ',' assignment_expression | ||
150 | ; | ||
151 | |||
152 | constant_expression | ||
153 | : conditional_expression | ||
154 | ; | ||
155 | |||
156 | declaration | ||
157 | : declaration_specifiers ';' | ||
158 | | declaration_specifiers init_declarator_list ';' | ||
159 | ; | ||
160 | |||
161 | declaration_specifiers | ||
162 | : storage_class_specifier | ||
163 | | storage_class_specifier declaration_specifiers | ||
164 | | type_specifier | ||
165 | | type_specifier declaration_specifiers | ||
166 | | type_qualifier | ||
167 | | type_qualifier declaration_specifiers | ||
168 | | function_specifier | ||
169 | | function_specifier declaration_specifiers | ||
170 | ; | ||
171 | |||
172 | init_declarator_list | ||
173 | : init_declarator | ||
174 | | init_declarator_list ',' init_declarator | ||
175 | ; | ||
176 | |||
177 | init_declarator | ||
178 | : declarator | ||
179 | | declarator '=' initializer | ||
180 | ; | ||
181 | |||
182 | storage_class_specifier | ||
183 | : TYPEDEF | ||
184 | | EXTERN | ||
185 | | STATIC | ||
186 | | AUTO | ||
187 | | REGISTER | ||
188 | ; | ||
189 | |||
190 | type_specifier | ||
191 | : VOID | ||
192 | | CHAR | ||
193 | | SHORT | ||
194 | | INT | ||
195 | | LONG | ||
196 | | FLOAT | ||
197 | | DOUBLE | ||
198 | | SIGNED | ||
199 | | UNSIGNED | ||
200 | | BOOL | ||
201 | | COMPLEX | ||
202 | | IMAGINARY | ||
203 | | struct_or_union_specifier | ||
204 | | enum_specifier | ||
205 | | TYPE_NAME | ||
206 | ; | ||
207 | |||
208 | struct_or_union_specifier | ||
209 | : struct_or_union IDENTIFIER '{' struct_declaration_list '}' | ||
210 | | struct_or_union '{' struct_declaration_list '}' | ||
211 | | struct_or_union IDENTIFIER | ||
212 | ; | ||
213 | |||
214 | struct_or_union | ||
215 | : STRUCT | ||
216 | | UNION | ||
217 | ; | ||
218 | |||
219 | struct_declaration_list | ||
220 | : struct_declaration | ||
221 | | struct_declaration_list struct_declaration | ||
222 | ; | ||
223 | |||
224 | struct_declaration | ||
225 | : specifier_qualifier_list struct_declarator_list ';' | ||
226 | ; | ||
227 | |||
228 | specifier_qualifier_list | ||
229 | : type_specifier specifier_qualifier_list | ||
230 | | type_specifier | ||
231 | | type_qualifier specifier_qualifier_list | ||
232 | | type_qualifier | ||
233 | ; | ||
234 | |||
235 | struct_declarator_list | ||
236 | : struct_declarator | ||
237 | | struct_declarator_list ',' struct_declarator | ||
238 | ; | ||
239 | |||
240 | struct_declarator | ||
241 | : declarator | ||
242 | | ':' constant_expression | ||
243 | | declarator ':' constant_expression | ||
244 | ; | ||
245 | |||
246 | enum_specifier | ||
247 | : ENUM '{' enumerator_list '}' | ||
248 | | ENUM IDENTIFIER '{' enumerator_list '}' | ||
249 | | ENUM '{' enumerator_list ',' '}' | ||
250 | | ENUM IDENTIFIER '{' enumerator_list ',' '}' | ||
251 | | ENUM IDENTIFIER | ||
252 | ; | ||
253 | |||
254 | enumerator_list | ||
255 | : enumerator | ||
256 | | enumerator_list ',' enumerator | ||
257 | ; | ||
258 | |||
259 | enumerator | ||
260 | : IDENTIFIER | ||
261 | | IDENTIFIER '=' constant_expression | ||
262 | ; | ||
263 | |||
264 | type_qualifier | ||
265 | : CONST | ||
266 | | RESTRICT | ||
267 | | VOLATILE | ||
268 | ; | ||
269 | |||
270 | function_specifier | ||
271 | : INLINE | ||
272 | ; | ||
273 | |||
274 | declarator | ||
275 | : pointer direct_declarator | ||
276 | | direct_declarator | ||
277 | ; | ||
278 | |||
279 | |||
280 | direct_declarator | ||
281 | : IDENTIFIER | ||
282 | | '(' declarator ')' | ||
283 | | direct_declarator '[' type_qualifier_list assignment_expression ']' | ||
284 | | direct_declarator '[' type_qualifier_list ']' | ||
285 | | direct_declarator '[' assignment_expression ']' | ||
286 | | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' | ||
287 | | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' | ||
288 | | direct_declarator '[' type_qualifier_list '*' ']' | ||
289 | | direct_declarator '[' '*' ']' | ||
290 | | direct_declarator '[' ']' | ||
291 | | direct_declarator '(' parameter_type_list ')' | ||
292 | | direct_declarator '(' identifier_list ')' | ||
293 | | direct_declarator '(' ')' | ||
294 | ; | ||
295 | |||
296 | pointer | ||
297 | : '*' | ||
298 | | '*' type_qualifier_list | ||
299 | | '*' pointer | ||
300 | | '*' type_qualifier_list pointer | ||
301 | ; | ||
302 | |||
303 | type_qualifier_list | ||
304 | : type_qualifier | ||
305 | | type_qualifier_list type_qualifier | ||
306 | ; | ||
307 | |||
308 | |||
309 | parameter_type_list | ||
310 | : parameter_list | ||
311 | | parameter_list ',' ELLIPSIS | ||
312 | ; | ||
313 | |||
314 | parameter_list | ||
315 | : parameter_declaration | ||
316 | | parameter_list ',' parameter_declaration | ||
317 | ; | ||
318 | |||
319 | parameter_declaration | ||
320 | : declaration_specifiers declarator | ||
321 | | declaration_specifiers abstract_declarator | ||
322 | | declaration_specifiers | ||
323 | ; | ||
324 | |||
325 | identifier_list | ||
326 | : IDENTIFIER | ||
327 | | identifier_list ',' IDENTIFIER | ||
328 | ; | ||
329 | |||
330 | type_name | ||
331 | : specifier_qualifier_list | ||
332 | | specifier_qualifier_list abstract_declarator | ||
333 | ; | ||
334 | |||
335 | abstract_declarator | ||
336 | : pointer | ||
337 | | direct_abstract_declarator | ||
338 | | pointer direct_abstract_declarator | ||
339 | ; | ||
340 | |||
341 | direct_abstract_declarator | ||
342 | : '(' abstract_declarator ')' | ||
343 | | '[' ']' | ||
344 | | '[' assignment_expression ']' | ||
345 | | direct_abstract_declarator '[' ']' | ||
346 | | direct_abstract_declarator '[' assignment_expression ']' | ||
347 | | '[' '*' ']' | ||
348 | | direct_abstract_declarator '[' '*' ']' | ||
349 | | '(' ')' | ||
350 | | '(' parameter_type_list ')' | ||
351 | | direct_abstract_declarator '(' ')' | ||
352 | | direct_abstract_declarator '(' parameter_type_list ')' | ||
353 | ; | ||
354 | |||
355 | initializer | ||
356 | : assignment_expression | ||
357 | | '{' initializer_list '}' | ||
358 | | '{' initializer_list ',' '}' | ||
359 | ; | ||
360 | |||
361 | initializer_list | ||
362 | : initializer | ||
363 | | designation initializer | ||
364 | | initializer_list ',' initializer | ||
365 | | initializer_list ',' designation initializer | ||
366 | ; | ||
367 | |||
368 | designation | ||
369 | : designator_list '=' | ||
370 | ; | ||
371 | |||
372 | designator_list | ||
373 | : designator | ||
374 | | designator_list designator | ||
375 | ; | ||
376 | |||
377 | designator | ||
378 | : '[' constant_expression ']' | ||
379 | | '.' IDENTIFIER | ||
380 | ; | ||
381 | |||
382 | statement | ||
383 | : labeled_statement | ||
384 | | compound_statement | ||
385 | | expression_statement | ||
386 | | selection_statement | ||
387 | | iteration_statement | ||
388 | | jump_statement | ||
389 | ; | ||
390 | |||
391 | labeled_statement | ||
392 | : IDENTIFIER ':' statement | ||
393 | | CASE constant_expression ':' statement | ||
394 | | DEFAULT ':' statement | ||
395 | ; | ||
396 | |||
397 | compound_statement | ||
398 | : '{' '}' | ||
399 | | '{' block_item_list '}' | ||
400 | ; | ||
401 | |||
402 | block_item_list | ||
403 | : block_item | ||
404 | | block_item_list block_item | ||
405 | ; | ||
406 | |||
407 | block_item | ||
408 | : declaration | ||
409 | | statement | ||
410 | ; | ||
411 | |||
412 | expression_statement | ||
413 | : ';' | ||
414 | | expression ';' | ||
415 | ; | ||
416 | |||
417 | selection_statement | ||
418 | : IF '(' expression ')' statement | ||
419 | | IF '(' expression ')' statement ELSE statement | ||
420 | | SWITCH '(' expression ')' statement | ||
421 | ; | ||
422 | |||
423 | iteration_statement | ||
424 | : WHILE '(' expression ')' statement | ||
425 | | DO statement WHILE '(' expression ')' ';' | ||
426 | | FOR '(' expression_statement expression_statement ')' statement | ||
427 | | FOR '(' expression_statement expression_statement expression ')' statement | ||
428 | | FOR '(' declaration expression_statement ')' statement | ||
429 | | FOR '(' declaration expression_statement expression ')' statement | ||
430 | ; | ||
431 | |||
432 | jump_statement | ||
433 | : GOTO IDENTIFIER ';' | ||
434 | | CONTINUE ';' | ||
435 | | BREAK ';' | ||
436 | | RETURN ';' | ||
437 | | RETURN expression ';' | ||
438 | ; | ||
439 | |||
440 | translation_unit | ||
441 | : external_declaration | ||
442 | | translation_unit external_declaration | ||
443 | ; | ||
444 | |||
445 | external_declaration | ||
446 | : function_definition | ||
447 | | declaration | ||
448 | ; | ||
449 | |||
450 | function_definition | ||
451 | : declaration_specifiers declarator declaration_list compound_statement | ||
452 | | declaration_specifiers declarator compound_statement | ||
453 | ; | ||
454 | |||
455 | declaration_list | ||
456 | : declaration | ||
457 | | declaration_list declaration | ||
458 | ; | ||
459 | |||
460 | |||
461 | %% | ||
462 | #include <stdio.h> | ||
463 | |||
464 | extern char yytext[]; | ||
465 | extern int column; | ||
466 | |||
467 | void yyerror(char const *s) | ||
468 | { | ||
469 | fflush(stdout); | ||
470 | printf("\n%*s\n%*s\n", column, "^", column, s); | ||
471 | } | ||
diff --git a/LuaSL/src/LuaSL_LSL_tree.c b/LuaSL/src/LuaSL_LSL_tree.c index 3728054..a0c07f0 100644 --- a/LuaSL/src/LuaSL_LSL_tree.c +++ b/LuaSL/src/LuaSL_LSL_tree.c | |||
@@ -6,9 +6,10 @@ | |||
6 | static void evaluateIntegerToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); | 6 | static void evaluateIntegerToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); |
7 | static void evaluateNoToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); | 7 | static void evaluateNoToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); |
8 | static void evaluateOperationToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); | 8 | static void evaluateOperationToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); |
9 | static void eveluateParenthesisToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); | ||
9 | static void evaluateStatementToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); | 10 | static void evaluateStatementToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right); |
10 | static void outputIntegerToken(LSL_Leaf *content); | 11 | static void outputIntegerToken(LSL_Leaf *content); |
11 | static void outputOperationToken(LSL_Leaf *content); | 12 | static void outputParenthesisToken(LSL_Leaf *content); |
12 | static void outputStatementToken(LSL_Leaf *content); | 13 | static void outputStatementToken(LSL_Leaf *content); |
13 | static void outputSpaceToken(LSL_Leaf *content); | 14 | static void outputSpaceToken(LSL_Leaf *content); |
14 | 15 | ||
@@ -22,54 +23,54 @@ LSL_Token LSL_Tokens[] = | |||
22 | // Left to right, unless oterwise stated. | 23 | // Left to right, unless oterwise stated. |
23 | // According to http://wiki.secondlife.com/wiki/Category:LSL_Operators | 24 | // According to http://wiki.secondlife.com/wiki/Category:LSL_Operators |
24 | 25 | ||
25 | {LSL_BOOL_AND, "&&", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 26 | {LSL_BOOL_AND, "&&", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
26 | // QUIRK - Seems to be some disagreement about BOOL_AND/BOOL_OR precedence. Either they are equal, or OR is higher. | 27 | // QUIRK - Seems to be some disagreement about BOOL_AND/BOOL_OR precedence. Either they are equal, or OR is higher. |
27 | // QUIRK - No boolean short circuiting. | 28 | // QUIRK - No boolean short circuiting. |
28 | {LSL_BOOL_OR, "||", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 29 | {LSL_BOOL_OR, "||", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
29 | {LSL_BIT_OR, "|", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 30 | {LSL_BIT_OR, "|", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
30 | {LSL_BIT_XOR, "^", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 31 | {LSL_BIT_XOR, "^", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
31 | {LSL_BIT_AND, "&", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 32 | {LSL_BIT_AND, "&", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
32 | // QUIRK - Conditionals are executed right to left. Or left to right, depending on who you ask. lol | 33 | // QUIRK - Conditionals are executed right to left. Or left to right, depending on who you ask. lol |
33 | {LSL_NOT_EQUAL, "!=", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 34 | {LSL_NOT_EQUAL, "!=", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
34 | {LSL_EQUAL, "==", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 35 | {LSL_EQUAL, "==", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
35 | {LSL_GREATER_EQUAL, ">=", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 36 | {LSL_GREATER_EQUAL, ">=", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
36 | {LSL_LESS_EQUAL, "<=", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 37 | {LSL_LESS_EQUAL, "<=", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
37 | {LSL_GREATER_THAN, ">", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 38 | {LSL_GREATER_THAN, ">", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
38 | {LSL_LESS_THAN, "<", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 39 | {LSL_LESS_THAN, "<", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
39 | {LSL_RIGHT_SHIFT, ">>", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 40 | {LSL_RIGHT_SHIFT, ">>", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
40 | {LSL_LEFT_SHIFT, "<<", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 41 | {LSL_LEFT_SHIFT, "<<", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
41 | // {LSL_CONCATENATE, "+", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 42 | // {LSL_CONCATENATE, "+", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
42 | {LSL_ADD, "+", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 43 | {LSL_ADD, "+", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
43 | {LSL_SUBTRACT, "-", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 44 | {LSL_SUBTRACT, "-", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
44 | // {LSL_CROSS_PRODUCT, "%", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 45 | // {LSL_CROSS_PRODUCT, "%", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
45 | // {LSL_DOT_PRODUCT, "*", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 46 | // {LSL_DOT_PRODUCT, "*", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
46 | {LSL_MULTIPLY, "*", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 47 | {LSL_MULTIPLY, "*", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
47 | {LSL_MODULO, "%", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 48 | {LSL_MODULO, "%", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
48 | {LSL_DIVIDE, "/", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 49 | {LSL_DIVIDE, "/", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
49 | {LSL_NEGATION, "-", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 50 | {LSL_NEGATION, "-", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
50 | {LSL_BOOL_NOT, "!", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 51 | {LSL_BOOL_NOT, "!", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
51 | {LSL_BIT_NOT, "~", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 52 | {LSL_BIT_NOT, "~", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
52 | // {LSL_TYPECAST_CLOSE, ")", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 53 | // {LSL_TYPECAST_CLOSE, ")", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
53 | // {LSL_TYPECAST_OPEN, "(", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 54 | // {LSL_TYPECAST_OPEN, "(", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
54 | {LSL_ANGLE_CLOSE, ">", LSL_LEFT2RIGHT | LSL_CREATION, outputOperationToken, NULL, evaluateOperationToken}, | 55 | {LSL_ANGLE_CLOSE, ">", LSL_LEFT2RIGHT | LSL_CREATION, NULL, NULL, evaluateOperationToken}, |
55 | {LSL_ANGLE_OPEN, "<", LSL_LEFT2RIGHT | LSL_CREATION, outputOperationToken, NULL, evaluateOperationToken}, | 56 | {LSL_ANGLE_OPEN, "<", LSL_LEFT2RIGHT | LSL_CREATION, NULL, NULL, evaluateOperationToken}, |
56 | {LSL_BRACKET_CLOSE, "]", LSL_INNER2OUTER | LSL_CREATION, outputOperationToken, NULL, evaluateOperationToken}, | 57 | {LSL_BRACKET_CLOSE, "]", LSL_INNER2OUTER | LSL_CREATION, NULL, NULL, evaluateOperationToken}, |
57 | {LSL_BRACKET_OPEN, "[", LSL_INNER2OUTER | LSL_CREATION, outputOperationToken, NULL, evaluateOperationToken}, | 58 | {LSL_BRACKET_OPEN, "[", LSL_INNER2OUTER | LSL_CREATION, NULL, NULL, evaluateOperationToken}, |
58 | {LSL_PARENTHESIS_CLOSE, ")", LSL_INNER2OUTER, NULL, NULL, evaluateNoToken}, | 59 | {LSL_PARENTHESIS_CLOSE, ")", LSL_INNER2OUTER, NULL, NULL, evaluateNoToken}, |
59 | {LSL_PARENTHESIS_OPEN, "(", LSL_INNER2OUTER, NULL, NULL, NULL}, | 60 | {LSL_PARENTHESIS_OPEN, "(", LSL_INNER2OUTER, outputParenthesisToken, NULL, eveluateParenthesisToken}, |
60 | // {LSL_ASSIGNMENT_CONCATENATE, "+=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, outputOperationToken, NULL, evaluateOperationToken}, | 61 | // {LSL_ASSIGNMENT_CONCATENATE, "+=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL, NULL, evaluateOperationToken}, |
61 | {LSL_ASSIGNMENT_ADD, "+=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, outputOperationToken, NULL, evaluateOperationToken}, | 62 | {LSL_ASSIGNMENT_ADD, "+=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL, NULL, evaluateOperationToken}, |
62 | {LSL_ASSIGNMENT_SUBTRACT, "-=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, outputOperationToken, NULL, evaluateOperationToken}, | 63 | {LSL_ASSIGNMENT_SUBTRACT, "-=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL, NULL, evaluateOperationToken}, |
63 | {LSL_ASSIGNMENT_MULTIPLY, "*=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, outputOperationToken, NULL, evaluateOperationToken}, | 64 | {LSL_ASSIGNMENT_MULTIPLY, "*=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL, NULL, evaluateOperationToken}, |
64 | {LSL_ASSIGNMENT_MODULO, "%=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, outputOperationToken, NULL, evaluateOperationToken}, | 65 | {LSL_ASSIGNMENT_MODULO, "%=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL, NULL, evaluateOperationToken}, |
65 | {LSL_ASSIGNMENT_DIVIDE, "/=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, outputOperationToken, NULL, evaluateOperationToken}, | 66 | {LSL_ASSIGNMENT_DIVIDE, "/=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL, NULL, evaluateOperationToken}, |
66 | {LSL_ASSIGNMENT_PLAIN, "=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, outputOperationToken, NULL, evaluateOperationToken}, | 67 | {LSL_ASSIGNMENT_PLAIN, "=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL, NULL, evaluateOperationToken}, |
67 | {LSL_DOT, ".", LSL_RIGHT2LEFT, outputOperationToken, NULL, evaluateOperationToken}, | 68 | {LSL_DOT, ".", LSL_RIGHT2LEFT, NULL, NULL, evaluateOperationToken}, |
68 | // {LSL_DECREMENT_POST, "--", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 69 | // {LSL_DECREMENT_POST, "--", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
69 | {LSL_DECREMENT_PRE, "--", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 70 | {LSL_DECREMENT_PRE, "--", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
70 | // {LSL_INCREMENT_POST, "++", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 71 | // {LSL_INCREMENT_POST, "++", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
71 | {LSL_INCREMENT_PRE, "++", LSL_RIGHT2LEFT | LSL_UNARY, outputOperationToken, NULL, evaluateOperationToken}, | 72 | {LSL_INCREMENT_PRE, "++", LSL_RIGHT2LEFT | LSL_UNARY, NULL, NULL, evaluateOperationToken}, |
72 | {LSL_COMMA, ",", LSL_LEFT2RIGHT, outputOperationToken, NULL, evaluateOperationToken}, | 73 | {LSL_COMMA, ",", LSL_LEFT2RIGHT, NULL, NULL, evaluateOperationToken}, |
73 | 74 | ||
74 | {LSL_EXPRESSION, "expression", LSL_NONE, NULL, NULL, NULL}, | 75 | {LSL_EXPRESSION, "expression", LSL_NONE, NULL, NULL, NULL}, |
75 | 76 | ||
@@ -108,14 +109,14 @@ LSL_Token LSL_Tokens[] = | |||
108 | {LSL_RETURN, "return", LSL_NONE, NULL, NULL, NULL}, | 109 | {LSL_RETURN, "return", LSL_NONE, NULL, NULL, NULL}, |
109 | {LSL_STATE_CHANGE, "state", LSL_NONE, NULL, NULL, NULL}, | 110 | {LSL_STATE_CHANGE, "state", LSL_NONE, NULL, NULL, NULL}, |
110 | {LSL_WHILE, "while", LSL_NONE, NULL, NULL, NULL}, | 111 | {LSL_WHILE, "while", LSL_NONE, NULL, NULL, NULL}, |
111 | {LSL_STATEMENT, ";", LSL_NONE, outputStatementToken, NULL, evaluateStatementToken}, | 112 | {LSL_STATEMENT, ";", LSL_NOIGNORE, outputStatementToken, NULL, evaluateStatementToken}, |
112 | 113 | ||
113 | {LSL_BLOCK_CLOSE, "}", LSL_NONE, NULL, NULL, NULL}, | 114 | {LSL_BLOCK_CLOSE, "}", LSL_NONE, NULL, NULL, NULL}, |
114 | {LSL_BLOCK_OPEN, "{", LSL_NONE, NULL, NULL, NULL}, | 115 | {LSL_BLOCK_OPEN, "{", LSL_NONE, NULL, NULL, NULL}, |
115 | // {LSL_PARAMETER, "parameter", LSL_NONE, NULL, NULL, NULL}, | 116 | // {LSL_PARAMETER, "parameter", LSL_NONE, NULL, NULL, NULL}, |
116 | // {LSL_FUNCTION, "function", LSL_NONE, NULL, NULL, NULL}, | 117 | // {LSL_FUNCTION, "function", LSL_NONE, NULL, NULL, NULL}, |
117 | // {LSL_STATE, "state", LSL_NONE, NULL, NULL, NULL}, | 118 | // {LSL_STATE, "state", LSL_NONE, NULL, NULL, NULL}, |
118 | // {LSL_SCRIPT, "script", LSL_NONE, NULL, NULL, NULL}, | 119 | {LSL_SCRIPT, "", LSL_NONE, NULL, NULL, NULL}, |
119 | 120 | ||
120 | {LSL_UNKNOWN, "unknown", LSL_NONE, NULL, NULL, NULL}, | 121 | {LSL_UNKNOWN, "unknown", LSL_NONE, NULL, NULL, NULL}, |
121 | 122 | ||
@@ -130,7 +131,7 @@ int lowestToken = 999999; | |||
130 | 131 | ||
131 | static LSL_Leaf *newLeaf(LSL_Type type, LSL_Leaf *left, LSL_Leaf *right) | 132 | static LSL_Leaf *newLeaf(LSL_Type type, LSL_Leaf *left, LSL_Leaf *right) |
132 | { | 133 | { |
133 | LSL_Leaf *leaf = malloc(sizeof(LSL_Leaf)); | 134 | LSL_Leaf *leaf = calloc(1, sizeof(LSL_Leaf)); |
134 | 135 | ||
135 | if (leaf) | 136 | if (leaf) |
136 | { | 137 | { |
@@ -142,7 +143,7 @@ static LSL_Leaf *newLeaf(LSL_Type type, LSL_Leaf *left, LSL_Leaf *right) | |||
142 | return leaf; | 143 | return leaf; |
143 | } | 144 | } |
144 | 145 | ||
145 | static void burnLeaf(LSL_Leaf *leaf) | 146 | void burnLeaf(LSL_Leaf *leaf) |
146 | { | 147 | { |
147 | if (leaf) | 148 | if (leaf) |
148 | { | 149 | { |
@@ -154,75 +155,56 @@ static void burnLeaf(LSL_Leaf *leaf) | |||
154 | } | 155 | } |
155 | } | 156 | } |
156 | 157 | ||
157 | static LSL_Leaf *cloneLeaf(LSL_Leaf *source) | ||
158 | { | ||
159 | LSL_Leaf *leaf = newLeaf(LSL_UNKNOWN, NULL, NULL); | ||
160 | |||
161 | if (leaf) | ||
162 | memcpy(leaf, source, sizeof(LSL_Leaf)); | ||
163 | |||
164 | return leaf; | ||
165 | } | ||
166 | |||
167 | LSL_Leaf *addInteger(LSL_Leaf *lval, int value) | ||
168 | { | ||
169 | return cloneLeaf(lval); | ||
170 | } | ||
171 | |||
172 | LSL_Leaf *addOperation(LSL_Leaf *lval, LSL_Type type, LSL_Leaf *left, LSL_Leaf *right) | 158 | LSL_Leaf *addOperation(LSL_Leaf *lval, LSL_Type type, LSL_Leaf *left, LSL_Leaf *right) |
173 | { | 159 | { |
174 | LSL_Leaf *leaf = newLeaf(type, left, right); | 160 | printf("******************************addOperation(%s, %d, , )\n", lval->token->token, type); |
175 | 161 | if (lval) | |
176 | if (leaf) | ||
177 | { | 162 | { |
163 | lval->left = left; | ||
164 | lval->right = right; | ||
178 | if (LSL_EXPRESSION == type) | 165 | if (LSL_EXPRESSION == type) |
179 | { | 166 | { |
180 | leaf->value.expressionValue = right; | 167 | lval->value.expressionValue = right; |
181 | leaf->left = NULL; | 168 | lval->left = NULL; |
182 | } | 169 | } |
183 | else | 170 | else |
184 | { | 171 | { |
185 | leaf->value.operationValue = type; | 172 | lval->value.operationValue = type; |
186 | leaf->ignorableText = lval->ignorableText; | ||
187 | } | 173 | } |
188 | } | 174 | } |
189 | 175 | ||
190 | return leaf; | 176 | return lval; |
191 | } | 177 | } |
192 | 178 | ||
193 | LSL_Leaf *addParenthesis(LSL_Leaf *lval, LSL_Leaf *expr) | 179 | LSL_Leaf *addParenthesis(LSL_Leaf *lval, LSL_Leaf *expr, LSL_Leaf *rval) |
194 | { | 180 | { |
195 | LSL_Leaf *leaf = newLeaf(LSL_PARENTHESIS_OPEN, NULL, expr); | 181 | LSL_Parenthesis *parens = malloc(sizeof(LSL_Parenthesis)); |
196 | 182 | ||
197 | if (leaf) | 183 | if (parens) |
198 | { | 184 | { |
199 | leaf->ignorableText = lval->ignorableText; | 185 | parens->left = lval; |
200 | leaf = newLeaf(LSL_PARENTHESIS_CLOSE, leaf, NULL); | 186 | parens->expression = expr; |
187 | parens->right = rval; | ||
188 | if (lval) | ||
189 | lval->value.parenthesis = parens; | ||
201 | } | 190 | } |
202 | 191 | return lval; | |
203 | return leaf; | ||
204 | } | 192 | } |
205 | 193 | ||
206 | LSL_Statement *createStatement(LSL_Type type, LSL_Leaf *expr) | 194 | LSL_Leaf *addStatement(LSL_Leaf *lval, LSL_Type type, LSL_Leaf *expr) |
207 | { | 195 | { |
208 | LSL_Statement *stat = malloc(sizeof(LSL_Statement)); | 196 | LSL_Statement *stat = malloc(sizeof(LSL_Statement)); |
197 | printf("******************************addStatement(%s, %d, , )\n", lval->token->token, type); | ||
209 | 198 | ||
210 | if (stat) | 199 | if (stat) |
211 | stat->expressions = expr; | ||
212 | |||
213 | return stat; | ||
214 | } | ||
215 | |||
216 | LSL_Leaf *addStatement(LSL_Statement *statement, LSL_Leaf *root) | ||
217 | { | ||
218 | LSL_Leaf *leaf = newLeaf(LSL_STATEMENT, root, NULL); | ||
219 | |||
220 | if (leaf) | ||
221 | { | 200 | { |
222 | leaf->value.statementValue = statement; | 201 | stat->type = type; |
202 | stat->expressions = expr; | ||
203 | if (lval) | ||
204 | lval->value.statementValue = stat; | ||
223 | } | 205 | } |
224 | 206 | ||
225 | return leaf; | 207 | return lval; |
226 | } | 208 | } |
227 | 209 | ||
228 | static void evaluateLeaf(LSL_Leaf *leaf, LSL_Leaf *left, LSL_Leaf *right) | 210 | static void evaluateLeaf(LSL_Leaf *leaf, LSL_Leaf *left, LSL_Leaf *right) |
@@ -349,10 +331,22 @@ static void evaluateOperationToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf * | |||
349 | } | 331 | } |
350 | } | 332 | } |
351 | 333 | ||
334 | static void eveluateParenthesisToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right) | ||
335 | { | ||
336 | if (content) | ||
337 | evaluateLeaf(content->value.parenthesis->expression, left, right); | ||
338 | } | ||
339 | |||
340 | |||
352 | static void evaluateStatementToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right) | 341 | static void evaluateStatementToken(LSL_Leaf *content, LSL_Leaf *left, LSL_Leaf *right) |
353 | { | 342 | { |
354 | if (content) | 343 | if (content) |
344 | { | ||
355 | evaluateLeaf(content->value.statementValue->expressions, left, right); | 345 | evaluateLeaf(content->value.statementValue->expressions, left, right); |
346 | printf("\nResult is %d.\n", left->value.integerValue); | ||
347 | left->value.integerValue = 0; | ||
348 | right->value.integerValue = 0; | ||
349 | } | ||
356 | } | 350 | } |
357 | 351 | ||
358 | static void outputLeaf(LSL_Leaf *leaf) | 352 | static void outputLeaf(LSL_Leaf *leaf) |
@@ -360,7 +354,7 @@ static void outputLeaf(LSL_Leaf *leaf) | |||
360 | if (leaf) | 354 | if (leaf) |
361 | { | 355 | { |
362 | outputLeaf(leaf->left); | 356 | outputLeaf(leaf->left); |
363 | if (leaf->ignorableText) | 357 | if ((!(LSL_NOIGNORE & leaf->token->flags)) && (leaf->ignorableText)) |
364 | printf("%s", leaf->ignorableText); | 358 | printf("%s", leaf->ignorableText); |
365 | if (leaf->token->output) | 359 | if (leaf->token->output) |
366 | leaf->token->output(leaf); | 360 | leaf->token->output(leaf); |
@@ -376,17 +370,25 @@ static void outputIntegerToken(LSL_Leaf *content) | |||
376 | printf("%d", content->value.integerValue); | 370 | printf("%d", content->value.integerValue); |
377 | } | 371 | } |
378 | 372 | ||
379 | static void outputOperationToken(LSL_Leaf *content) | 373 | static void outputParenthesisToken(LSL_Leaf *content) |
380 | { | 374 | { |
381 | if (content) | 375 | if (content) |
376 | { | ||
382 | printf("%s", content->token->token); | 377 | printf("%s", content->token->token); |
378 | outputLeaf(content->value.parenthesis->expression); | ||
379 | outputLeaf(content->value.parenthesis->right); | ||
380 | } | ||
383 | } | 381 | } |
384 | 382 | ||
385 | static void outputStatementToken(LSL_Leaf *content) | 383 | static void outputStatementToken(LSL_Leaf *content) |
386 | { | 384 | { |
387 | if (content) | 385 | if (content) |
386 | { | ||
388 | outputLeaf(content->value.statementValue->expressions); | 387 | outputLeaf(content->value.statementValue->expressions); |
389 | printf(";"); | 388 | if (content->ignorableText) |
389 | printf("%s", content->ignorableText); | ||
390 | printf("%s", content->token->token); | ||
391 | } | ||
390 | } | 392 | } |
391 | 393 | ||
392 | static void outputSpaceToken(LSL_Leaf *content) | 394 | static void outputSpaceToken(LSL_Leaf *content) |
@@ -400,6 +402,8 @@ static void convertLeaf2Lua(LSL_Leaf *leaf) | |||
400 | if (leaf) | 402 | if (leaf) |
401 | { | 403 | { |
402 | convertLeaf2Lua(leaf->left); | 404 | convertLeaf2Lua(leaf->left); |
405 | if ((!(LSL_NOIGNORE & leaf->token->flags)) && (leaf->ignorableText)) | ||
406 | printf("%s", leaf->ignorableText); | ||
403 | if (leaf->token->convert) | 407 | if (leaf->token->convert) |
404 | leaf->token->convert(leaf); | 408 | leaf->token->convert(leaf); |
405 | else if (leaf->token->output) | 409 | else if (leaf->token->output) |
@@ -426,8 +430,7 @@ int main(int argc, char **argv) | |||
426 | { | 430 | { |
427 | char buffer[4096]; | 431 | char buffer[4096]; |
428 | LuaSL_yyparseParam param; | 432 | LuaSL_yyparseParam param; |
429 | int count; | 433 | int file; |
430 | FILE *file; | ||
431 | boolean badArgs = FALSE; | 434 | boolean badArgs = FALSE; |
432 | 435 | ||
433 | // Sort the token table. | 436 | // Sort the token table. |
@@ -474,11 +477,13 @@ int main(int argc, char **argv) | |||
474 | printf("Usage: %s [-f filename]\n", programName); | 477 | printf("Usage: %s [-f filename]\n", programName); |
475 | printf(" -f: Script file to run.\n"); | 478 | printf(" -f: Script file to run.\n"); |
476 | printf("Or pass filenames in stdin.\n"); | 479 | printf("Or pass filenames in stdin.\n"); |
477 | return 1; | 480 | // return 1; |
478 | } | 481 | } |
479 | 482 | ||
480 | if ('\0' == buffer[0]) | 483 | if ('\0' == buffer[0]) |
481 | { | 484 | { |
485 | strcpy(buffer, "test.lsl"); | ||
486 | /* | ||
482 | count = read(STDIN_FILENO, buffer, sizeof(buffer)); | 487 | count = read(STDIN_FILENO, buffer, sizeof(buffer)); |
483 | if (0 > count) | 488 | if (0 > count) |
484 | { | 489 | { |
@@ -495,33 +500,55 @@ int main(int argc, char **argv) | |||
495 | buffer[count] = '\0'; | 500 | buffer[count] = '\0'; |
496 | printf("Filename %s in stdin.\n", buffer); | 501 | printf("Filename %s in stdin.\n", buffer); |
497 | } | 502 | } |
503 | */ | ||
498 | } | 504 | } |
499 | else | 505 | else |
500 | printf("Filename %s in argument.\n", buffer); | 506 | printf("Filename %s in argument.\n", buffer); |
501 | 507 | ||
502 | file = fopen(buffer, "r"); | 508 | file = open(buffer, 0); |
503 | if (NULL == file) | 509 | if (-1 == file) |
504 | { | 510 | { |
505 | printf("Error opening file %s.\n", buffer); | 511 | printf("Error opening file %s.\n", buffer); |
506 | return 1; | 512 | return 1; |
507 | } | 513 | } |
508 | |||
509 | #ifdef LUASL_DEBUG | 514 | #ifdef LUASL_DEBUG |
510 | yydebug= 5; | 515 | // yydebug= 5; |
511 | #endif | 516 | #endif |
512 | 517 | ||
513 | param.ast = NULL; | 518 | param.ast = NULL; |
519 | param.lval = calloc(1, sizeof(LSL_Leaf)); | ||
514 | if (yylex_init(&(param.scanner))) | 520 | if (yylex_init(&(param.scanner))) |
515 | return 1; | 521 | return 1; |
516 | 522 | ||
517 | #ifdef LUASL_DEBUG | 523 | #ifdef LUASL_DEBUG |
518 | yyset_debug(1, param.scanner); | 524 | yyset_debug(1, param.scanner); |
519 | #endif | 525 | #endif |
520 | yyset_in(file, param.scanner); | 526 | // yyset_in(file, param.scanner); |
521 | 527 | ||
522 | if (!yyparse(¶m)) | ||
523 | { | 528 | { |
529 | void *pParser = ParseAlloc(malloc); | ||
530 | int yv; | ||
531 | |||
532 | ParseTrace(stdout, "LSL_lemon "); | ||
533 | |||
534 | while ((i = read(file, buffer, 4095)) > 0) | ||
535 | { | ||
536 | buffer[i] = '\0'; | ||
537 | yy_scan_string(buffer, param.scanner); | ||
538 | // on EOF yylex will return 0 | ||
539 | while((yv = yylex(param.lval, param.scanner)) != 0) | ||
540 | { | ||
541 | printf("******************************PARSING - %d %s\n", yv, param.lval->token->token); | ||
542 | Parse(pParser, yv, param.lval, ¶m); | ||
543 | if (LSL_SCRIPT == yv) | ||
544 | break; | ||
545 | param.lval = calloc(1, sizeof(LSL_Leaf)); | ||
546 | } | ||
547 | } | ||
548 | |||
524 | yylex_destroy(param.scanner); | 549 | yylex_destroy(param.scanner); |
550 | Parse (pParser, 0, param.lval, ¶m); | ||
551 | ParseFree(pParser, free); | ||
525 | 552 | ||
526 | if (param.ast) | 553 | if (param.ast) |
527 | { | 554 | { |
@@ -531,20 +558,19 @@ int main(int argc, char **argv) | |||
531 | left.token = tokens[LSL_INTEGER - lowestToken]; | 558 | left.token = tokens[LSL_INTEGER - lowestToken]; |
532 | right.value.integerValue = 0; | 559 | right.value.integerValue = 0; |
533 | right.token = tokens[LSL_INTEGER - lowestToken]; | 560 | right.token = tokens[LSL_INTEGER - lowestToken]; |
534 | evaluateLeaf(param.ast, &left, &right); | ||
535 | 561 | ||
536 | #ifdef LUASL_DEBUG | ||
537 | printf("\n"); | ||
538 | #endif | ||
539 | printf("Result of -\n"); | ||
540 | outputLeaf(param.ast); | 562 | outputLeaf(param.ast); |
541 | printf("\n"); | 563 | printf("\n"); |
542 | printf("is %d %d. And converted to Lua it is -\n", left.value.integerValue, right.value.integerValue); | 564 | evaluateLeaf(param.ast, &left, &right); |
565 | |||
566 | printf("\nAnd converted to Lua it is -\n"); | ||
543 | convertLeaf2Lua(param.ast); | 567 | convertLeaf2Lua(param.ast); |
544 | printf("\n"); | 568 | printf("\n"); |
545 | burnLeaf(param.ast); | 569 | burnLeaf(param.ast); |
546 | } | 570 | } |
571 | |||
547 | } | 572 | } |
573 | |||
548 | } | 574 | } |
549 | else | 575 | else |
550 | { | 576 | { |
diff --git a/LuaSL/src/LuaSL_LSL_tree.h b/LuaSL/src/LuaSL_LSL_tree.h index 3fc436e..9db83d0 100644 --- a/LuaSL/src/LuaSL_LSL_tree.h +++ b/LuaSL/src/LuaSL_LSL_tree.h | |||
@@ -10,7 +10,20 @@ | |||
10 | #include <sys/stat.h> | 10 | #include <sys/stat.h> |
11 | #include <fcntl.h> | 11 | #include <fcntl.h> |
12 | 12 | ||
13 | #include "LuaSL_yaccer.tab.h" | 13 | //#include <iostream> |
14 | //#include <cstdlib> | ||
15 | #include "assert.h" | ||
16 | //#include "ex5def.h" | ||
17 | //#include "example5.h" | ||
18 | #include <unistd.h> | ||
19 | #include <sys/types.h> | ||
20 | #include <sys/stat.h> | ||
21 | #include <fcntl.h> | ||
22 | #include <stdlib.h> | ||
23 | //#include "lexglobal.h" | ||
24 | //#define BUFS 1024 | ||
25 | |||
26 | #include "LuaSL_lemon_yaccer.h" | ||
14 | 27 | ||
15 | #define YYERRCODE 256 | 28 | #define YYERRCODE 256 |
16 | #define YYDEBUG 1 | 29 | #define YYDEBUG 1 |
@@ -22,6 +35,7 @@ extern int yydebug; | |||
22 | 35 | ||
23 | typedef struct _LSL_Token LSL_Token; | 36 | typedef struct _LSL_Token LSL_Token; |
24 | typedef struct _LSL_Leaf LSL_Leaf; | 37 | typedef struct _LSL_Leaf LSL_Leaf; |
38 | typedef struct _LSL_Parenthesis LSL_Parenthesis; | ||
25 | typedef struct _LSL_Identifier LSL_Identifier; | 39 | typedef struct _LSL_Identifier LSL_Identifier; |
26 | typedef struct _LSL_Statement LSL_Statement; | 40 | typedef struct _LSL_Statement LSL_Statement; |
27 | typedef struct _LSL_Block LSL_Block; | 41 | typedef struct _LSL_Block LSL_Block; |
@@ -54,7 +68,8 @@ typedef enum | |||
54 | LSL_INNER2OUTER = 4, | 68 | LSL_INNER2OUTER = 4, |
55 | LSL_UNARY = 8, | 69 | LSL_UNARY = 8, |
56 | LSL_ASSIGNMENT = 16, | 70 | LSL_ASSIGNMENT = 16, |
57 | LSL_CREATION = 32 | 71 | LSL_CREATION = 32, |
72 | LSL_NOIGNORE = 64 | ||
58 | } LSL_Flags; | 73 | } LSL_Flags; |
59 | 74 | ||
60 | struct _LSL_Token | 75 | struct _LSL_Token |
@@ -78,6 +93,7 @@ struct _LSL_Leaf | |||
78 | 93 | ||
79 | LSL_Type operationValue; | 94 | LSL_Type operationValue; |
80 | LSL_Leaf *expressionValue; | 95 | LSL_Leaf *expressionValue; |
96 | LSL_Parenthesis *parenthesis; | ||
81 | 97 | ||
82 | float floatValue; | 98 | float floatValue; |
83 | int integerValue; | 99 | int integerValue; |
@@ -115,6 +131,13 @@ struct _LSL_Leaf | |||
115 | int line, column; | 131 | int line, column; |
116 | }; | 132 | }; |
117 | 133 | ||
134 | struct _LSL_Parenthesis | ||
135 | { | ||
136 | LSL_Leaf *left; | ||
137 | LSL_Leaf *expression; | ||
138 | LSL_Leaf *right; | ||
139 | }; | ||
140 | |||
118 | struct _LSL_Identifier // For variables and function parameters. | 141 | struct _LSL_Identifier // For variables and function parameters. |
119 | { | 142 | { |
120 | char *name; | 143 | char *name; |
@@ -124,6 +147,7 @@ struct _LSL_Identifier // For variables and function parameters. | |||
124 | struct _LSL_Statement | 147 | struct _LSL_Statement |
125 | { | 148 | { |
126 | LSL_Leaf *expressions; /// For things like a for statement, might hold three expressions. | 149 | LSL_Leaf *expressions; /// For things like a for statement, might hold three expressions. |
150 | LSL_Type type; // Expression type. | ||
127 | }; | 151 | }; |
128 | 152 | ||
129 | struct _LSL_Block | 153 | struct _LSL_Block |
@@ -167,25 +191,30 @@ typedef struct | |||
167 | { | 191 | { |
168 | yyscan_t scanner; | 192 | yyscan_t scanner; |
169 | LSL_Leaf *ast; | 193 | LSL_Leaf *ast; |
194 | LSL_Leaf *lval; | ||
170 | } LuaSL_yyparseParam; | 195 | } LuaSL_yyparseParam; |
171 | 196 | ||
172 | // the parameter name (of the reentrant 'yyparse' function) | 197 | // the parameter name (of the reentrant 'yyparse' function) |
173 | // data is a pointer to a 'yyparseParam' structure | 198 | // data is a pointer to a 'yyparseParam' structure |
174 | #define YYPARSE_PARAM data | 199 | //#define YYPARSE_PARAM data |
175 | 200 | ||
176 | // the argument for the 'yylex' function | 201 | // the argument for the 'yylex' function |
177 | #define YYLEX_PARAM ((LuaSL_yyparseParam*)data)->scanner | 202 | #define YYLEX_PARAM ((LuaSL_yyparseParam*)data)->scanner |
203 | //#define ParseTOKENTYPE YYSTYPE * | ||
204 | //#define ParseARG_PDECL , LuaSL_yyparseParam *param | ||
178 | 205 | ||
179 | 206 | void burnLeaf(LSL_Leaf *leaf); | |
180 | LSL_Leaf *addExpression(LSL_Leaf *exp); | 207 | LSL_Leaf *addExpression(LSL_Leaf *exp); |
181 | LSL_Leaf *addInteger(LSL_Leaf *lval, int value); | ||
182 | LSL_Leaf *addOperation(LSL_Leaf *lval, LSL_Type type, LSL_Leaf *left, LSL_Leaf *right); | 208 | LSL_Leaf *addOperation(LSL_Leaf *lval, LSL_Type type, LSL_Leaf *left, LSL_Leaf *right); |
183 | LSL_Leaf *addParenthesis(LSL_Leaf *lval, LSL_Leaf *expr); | 209 | LSL_Leaf *addParenthesis(LSL_Leaf *lval, LSL_Leaf *expr, LSL_Leaf *rval); |
184 | LSL_Statement *createStatement(LSL_Type type, LSL_Leaf *root); | 210 | LSL_Leaf *addStatement(LSL_Leaf *lval, LSL_Type type, LSL_Leaf *expr); |
185 | LSL_Leaf *addStatement(LSL_Statement *statement, LSL_Leaf *root); | ||
186 | 211 | ||
187 | int yyerror(const char *msg); | 212 | int yyerror(const char *msg); |
188 | int yyparse(void *param); | 213 | |
214 | void *ParseAlloc(void *(*mallocProc)(size_t)); | ||
215 | void ParseTrace(FILE *TraceFILE, char *zTracePrompt); | ||
216 | void Parse(void *yyp, int yymajor, LSL_Leaf *yyminor, LuaSL_yyparseParam *param); | ||
217 | void ParseFree(void *p, void (*freeProc)(void*)); | ||
189 | 218 | ||
190 | 219 | ||
191 | #endif // __EXPRESSION_H__ | 220 | #endif // __EXPRESSION_H__ |
diff --git a/LuaSL/src/LuaSL_lemon_yaccer.y b/LuaSL/src/LuaSL_lemon_yaccer.y new file mode 100644 index 0000000..14942b7 --- /dev/null +++ b/LuaSL/src/LuaSL_lemon_yaccer.y | |||
@@ -0,0 +1,103 @@ | |||
1 | %include { | ||
2 | #include "LuaSL_LSL_tree.h" | ||
3 | } | ||
4 | |||
5 | %extra_argument { LuaSL_yyparseParam *param } | ||
6 | |||
7 | %stack_size 256 | ||
8 | |||
9 | %token_type {LSL_Leaf *} | ||
10 | %default_type {LSL_Leaf *} | ||
11 | %token_destructor { burnLeaf($$); } | ||
12 | |||
13 | |||
14 | program ::= script LSL_SCRIPT(A). { A->left = param->ast; param->ast = A; } // Lemon does not like the start symbol to be on the RHS, so give it a dummy one. | ||
15 | |||
16 | |||
17 | %left LSL_BOOL_AND. | ||
18 | expr(A) ::= expr(B) LSL_BOOL_AND(D) expr(C). { A = addOperation(D, D->token->type, B, C); } | ||
19 | %left LSL_BOOL_OR. | ||
20 | expr(A) ::= expr(B) LSL_BOOL_OR(D) expr(C). { A = addOperation(D, LSL_BOOL_OR, B, C); } | ||
21 | %left LSL_BIT_AND LSL_BIT_XOR LSL_BIT_OR. | ||
22 | expr(A) ::= expr(B) LSL_BIT_OR(D) expr(C). { A = addOperation(D, LSL_BIT_OR, B, C); } | ||
23 | expr(A) ::= expr(B) LSL_BIT_XOR(D) expr(C). { A = addOperation(D, LSL_BIT_XOR, B, C); } | ||
24 | expr(A) ::= expr(B) LSL_BIT_AND(D) expr(C). { A = addOperation(D, LSL_BIT_AND, B, C); } | ||
25 | %left LSL_EQUAL LSL_NOT_EQUAL. | ||
26 | expr(A) ::= expr(B) LSL_NOT_EQUAL(D) expr(C). { A = addOperation(D, LSL_NOT_EQUAL, B, C); } | ||
27 | expr(A) ::= expr(B) LSL_EQUAL(D) expr(C). { A = addOperation(D, LSL_EQUAL, B, C); } | ||
28 | %left LSL_LESS_THAN LSL_GREATER_THAN LSL_LESS_EQUAL LSL_GREATER_EQUAL. | ||
29 | expr(A) ::= expr(B) LSL_GREATER_EQUAL(D) expr(C). { A = addOperation(D, LSL_GREATER_EQUAL, B, C); } | ||
30 | expr(A) ::= expr(B) LSL_LESS_EQUAL(D) expr(C). { A = addOperation(D, LSL_LESS_EQUAL, B, C); } | ||
31 | expr(A) ::= expr(B) LSL_GREATER_THAN(D) expr(C). { A = addOperation(D, LSL_GREATER_THAN, B, C); } | ||
32 | expr(A) ::= expr(B) LSL_LESS_THAN(D) expr(C). { A = addOperation(D, LSL_LESS_THAN, B, C); } | ||
33 | %left LSL_LEFT_SHIFT LSL_RIGHT_SHIFT. | ||
34 | expr(A) ::= expr(B) LSL_RIGHT_SHIFT(D) expr(C). { A = addOperation(D, LSL_RIGHT_SHIFT, B, C); } | ||
35 | expr(A) ::= expr(B) LSL_LEFT_SHIFT(D) expr(C). { A = addOperation(D, LSL_LEFT_SHIFT, B, C); } | ||
36 | %left LSL_SUBTRACT LSL_ADD. | ||
37 | expr(A) ::= expr(B) LSL_ADD(D) expr(C). { A = addOperation(D, LSL_ADD, B, C); } | ||
38 | expr(A) ::= expr(B) LSL_SUBTRACT(D) expr(C). { A = addOperation(D, LSL_SUBTRACT, B, C); } | ||
39 | %left LSL_DIVIDE LSL_MODULO LSL_MULTIPLY. | ||
40 | expr(A) ::= expr(B) LSL_MULTIPLY(D) expr(C). { A = addOperation(D, LSL_MULTIPLY, B, C); } | ||
41 | expr(A) ::= expr(B) LSL_MODULO(D) expr(C). { A = addOperation(D, LSL_MODULO, B, C); } | ||
42 | expr(A) ::= expr(B) LSL_DIVIDE(D) expr(C). { A = addOperation(D, LSL_DIVIDE, B, C); } | ||
43 | %right LSL_BIT_NOT LSL_BOOL_NOT LSL_NEGATION. | ||
44 | expr(A) ::= LSL_BIT_NOT(D) expr(B). { A = addOperation(D, LSL_BIT_NOT, NULL, B); } | ||
45 | expr(A) ::= LSL_BOOL_NOT(D) expr(B). { A = addOperation(D, LSL_BOOL_NOT, NULL, B); } | ||
46 | expr(A) ::= LSL_SUBTRACT(D) expr(B). [LSL_NEGATION] { A = addOperation(D, LSL_NEGATION, NULL, B); } | ||
47 | %left LSL_ANGLE_OPEN LSL_ANGLE_CLOSE. | ||
48 | %nonassoc LSL_BRACKET_OPEN LSL_BRACKET_CLOSE. | ||
49 | %nonassoc LSL_PARENTHESIS_OPEN LSL_PARENTHESIS_CLOSE LSL_EXPRESSION. | ||
50 | expr(A) ::= LSL_PARENTHESIS_OPEN(B) expr(C) LSL_PARENTHESIS_CLOSE(D). { A = addParenthesis(B, C, D); } | ||
51 | %right LSL_ASSIGNMENT_ADD LSL_ASSIGNMENT_SUBTRACT LSL_ASSIGNMENT_MULTIPLY LSL_ASSIGNMENT_MODULO LSL_ASSIGNMENT_DIVIDE LSL_ASSIGNMENT_PLAIN. | ||
52 | %right LSL_DOT. | ||
53 | %right LSL_DECREMENT_PRE LSL_INCREMENT_PRE. | ||
54 | %nonassoc LSL_COMMA. | ||
55 | |||
56 | %nonassoc LSL_FLOAT. | ||
57 | %nonassoc LSL_INTEGER. | ||
58 | expr(A) ::= LSL_INTEGER(B). { A = B; } | ||
59 | |||
60 | %nonassoc LSL_TYPE_FLOAT LSL_TYPE_INTEGER LSL_TYPE_KEY LSL_TYPE_LIST LSL_TYPE_ROTATION LSL_TYPE_STRING LSL_TYPE_VECTOR. | ||
61 | |||
62 | %nonassoc LSL_DO LSL_FOR LSL_ELSE LSL_IF LSL_JUMP LSL_RETURN LSL_STATE_CHANGE LSL_WHILE. | ||
63 | |||
64 | %nonassoc LSL_LABEL. | ||
65 | |||
66 | %nonassoc LSL_BLOCK_OPEN LSL_BLOCK_CLOSE. | ||
67 | |||
68 | %nonassoc LSL_STATEMENT. | ||
69 | statement(A) ::= expr(B) LSL_STATEMENT(D). { A = addStatement(D, LSL_EXPRESSION, B); } | ||
70 | |||
71 | %nonassoc LSL_SPACE LSL_COMMENT LSL_COMMENT_LINE LSL_IDENTIFIER LSL_SCRIPT LSL_UNKNOWN. | ||
72 | script ::= script statement(A). { A->left = param->ast; param->ast = A; } | ||
73 | script ::= statement(A). { A->left = param->ast; param->ast = A; } | ||
74 | |||
75 | |||
76 | %parse_accept {printf("Parsing complete.\n");} | ||
77 | |||
78 | %parse_failure { | ||
79 | fprintf(stderr,"Giving up. Parser is hopelessly lost...\n"); | ||
80 | } | ||
81 | |||
82 | %stack_overflow { | ||
83 | fprintf(stderr,"Giving up. Parser stack overflow!\n"); | ||
84 | } | ||
85 | |||
86 | %syntax_error { | ||
87 | fprintf(stderr,"Syntax error!\n"); | ||
88 | } | ||
89 | |||
90 | /* Undocumented shit that might be useful later. Pffft | ||
91 | |||
92 | ** The next table maps tokens into fallback tokens. If a construct | ||
93 | ** like the following: | ||
94 | **. | ||
95 | ** %fallback ID X Y Z. | ||
96 | ** | ||
97 | ** appears in the grammar, then ID becomes a fallback token for X, Y, | ||
98 | ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser | ||
99 | ** but it does not parse, the type of the token is changed to ID and | ||
100 | ** the parse is retried before an error is thrown. | ||
101 | |||
102 | */ | ||
103 | |||
diff --git a/LuaSL/src/LuaSL_lexer.l b/LuaSL/src/LuaSL_lexer.l index d81eb29..ddcb520 100644 --- a/LuaSL/src/LuaSL_lexer.l +++ b/LuaSL/src/LuaSL_lexer.l | |||
@@ -100,7 +100,7 @@ IDENTIFIER [[:alpha:]](_|[[:alpha:]]|[[:digit:]])* | |||
100 | "}" %{ return common(yylval, yytext, TRUE, LSL_BLOCK_CLOSE); %} | 100 | "}" %{ return common(yylval, yytext, TRUE, LSL_BLOCK_CLOSE); %} |
101 | ";" %{ return common(yylval, yytext, TRUE, LSL_STATEMENT); %} | 101 | ";" %{ return common(yylval, yytext, TRUE, LSL_STATEMENT); %} |
102 | 102 | ||
103 | <<EOF>> { yyterminate(); } | 103 | <<EOF>> { return common(yylval, yytext, TRUE, LSL_SCRIPT); } |
104 | 104 | ||
105 | /* Everything else */ | 105 | /* Everything else */ |
106 | . %{ printf(" unexpected character.\n"); yylval->value.unknownValue = strdup(yytext); common(yylval, yytext, TRUE, LSL_UNKNOWN); %} | 106 | . %{ printf(" unexpected character.\n"); yylval->value.unknownValue = strdup(yytext); common(yylval, yytext, TRUE, LSL_UNKNOWN); %} |
@@ -150,7 +150,7 @@ int common(YYSTYPE *lval, char *text, boolean checkIgnorable, int type) | |||
150 | } | 150 | } |
151 | 151 | ||
152 | #ifdef LUASL_DEBUG | 152 | #ifdef LUASL_DEBUG |
153 | printf ("%04d, %04d [%s]\n", line, column, text); | 153 | printf ("******************************common(%s, \"%s\", , %d) %04d, %04d\n", lval->token->token, text, type, line, column); |
154 | #endif | 154 | #endif |
155 | 155 | ||
156 | return type; | 156 | return type; |
diff --git a/LuaSL/src/btyacc-c.ske b/LuaSL/src/btyacc-c.ske deleted file mode 100644 index 399a25c..0000000 --- a/LuaSL/src/btyacc-c.ske +++ /dev/null | |||
@@ -1,939 +0,0 @@ | |||
1 | /* -*- C -*- | ||
2 | |||
3 | The banner used here should be replaced with an #ident directive if | ||
4 | the target C compiler supports #ident directives. | ||
5 | |||
6 | If the skeleton is changed, the banner should be changed so that | ||
7 | the altered version can easily be distinguished from the original. */ | ||
8 | |||
9 | %% banner | ||
10 | /* -*- C -*- | ||
11 | |||
12 | @(#)btyaccpar, based on byacc 1.8 (Berkeley), modified for rentrant flex. | ||
13 | |||
14 | */ | ||
15 | #define YYBTYACC 1 | ||
16 | |||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | |||
21 | typedef int Yshort; | ||
22 | |||
23 | %% tables | ||
24 | |||
25 | #ifndef _YACC_EXTERN_ | ||
26 | # define _YACC_EXTERN_ "C" | ||
27 | #endif | ||
28 | |||
29 | extern _YACC_EXTERN_ Yshort yylhs[]; | ||
30 | extern _YACC_EXTERN_ Yshort yylen[]; | ||
31 | |||
32 | /* idx: current state; entry: non-zero if to reduce regardless of lookahead*/ | ||
33 | extern _YACC_EXTERN_ Yshort yydefred[]; | ||
34 | |||
35 | extern _YACC_EXTERN_ Yshort yydgoto[]; | ||
36 | |||
37 | /* idx: current state; entry: non-zero if shifting|reducing possible | ||
38 | in this state - in that case, yycheck[entry + lookahead] indicates | ||
39 | whether to perform the action for this lookahead. */ | ||
40 | extern _YACC_EXTERN_ Yshort yysindex[]; | ||
41 | extern _YACC_EXTERN_ Yshort yyrindex[]; | ||
42 | |||
43 | /* yycindex idx: current state; entry: non-zero if shift/reduce | ||
44 | conflicts for this state - in that case, yycheck[entry + lookahead] | ||
45 | indicates whether there's a conflict for this lookahead */ | ||
46 | extern _YACC_EXTERN_ Yshort yycindex[]; | ||
47 | extern _YACC_EXTERN_ Yshort yycheck[]; | ||
48 | |||
49 | extern _YACC_EXTERN_ Yshort yygindex[]; | ||
50 | extern _YACC_EXTERN_ Yshort yytable[]; | ||
51 | extern _YACC_EXTERN_ Yshort yyctable[]; | ||
52 | |||
53 | #if YYDEBUG | ||
54 | /* idx: token code; entry: spelling of token */ | ||
55 | extern _YACC_EXTERN_ char *yyname[]; | ||
56 | |||
57 | extern _YACC_EXTERN_ char *yyrule[]; | ||
58 | #endif | ||
59 | |||
60 | %% header | ||
61 | |||
62 | /* YYPOSN is user-defined text position type. */ | ||
63 | #ifndef YYPOSN | ||
64 | # define YYPOSN int | ||
65 | #endif | ||
66 | |||
67 | #ifdef YYREDUCEPOSNFUNC | ||
68 | # define YYCALLREDUCEPOSN(e) \ | ||
69 | if(reduce_posn) { \ | ||
70 | YYREDUCEPOSNFUNC(yyps->pos, &(yyps->psp)[1-yym], &(yyps->vsp)[1-yym],\ | ||
71 | yym, yyps->psp - yyps->ps, yychar, yyposn, e); \ | ||
72 | reduce_posn = 0; \ | ||
73 | } | ||
74 | |||
75 | # ifndef YYCALLREDUCEPOSNARG | ||
76 | # define YYCALLREDUCEPOSNARG (yyps->val) | ||
77 | # endif | ||
78 | |||
79 | |||
80 | # define YYPOSNARG(n) ((yyps->psp)[1-yym+(n)-1]) | ||
81 | # define YYPOSNOUT (yyps->pos) | ||
82 | #endif | ||
83 | |||
84 | /* If delete function is not defined by the user, do not delete. */ | ||
85 | #ifndef YYDELETEVAL | ||
86 | # define YYDELETEVAL(v, t) | ||
87 | #endif | ||
88 | |||
89 | /* If delete function is not defined by the user, do not delete. */ | ||
90 | #ifndef YYDELETEPOSN | ||
91 | # define YYDELETEPOSN(v, t) | ||
92 | #endif | ||
93 | |||
94 | #define YYEMPTY (-1) | ||
95 | #define yyclearin (yychar=YYEMPTY) | ||
96 | |||
97 | #define yyerrok (yyps->errflag=0) | ||
98 | |||
99 | #ifndef YYSTACKGROWTH | ||
100 | # define YYSTACKGROWTH 32 | ||
101 | #endif | ||
102 | |||
103 | #ifndef YYDEFSTACKSIZE | ||
104 | # define YYDEFSTACKSIZE 12 | ||
105 | #endif | ||
106 | |||
107 | #ifdef YYDEBUG | ||
108 | int yydebug = 0; | ||
109 | #endif | ||
110 | |||
111 | int yynerrs; | ||
112 | |||
113 | /* These value/posn are taken from the lexer */ | ||
114 | YYSTYPE yylval; | ||
115 | YYPOSN yyposn; | ||
116 | |||
117 | /* These value/posn of the root non-terminal are returned to the caller */ | ||
118 | YYSTYPE yyretlval; | ||
119 | YYPOSN yyretposn; | ||
120 | |||
121 | #define YYABORT goto yyabort | ||
122 | #define YYACCEPT goto yyaccept | ||
123 | #define YYERROR goto yyerrlab | ||
124 | #define YYVALID do { if (yyps->save) goto yyvalid; } while(0) | ||
125 | #define YYVALID_NESTED do { if (yyps->save && \ | ||
126 | yyps->save->save==0) goto yyvalid; } while(0) | ||
127 | |||
128 | struct YYParseState_s { | ||
129 | struct YYParseState_s *save; /* Previously saved parser state */ | ||
130 | int state; | ||
131 | int errflag; | ||
132 | Yshort *ssp; /* state stack pointer */ | ||
133 | YYSTYPE *vsp; /* value stack pointer */ | ||
134 | YYPOSN *psp; /* position stack pointer */ | ||
135 | YYSTYPE val; /* value as returned by actions */ | ||
136 | YYPOSN pos; /* position as returned by universal action */ | ||
137 | Yshort *ss; /* state stack base */ | ||
138 | YYSTYPE *vs; /* values stack base */ | ||
139 | YYPOSN *ps; /* position stack base */ | ||
140 | int lexeme; /* index of conflict lexeme in lexical queue */ | ||
141 | unsigned int stacksize; /* current maximum stack size */ | ||
142 | Yshort ctry; /* index in yyctable[] for this conflict */ | ||
143 | }; | ||
144 | typedef struct YYParseState_s YYParseState; | ||
145 | |||
146 | /* Current parser state */ | ||
147 | static YYParseState *yyps = 0; | ||
148 | |||
149 | /* yypath!=NULL: do the full parse, starting at *yypath parser state. */ | ||
150 | static YYParseState *yypath = 0; | ||
151 | |||
152 | /* Base of the lexical value queue */ | ||
153 | static YYSTYPE *yylvals = 0; | ||
154 | |||
155 | /* Current position at lexical value queue */ | ||
156 | static YYSTYPE *yylvp = 0; | ||
157 | |||
158 | /* End position of lexical value queue */ | ||
159 | static YYSTYPE *yylve = 0; | ||
160 | |||
161 | /* The last allocated position at the lexical value queue */ | ||
162 | static YYSTYPE *yylvlim = 0; | ||
163 | |||
164 | /* Base of the lexical position queue */ | ||
165 | static YYPOSN *yylpsns = 0; | ||
166 | |||
167 | /* Current position at lexical position queue */ | ||
168 | static YYPOSN *yylpp = 0; | ||
169 | |||
170 | /* End position of lexical position queue */ | ||
171 | static YYPOSN *yylpe = 0; | ||
172 | |||
173 | /* The last allocated position at the lexical position queue */ | ||
174 | static YYPOSN *yylplim = 0; | ||
175 | |||
176 | /* Current position at lexical token queue */ | ||
177 | static Yshort *yylexp = 0; | ||
178 | |||
179 | static Yshort *yylexemes = 0; | ||
180 | |||
181 | /* For use in generated program */ | ||
182 | #define yytrial (yyps->save) | ||
183 | #define yyvsp (yyps->vsp) | ||
184 | #define yyval (yyps->val) | ||
185 | #define yydepth (yyps->ssp - yyps->ss) | ||
186 | |||
187 | |||
188 | /* Local prototypes. */ | ||
189 | int yyparse(void *YYPARSE_PARAM); | ||
190 | |||
191 | static int yyLex1(YYSTYPE *yylval, yyscan_t scanner); | ||
192 | static int yyExpand(); | ||
193 | static void yySCopy(YYSTYPE *to, YYSTYPE *from, int size); | ||
194 | static void yyPCopy(YYPOSN *to, YYPOSN *from, int size); | ||
195 | static void yyMoreStack(YYParseState *yyps); | ||
196 | static YYParseState *yyNewState(int size); | ||
197 | static void yyFreeState(YYParseState *p); | ||
198 | |||
199 | |||
200 | %% body | ||
201 | |||
202 | |||
203 | /* Parser function. Roughly looks like this: | ||
204 | int yyparse(void *YYPARSE_PARAM) { | ||
205 | yyloop: | ||
206 | if (reduce_possible) goto yyreduce; | ||
207 | read_token; | ||
208 | if (conflict) { | ||
209 | handle_conflict; | ||
210 | goto yyshift; or goto yyreduce; | ||
211 | } | ||
212 | if (shift_possible) { | ||
213 | yyshift: | ||
214 | do_shift; | ||
215 | goto yyloop; | ||
216 | } | ||
217 | if (reduce_possible) goto yyreduce; | ||
218 | |||
219 | (error handling); | ||
220 | goto yyloop; | ||
221 | |||
222 | yyreduce: | ||
223 | BIG_CHUNK_OF_RULE_ACTIONS; | ||
224 | goto yyloop; | ||
225 | |||
226 | (more error handling); | ||
227 | }*/ | ||
228 | int yyparse(void *YYPARSE_PARAM) { | ||
229 | int yym, yyn, yystate, yychar, yynewerrflag; | ||
230 | YYParseState *yyerrctx = 0; | ||
231 | int reduce_posn; | ||
232 | |||
233 | # if YYDEBUG | ||
234 | char *yys; | ||
235 | |||
236 | if ((yys = getenv("YYDEBUG"))) { | ||
237 | yyn = *yys; | ||
238 | if (yyn >= '0' && yyn <= '9') | ||
239 | yydebug = yyn - '0'; | ||
240 | } | ||
241 | if (yydebug) { | ||
242 | fputs("btyacc[<current state>,<nr of symbols on state stack>]\n", | ||
243 | stderr); | ||
244 | } | ||
245 | # endif | ||
246 | |||
247 | yyps = yyNewState(YYDEFSTACKSIZE); | ||
248 | yyps->save = 0; | ||
249 | yynerrs = 0; | ||
250 | yyps->errflag = 0; | ||
251 | yychar = (YYEMPTY); | ||
252 | |||
253 | yyps->ssp = yyps->ss; | ||
254 | yyps->vsp = yyps->vs; | ||
255 | yyps->psp = yyps->ps; | ||
256 | *(yyps->ssp) = yystate = 0; | ||
257 | |||
258 | |||
259 | /* Main parsing loop */ | ||
260 | yyloop: | ||
261 | if ((yyn = yydefred[yystate])) { | ||
262 | goto yyreduce; | ||
263 | } | ||
264 | |||
265 | /* Read one token */ | ||
266 | if (yychar < 0) { | ||
267 | yychar = yyLex1(&yylval, YYLEX_PARAM); | ||
268 | if (yychar < 0) yychar = 0; | ||
269 | # if YYDEBUG | ||
270 | if (yydebug) { | ||
271 | yys = 0; | ||
272 | if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; | ||
273 | if (!yys) yys = "illegal-symbol"; | ||
274 | fprintf(stderr, "btyacc[%3d,%2d%s]: read token %d (%s)", | ||
275 | yystate, (int) yydepth, (yytrial ? ",trial" : ""), yychar, yys); | ||
276 | # ifdef YYDBPR | ||
277 | fputc('<', stderr); | ||
278 | YYDBPR(yylval); | ||
279 | fputc('>', stderr); | ||
280 | # endif | ||
281 | fputc('\n', stderr); | ||
282 | } | ||
283 | # endif | ||
284 | } | ||
285 | |||
286 | /* Do we have a conflict? */ | ||
287 | yyn = yycindex[yystate]; | ||
288 | if (yyn != 0 && (yyn += yychar) >= 0 | ||
289 | && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { | ||
290 | int ctry; | ||
291 | |||
292 | if (yypath) { | ||
293 | YYParseState *save; | ||
294 | # if YYDEBUG | ||
295 | if (yydebug) { | ||
296 | fprintf(stderr, "btyacc[%3d,%2d%s]: CONFLICT: following successful " | ||
297 | "trial parse\n", yystate, (int) yydepth, (yytrial ? ",trial" :"")); | ||
298 | } | ||
299 | # endif | ||
300 | /* Switch to the next conflict context */ | ||
301 | save = yypath; | ||
302 | yypath = save->save; | ||
303 | ctry = save->ctry; | ||
304 | if (save->state != yystate) | ||
305 | goto yyabort; | ||
306 | yyFreeState(save); | ||
307 | |||
308 | } else { | ||
309 | |||
310 | /* Unresolved conflict - start/continue trial parse */ | ||
311 | YYParseState *save; | ||
312 | # if YYDEBUG | ||
313 | if (yydebug) { | ||
314 | fprintf(stderr, "btyacc[%3d,%2d%s]: CONFLICT. ", | ||
315 | yystate, (int) yydepth, (yytrial ? ",trial" : "")); | ||
316 | if(yyps->save) | ||
317 | fputs("ALREADY in conflict, continuing trial parse.\n", stderr); | ||
318 | else | ||
319 | fputs("starting trial parse.\n", stderr); | ||
320 | } | ||
321 | # endif | ||
322 | save = yyNewState(yyps->ssp - yyps->ss); | ||
323 | save->save = yyps->save; | ||
324 | save->state = yystate; | ||
325 | save->errflag = yyps->errflag; | ||
326 | save->ssp = save->ss + (yyps->ssp - yyps->ss); | ||
327 | save->vsp = save->vs + (yyps->vsp - yyps->vs); | ||
328 | save->psp = save->ps + (yyps->psp - yyps->ps); | ||
329 | memcpy(save->ss, yyps->ss, (yyps->ssp - yyps->ss + 1)*sizeof(Yshort)); | ||
330 | yySCopy(save->vs, yyps->vs, (yyps->ssp - yyps->ss + 1)); | ||
331 | yyPCopy(save->ps, yyps->ps, (yyps->ssp - yyps->ss + 1)); | ||
332 | ctry = yytable[yyn]; | ||
333 | if (yyctable[ctry] == -1) { | ||
334 | # if YYDEBUG | ||
335 | if (yydebug && yychar >= 0) | ||
336 | fputs("btyacc[trial]: backtracking 1 token\n", stderr); | ||
337 | # endif | ||
338 | ctry++; | ||
339 | } | ||
340 | save->ctry = ctry; | ||
341 | if (yyps->save == 0) { | ||
342 | /* If this is a first conflict in the stack, start saving lexemes */ | ||
343 | if (!yylexemes) { | ||
344 | # ifdef __cplusplus | ||
345 | yylexemes = new Yshort[YYSTACKGROWTH]; | ||
346 | yylvals = new YYSTYPE[YYSTACKGROWTH]; | ||
347 | yylvlim = yylvals + YYSTACKGROWTH; | ||
348 | yylpsns = new YYPOSN[YYSTACKGROWTH]; | ||
349 | yylplim = yylpsns + YYSTACKGROWTH; | ||
350 | # else | ||
351 | yylexemes = (Yshort*)malloc((YYSTACKGROWTH) * sizeof(Yshort)); | ||
352 | yylvals = (YYSTYPE*)malloc((YYSTACKGROWTH) * sizeof(YYSTYPE)); | ||
353 | yylvlim = yylvals + YYSTACKGROWTH; | ||
354 | yylpsns = (YYPOSN*)malloc((YYSTACKGROWTH) * sizeof(YYPOSN)); | ||
355 | yylplim = yylpsns + YYSTACKGROWTH; | ||
356 | # endif | ||
357 | } | ||
358 | if (yylvp == yylve) { | ||
359 | yylvp = yylve = yylvals; | ||
360 | yylpp = yylpe = yylpsns; | ||
361 | yylexp = yylexemes; | ||
362 | if (yychar >= 0) { | ||
363 | *yylve++ = yylval; | ||
364 | *yylpe++ = yyposn; | ||
365 | *yylexp = yychar; | ||
366 | yychar = YYEMPTY; | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | if (yychar >= 0) { | ||
371 | yylvp--, yylpp--, yylexp--; | ||
372 | yychar = YYEMPTY; | ||
373 | } | ||
374 | save->lexeme = yylvp - yylvals; | ||
375 | yyps->save = save; | ||
376 | } | ||
377 | |||
378 | if (yytable[yyn] == ctry) { | ||
379 | # if YYDEBUG | ||
380 | if (yydebug) | ||
381 | fprintf(stderr, "btyacc[%3d,%2d%s]: shifting to state %d\n", | ||
382 | yystate, (int) yydepth, (yytrial ? ",trial" : ""), yyctable[ctry]); | ||
383 | # endif | ||
384 | if (yychar < 0) { | ||
385 | yylvp++; yylpp++; yylexp++; | ||
386 | } | ||
387 | yychar = YYEMPTY; | ||
388 | if (yyps->errflag > 0) --yyps->errflag; | ||
389 | yystate = yyctable[ctry]; | ||
390 | goto yyshift; | ||
391 | } else { | ||
392 | yyn = yyctable[ctry]; | ||
393 | goto yyreduce; | ||
394 | } | ||
395 | } /* End of code dealing with conflicts */ | ||
396 | |||
397 | |||
398 | /* Is action a shift? */ | ||
399 | yyn = yysindex[yystate]; | ||
400 | if (yyn != 0 && (yyn += yychar) >= 0 | ||
401 | && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { | ||
402 | # if YYDEBUG | ||
403 | if (yydebug) | ||
404 | fprintf(stderr, "btyacc[%3d,%2d%s]: shifting to state %d\n", | ||
405 | yystate, (int) yydepth, (yytrial ? ",trial" : ""), yytable[yyn]); | ||
406 | # endif | ||
407 | yychar = YYEMPTY; | ||
408 | if (yyps->errflag > 0) --yyps->errflag; | ||
409 | yystate = yytable[yyn]; | ||
410 | |||
411 | yyshift: | ||
412 | if (yyps->ssp >= yyps->ss + yyps->stacksize - 1) { | ||
413 | yyMoreStack(yyps); | ||
414 | } | ||
415 | *++(yyps->ssp) = yystate; | ||
416 | *++(yyps->vsp) = yylval; | ||
417 | *++(yyps->psp) = yyposn; | ||
418 | goto yyloop; | ||
419 | } | ||
420 | if ((yyn = yyrindex[yystate]) && | ||
421 | (yyn += yychar) >= 0 && | ||
422 | yyn <= YYTABLESIZE && | ||
423 | yycheck[yyn] == yychar) { | ||
424 | yyn = yytable[yyn]; | ||
425 | goto yyreduce; | ||
426 | } | ||
427 | |||
428 | /* According to the tables, neither shift nor reduce is OK here - error! */ | ||
429 | if (yyps->errflag) goto yyinrecovery; | ||
430 | yynewerrflag = 1; | ||
431 | goto yyerrhandler; | ||
432 | yyerrlab: | ||
433 | yynewerrflag = 0; | ||
434 | yyerrhandler: | ||
435 | while (yyps->save) { | ||
436 | int ctry; | ||
437 | YYParseState *save = yyps->save; | ||
438 | # if YYDEBUG | ||
439 | if (yydebug) | ||
440 | fprintf(stderr, "btyacc[%3d,%2d%s]: ERROR, " | ||
441 | "CONFLICT BACKTRACKING to state %d, %d tokens\n", | ||
442 | yystate, (int) yydepth, (yytrial ? ",trial" : ""), | ||
443 | yyps->save->state, (int) (yylvp - yylvals - yyps->save->lexeme)); | ||
444 | # endif | ||
445 | /* Memorize most forward-looking error state in case | ||
446 | it's really an error. */ | ||
447 | if(yyerrctx==0 || yyerrctx->lexeme<yylvp-yylvals) { | ||
448 | /* Free old saved error context state */ | ||
449 | if(yyerrctx) yyFreeState(yyerrctx); | ||
450 | /* Create and fill out new saved error context state */ | ||
451 | yyerrctx = yyNewState(yyps->ssp - yyps->ss); | ||
452 | yyerrctx->save = yyps->save; | ||
453 | yyerrctx->state = yystate; | ||
454 | yyerrctx->errflag = yyps->errflag; | ||
455 | yyerrctx->ssp = yyerrctx->ss + (yyps->ssp - yyps->ss); | ||
456 | yyerrctx->vsp = yyerrctx->vs + (yyps->vsp - yyps->vs); | ||
457 | yyerrctx->psp = yyerrctx->ps + (yyps->psp - yyps->ps); | ||
458 | memcpy (yyerrctx->ss, yyps->ss, | ||
459 | (yyps->ssp - yyps->ss + 1) * sizeof(Yshort)); | ||
460 | yySCopy(yyerrctx->vs, yyps->vs, (yyps->ssp - yyps->ss + 1)); | ||
461 | yyPCopy(yyerrctx->ps, yyps->ps, (yyps->ssp - yyps->ss + 1)); | ||
462 | yyerrctx->lexeme = yylvp - yylvals; | ||
463 | } | ||
464 | yylvp = yylvals + save->lexeme; | ||
465 | yylpp = yylpsns + save->lexeme; | ||
466 | yylexp = yylexemes + save->lexeme; | ||
467 | yychar = YYEMPTY; | ||
468 | yyps->ssp = yyps->ss + (save->ssp - save->ss); | ||
469 | yyps->vsp = yyps->vs + (save->vsp - save->vs); | ||
470 | yyps->psp = yyps->ps + (save->psp - save->ps); | ||
471 | memcpy (yyps->ss, save->ss, (yyps->ssp - yyps->ss + 1) * sizeof(Yshort)); | ||
472 | yySCopy(yyps->vs, save->vs, yyps->vsp - yyps->vs + 1); | ||
473 | yyPCopy(yyps->ps, save->ps, yyps->psp - yyps->ps + 1); | ||
474 | ctry = ++save->ctry; | ||
475 | yystate = save->state; | ||
476 | /* We tried shift, try reduce now */ | ||
477 | if ((yyn = yyctable[ctry]) >= 0) { | ||
478 | goto yyreduce; | ||
479 | } | ||
480 | yyps->save = save->save; | ||
481 | yyFreeState(save); | ||
482 | |||
483 | /* Nothing left on the stack -- error */ | ||
484 | if (!yyps->save) { | ||
485 | # if YYDEBUG | ||
486 | if (yydebug) { | ||
487 | fputs("btyacc[trial]: trial parse FAILED, entering ERROR mode\n", | ||
488 | stderr); | ||
489 | } | ||
490 | # endif | ||
491 | /* Restore state as it was in the most forward-advanced error */ | ||
492 | yylvp = yylvals + yyerrctx->lexeme; | ||
493 | yylpp = yylpsns + yyerrctx->lexeme; | ||
494 | yylexp = yylexemes + yyerrctx->lexeme; | ||
495 | yychar = yylexp[-1]; | ||
496 | yylval = yylvp[-1]; | ||
497 | yyposn = yylpp[-1]; | ||
498 | yyps->ssp = yyps->ss + (yyerrctx->ssp - yyerrctx->ss); | ||
499 | yyps->vsp = yyps->vs + (yyerrctx->vsp - yyerrctx->vs); | ||
500 | yyps->psp = yyps->ps + (yyerrctx->psp - yyerrctx->ps); | ||
501 | memcpy (yyps->ss, yyerrctx->ss, | ||
502 | (yyps->ssp - yyps->ss + 1) * sizeof(Yshort)); | ||
503 | yySCopy(yyps->vs, yyerrctx->vs, yyps->vsp - yyps->vs + 1); | ||
504 | yyPCopy(yyps->ps, yyerrctx->ps, yyps->psp - yyps->ps + 1); | ||
505 | yystate = yyerrctx->state; | ||
506 | yyFreeState(yyerrctx); | ||
507 | yyerrctx = 0; | ||
508 | } | ||
509 | yynewerrflag = 1; | ||
510 | } | ||
511 | if (yynewerrflag) { | ||
512 | # ifdef YYERROR_DETAILED | ||
513 | yyerror_detailed("parse error", yychar, yylval, yyposn); | ||
514 | # else | ||
515 | yyerror("parse error"); | ||
516 | # endif | ||
517 | } | ||
518 | ++yynerrs; | ||
519 | yyinrecovery: | ||
520 | if (yyps->errflag < 3) { | ||
521 | yyps->errflag = 3; | ||
522 | for (;;) { | ||
523 | if ((yyn = yysindex[*(yyps->ssp)]) | ||
524 | && (yyn += YYERRCODE) >= 0 | ||
525 | && yyn <= YYTABLESIZE | ||
526 | && yycheck[yyn] == YYERRCODE) { | ||
527 | # if YYDEBUG | ||
528 | if (yydebug) | ||
529 | fprintf(stderr, "btyacc[%3d,%2d%s]: ERROR recovery shifts to " | ||
530 | "state %d\n", | ||
531 | *(yyps->ssp), (int) yydepth, (yytrial ? ",trial" : ""), | ||
532 | yytable[yyn]); | ||
533 | # endif | ||
534 | /* Use label yyerrlab, so that compiler does not warn */ | ||
535 | if(yyps->errflag != yyps->errflag) goto yyerrlab; | ||
536 | yystate = yytable[yyn]; | ||
537 | goto yyshift; | ||
538 | } else { | ||
539 | # if YYDEBUG | ||
540 | if (yydebug) | ||
541 | fprintf(stderr, | ||
542 | "btyacc[%3d,%2d%s]: ERROR recovery discards this state\n", | ||
543 | *(yyps->ssp), (int) yydepth, (yytrial ? ",trial" : "")); | ||
544 | # endif | ||
545 | if (yyps->ssp <= yyps->ss) { | ||
546 | goto yyabort; | ||
547 | } | ||
548 | if(!yytrial) { | ||
549 | YYDELETEVAL(yyps->vsp[0],1); | ||
550 | YYDELETEPOSN(yyps->psp[0],1); | ||
551 | } | ||
552 | --(yyps->ssp); | ||
553 | --(yyps->vsp); | ||
554 | --(yyps->psp); | ||
555 | } | ||
556 | } | ||
557 | } else { | ||
558 | if (yychar == 0) goto yyabort; | ||
559 | # if YYDEBUG | ||
560 | if (yydebug) { | ||
561 | yys = 0; | ||
562 | if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; | ||
563 | if (!yys) yys = "illegal-symbol"; | ||
564 | fprintf(stderr, "btyacc[%3d,%2d%s]: ERROR recovery discards token " | ||
565 | "%d (%s)\n", | ||
566 | yystate, (int) yydepth, (yytrial ? ",trial" : ""), yychar, yys); | ||
567 | } | ||
568 | # endif | ||
569 | if(!yytrial) { | ||
570 | YYDELETEVAL(yylval,0); | ||
571 | YYDELETEPOSN(yyposn,0); | ||
572 | } | ||
573 | yychar = (YYEMPTY); | ||
574 | goto yyloop; | ||
575 | } | ||
576 | |||
577 | /* Reduce the rule */ | ||
578 | yyreduce: | ||
579 | yym = yylen[yyn]; | ||
580 | # if YYDEBUG | ||
581 | if (yydebug) { | ||
582 | fprintf(stderr, "btyacc[%3d,%2d%s]: reducing by rule %d (%s)", | ||
583 | yystate, (int) yydepth, (yytrial ? ",trial" : ""), yyn, yyrule[yyn]); | ||
584 | # ifdef YYDBPR | ||
585 | if (yym) { | ||
586 | int i; | ||
587 | fputc('<', stderr); | ||
588 | for (i=yym; i>0; i--) { | ||
589 | if (i!=yym) printf(", "); | ||
590 | YYDBPR((yyps->vsp)[1-i]); | ||
591 | } | ||
592 | fputc('>', stderr); | ||
593 | } | ||
594 | # endif | ||
595 | fputc('\n', stderr); | ||
596 | } | ||
597 | # endif | ||
598 | if (yyps->ssp + 1 - yym >= yyps->ss + yyps->stacksize) { | ||
599 | yyMoreStack(yyps); | ||
600 | } | ||
601 | |||
602 | # ifdef _YACC_DEFAULT_ACTION_ | ||
603 | /* "$$ = NULL" default action */ | ||
604 | memset(&yyps->val, 0, sizeof(yyps->val)); | ||
605 | # else | ||
606 | /* RA: bison compatibility: default action is '$$ = $1;' */ | ||
607 | if (yym > 0) yyps->val = (yyps->vsp)[1 - yym]; | ||
608 | # endif | ||
609 | |||
610 | /* Default reduced position is NULL -- no position at all. No | ||
611 | position will be assigned at trial time and if no position | ||
612 | handling is present */ | ||
613 | memset(&yyps->pos, 0, sizeof(yyps->pos)); | ||
614 | |||
615 | reduce_posn = 1; | ||
616 | |||
617 | switch (yyn) { | ||
618 | |||
619 | %% trailer | ||
620 | |||
621 | default: | ||
622 | break; | ||
623 | } | ||
624 | |||
625 | # if YYDEBUG && defined(YYDBPR) | ||
626 | if (yydebug) { | ||
627 | fputs("btyacc[trial]: reduced, result is ", stderr); | ||
628 | YYDBPR(yyps->val); | ||
629 | fputc('\n', stderr); | ||
630 | } | ||
631 | # endif | ||
632 | |||
633 | /* Perform user-defined position reduction */ | ||
634 | # ifdef YYREDUCEPOSNFUNC | ||
635 | if(!yytrial) { | ||
636 | YYCALLREDUCEPOSN(YYREDUCEPOSNFUNCARG); | ||
637 | } | ||
638 | # endif | ||
639 | |||
640 | yyps->ssp -= yym; | ||
641 | yystate = *(yyps->ssp); | ||
642 | yyps->vsp -= yym; | ||
643 | yyps->psp -= yym; | ||
644 | |||
645 | yym = yylhs[yyn]; | ||
646 | if (yystate == 0 && yym == 0) { | ||
647 | # if YYDEBUG | ||
648 | if (yydebug) { | ||
649 | fprintf(stderr, | ||
650 | "btyacc[ 0,%2d%s]: reduced, shifting to final state %d\n", | ||
651 | (int) yydepth, (yytrial ? ",trial" : ""), YYFINAL); | ||
652 | } | ||
653 | # endif | ||
654 | yystate = YYFINAL; | ||
655 | *++(yyps->ssp) = YYFINAL; | ||
656 | *++(yyps->vsp) = yyps->val; | ||
657 | yyretlval = yyps->val; /* return value of root non-terminal to yylval */ | ||
658 | *++(yyps->psp) = yyps->pos; | ||
659 | yyretposn = yyps->pos; /* return value of root position to yyposn */ | ||
660 | if (yychar < 0) { | ||
661 | if ((yychar = yyLex1(&yylval, YYLEX_PARAM)) < 0) { | ||
662 | yychar = 0; | ||
663 | } | ||
664 | # if YYDEBUG | ||
665 | if (yydebug) { | ||
666 | yys = 0; | ||
667 | if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; | ||
668 | if (!yys) yys = "illegal-symbol"; | ||
669 | fprintf(stderr, "btyacc[%3d,%2d%s]: read %d (%s)\n", | ||
670 | YYFINAL, (int) yydepth, (yytrial ? ",trial" : ""), yychar, yys); | ||
671 | } | ||
672 | # endif | ||
673 | } | ||
674 | if (yychar == 0) goto yyaccept; | ||
675 | goto yyloop; | ||
676 | } | ||
677 | |||
678 | if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && | ||
679 | yyn <= YYTABLESIZE && yycheck[yyn] == yystate) { | ||
680 | yystate = yytable[yyn]; | ||
681 | } else { | ||
682 | yystate = yydgoto[yym]; | ||
683 | } | ||
684 | # if YYDEBUG | ||
685 | if (yydebug) | ||
686 | fprintf(stderr, "btyacc[%3d,%2d%s]: reduced, shifting to state %d\n", | ||
687 | *(yyps->ssp), (int) yydepth, (yytrial ? ",trial" : ""), yystate); | ||
688 | # endif | ||
689 | if (yyps->ssp >= yyps->ss + yyps->stacksize - 1) { | ||
690 | yyMoreStack(yyps); | ||
691 | } | ||
692 | *++(yyps->ssp) = yystate; | ||
693 | *++(yyps->vsp) = yyps->val; | ||
694 | *++(yyps->psp) = yyps->pos; | ||
695 | goto yyloop; | ||
696 | |||
697 | |||
698 | /* Reduction declares that this path is valid. | ||
699 | Set yypath and do a full parse */ | ||
700 | yyvalid: | ||
701 | if (yypath) { | ||
702 | goto yyabort; | ||
703 | } | ||
704 | while (yyps->save) { | ||
705 | YYParseState *save = yyps->save; | ||
706 | yyps->save = save->save; | ||
707 | save->save = yypath; | ||
708 | yypath = save; | ||
709 | } | ||
710 | # if YYDEBUG | ||
711 | if (yydebug) | ||
712 | fprintf(stderr, "btyacc[%3d,%2d%s]: CONFLICT trial successful, " | ||
713 | "backtracking to state %d, %d tokens\n", | ||
714 | yystate, (int) yydepth, (yytrial ? ",trial" : ""), | ||
715 | yypath->state, (int) (yylvp - yylvals - yypath->lexeme)); | ||
716 | # endif | ||
717 | if(yyerrctx) { | ||
718 | yyFreeState(yyerrctx); yyerrctx = 0; | ||
719 | } | ||
720 | yychar = YYEMPTY; | ||
721 | yyps->ssp = yyps->ss + (yypath->ssp - yypath->ss); | ||
722 | yyps->vsp = yyps->vs + (yypath->vsp - yypath->vs); | ||
723 | yyps->psp = yyps->ps + (yypath->psp - yypath->ps); | ||
724 | memcpy (yyps->ss, yypath->ss, (yyps->ssp - yyps->ss + 1) * sizeof(Yshort)); | ||
725 | yySCopy(yyps->vs, yypath->vs, yyps->vsp - yyps->vs + 1); | ||
726 | yyPCopy(yyps->ps, yypath->ps, yyps->psp - yyps->ps + 1); | ||
727 | yylvp = yylvals + yypath->lexeme; | ||
728 | yylpp = yylpsns + yypath->lexeme; | ||
729 | yylexp = yylexemes + yypath->lexeme; | ||
730 | yystate = yypath->state; | ||
731 | goto yyloop; | ||
732 | |||
733 | |||
734 | yyabort: | ||
735 | { | ||
736 | YYSTYPE *pv; | ||
737 | YYPOSN *pp; | ||
738 | |||
739 | if(yyerrctx) { | ||
740 | yyFreeState(yyerrctx); yyerrctx = 0; | ||
741 | } | ||
742 | |||
743 | for(pv=yyps->vs; pv<yyps->vsp; pv++) { | ||
744 | YYDELETEVAL(*pv,2); | ||
745 | } | ||
746 | |||
747 | for(pp=yyps->ps; pp<yyps->psp; pp++) { | ||
748 | YYDELETEPOSN(*pp,2); | ||
749 | } | ||
750 | |||
751 | while (yyps) { | ||
752 | YYParseState *save = yyps; | ||
753 | yyps = save->save; | ||
754 | yyFreeState(save); | ||
755 | } | ||
756 | while (yypath) { | ||
757 | YYParseState *save = yypath; | ||
758 | yypath = save->save; | ||
759 | yyFreeState(save); | ||
760 | } | ||
761 | return (1); | ||
762 | } | ||
763 | |||
764 | yyaccept: | ||
765 | if (yyps->save) goto yyvalid; | ||
766 | if(yyerrctx) { | ||
767 | yyFreeState(yyerrctx); yyerrctx = 0; | ||
768 | } | ||
769 | while (yyps) { | ||
770 | YYParseState *save = yyps; | ||
771 | yyps = save->save; | ||
772 | yyFreeState(save); | ||
773 | } | ||
774 | while (yypath) { | ||
775 | YYParseState *save = yypath; | ||
776 | yypath = save->save; | ||
777 | yyFreeState(save); | ||
778 | } | ||
779 | return (0); | ||
780 | } | ||
781 | |||
782 | |||
783 | /* Call yylex() unless the token has already been read. */ | ||
784 | static int yyLex1(YYSTYPE *yylval, yyscan_t scanner) { | ||
785 | if(yylvp < yylve) { | ||
786 | /* we're currently re-reading tokens */ | ||
787 | *yylval = *yylvp++; | ||
788 | yyposn = *yylpp++; | ||
789 | return *yylexp++; | ||
790 | } else if(yyps->save) { | ||
791 | /* in trial mode; save scanner results for future parse attempts */ | ||
792 | if(yylvp == yylvlim) | ||
793 | yyExpand(); | ||
794 | *yylexp = yylex(yylval, scanner); | ||
795 | *yylvp++ = *yylval; | ||
796 | yylve++; | ||
797 | *yylpp++ = yyposn; | ||
798 | yylpe++; | ||
799 | return *yylexp++; | ||
800 | } else { /* normal operation, no conflict encountered */ | ||
801 | return yylex(yylval, scanner); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | /* Enlarge lexical value queue */ | ||
806 | static int yyExpand() { | ||
807 | int p = yylvp - yylvals; | ||
808 | int s = yylvlim - yylvals; | ||
809 | s += YYSTACKGROWTH; | ||
810 | { | ||
811 | Yshort *tl = yylexemes; | ||
812 | YYSTYPE *tv = yylvals; | ||
813 | YYPOSN *tp = yylpsns; | ||
814 | # ifdef __cplusplus | ||
815 | yylvals = new YYSTYPE[s]; | ||
816 | yylpsns = new YYPOSN[s]; | ||
817 | yylexemes = new Yshort[s]; | ||
818 | memcpy(yylexemes, tl, (s-YYSTACKGROWTH)*sizeof(Yshort)); | ||
819 | yySCopy(yylvals, tv, s-YYSTACKGROWTH); | ||
820 | yyPCopy(yylpsns, tp, s-YYSTACKGROWTH); | ||
821 | delete[] tl; | ||
822 | delete[] tv; | ||
823 | delete[] tp; | ||
824 | # else | ||
825 | yylvals = (YYSTYPE*)malloc(s * sizeof(YYSTYPE)); | ||
826 | yylpsns = (YYPOSN*)malloc(s * sizeof(YYPOSN)); | ||
827 | yylexemes = (Yshort*)malloc(s * sizeof(Yshort)); | ||
828 | memcpy(yylexemes, tl, (s - YYSTACKGROWTH)*sizeof(Yshort)); | ||
829 | yySCopy(yylvals, tv, s - YYSTACKGROWTH); | ||
830 | yyPCopy(yylpsns, tp, s - YYSTACKGROWTH); | ||
831 | free(tl); | ||
832 | free(tv); | ||
833 | free(tp); | ||
834 | # endif | ||
835 | } | ||
836 | yylvp = yylve = yylvals + p; | ||
837 | yylvlim = yylvals + s; | ||
838 | yylpp = yylpe = yylpsns + p; | ||
839 | yylplim = yylpsns + s; | ||
840 | yylexp = yylexemes + p; | ||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | static void yySCopy(YYSTYPE *to, YYSTYPE *from, int size) { | ||
845 | int i; | ||
846 | for (i = size-1; i >= 0; i--) { | ||
847 | to[i] = from[i]; | ||
848 | } | ||
849 | } | ||
850 | |||
851 | static void yyPCopy(YYPOSN *to, YYPOSN *from, int size) { | ||
852 | int i; | ||
853 | for (i = size-1; i >= 0; i--) { | ||
854 | to[i] = from[i]; | ||
855 | } | ||
856 | } | ||
857 | |||
858 | static void yyMoreStack(YYParseState *yyps) { | ||
859 | int p = yyps->ssp - yyps->ss; | ||
860 | Yshort *tss = yyps->ss; | ||
861 | YYSTYPE *tvs = yyps->vs; | ||
862 | YYPOSN *tps = yyps->ps; | ||
863 | int newSize = yyps->stacksize + YYSTACKGROWTH; | ||
864 | |||
865 | # ifdef __cplusplus | ||
866 | yyps->ss = new Yshort [newSize]; | ||
867 | yyps->vs = new YYSTYPE[newSize]; | ||
868 | yyps->ps = new YYPOSN [newSize]; | ||
869 | memcpy(yyps->ss, tss, yyps->stacksize * sizeof(Yshort)); | ||
870 | yySCopy(yyps->vs, tvs, yyps->stacksize); | ||
871 | yyPCopy(yyps->ps, tps, yyps->stacksize); | ||
872 | yyps->stacksize += YYSTACKGROWTH; | ||
873 | delete[] tss; | ||
874 | delete[] tvs; | ||
875 | delete[] tps; | ||
876 | # else | ||
877 | yyps->ss = (Yshort*) malloc(newSize * sizeof(Yshort)); | ||
878 | yyps->vs = (YYSTYPE*)malloc(newSize * sizeof(YYSTYPE)); | ||
879 | yyps->ps = (YYPOSN*) malloc(newSize * sizeof(YYPOSN)); | ||
880 | memcpy(yyps->ss, tss, yyps->stacksize * sizeof(Yshort)); | ||
881 | yySCopy(yyps->vs, tvs, yyps->stacksize); | ||
882 | yyPCopy(yyps->ps, tps, yyps->stacksize); | ||
883 | yyps->stacksize += YYSTACKGROWTH; | ||
884 | free(tss); | ||
885 | free(tvs); | ||
886 | free(tps); | ||
887 | # endif | ||
888 | yyps->ssp = yyps->ss + p; | ||
889 | yyps->vsp = yyps->vs + p; | ||
890 | yyps->psp = yyps->ps + p; | ||
891 | # if YYDEBUG | ||
892 | if (yydebug) | ||
893 | fprintf(stderr, "btyacc: stack size increased to %d\n", yyps->stacksize); | ||
894 | # endif | ||
895 | } | ||
896 | |||
897 | |||
898 | #ifdef __cplusplus | ||
899 | |||
900 | static YYParseState *yyNewState(int size) { | ||
901 | YYParseState *p = new YYParseState; | ||
902 | p->stacksize = size+4; | ||
903 | p->ss = new Yshort [size + 4]; | ||
904 | p->vs = new YYSTYPE[size + 4]; | ||
905 | p->ps = new YYPOSN [size + 4]; | ||
906 | memset(&p->vs[0], 0, (size+4)*sizeof(YYSTYPE)); | ||
907 | memset(&p->ps[0], 0, (size+4)*sizeof(YYPOSN)); | ||
908 | return p; | ||
909 | } | ||
910 | |||
911 | static void yyFreeState(YYParseState *p) { | ||
912 | delete[] p->ss; | ||
913 | delete[] p->vs; | ||
914 | delete[] p->ps; | ||
915 | delete p; | ||
916 | } | ||
917 | |||
918 | #else /* not __cplusplus */ | ||
919 | |||
920 | static YYParseState *yyNewState(int size) { | ||
921 | YYParseState *p = (YYParseState*)malloc(sizeof(YYParseState)); | ||
922 | |||
923 | p->stacksize = size+4; | ||
924 | p->ss = (Yshort*) malloc((size + 4) * sizeof(Yshort)); | ||
925 | p->vs = (YYSTYPE*)malloc((size + 4) * sizeof(YYSTYPE)); | ||
926 | p->ps = (YYPOSN*) malloc((size + 4) * sizeof(YYPOSN)); | ||
927 | memset(&p->vs[0], 0, (size+4)*sizeof(YYSTYPE)); | ||
928 | memset(&p->ps[0], 0, (size+4)*sizeof(YYPOSN)); | ||
929 | return p; | ||
930 | } | ||
931 | |||
932 | static void yyFreeState(YYParseState *p) { | ||
933 | free(p->ss); | ||
934 | free(p->vs); | ||
935 | free(p->ps); | ||
936 | free(p); | ||
937 | } | ||
938 | |||
939 | #endif | ||
diff --git a/LuaSL/src/fonts/Vera.ttf b/LuaSL/src/fonts/Vera.ttf deleted file mode 100644 index 58cd6b5..0000000 --- a/LuaSL/src/fonts/Vera.ttf +++ /dev/null | |||
Binary files differ | |||
diff --git a/LuaSL/src/lemon.c b/LuaSL/src/lemon.c new file mode 100644 index 0000000..a089bc7 --- /dev/null +++ b/LuaSL/src/lemon.c | |||
@@ -0,0 +1,4898 @@ | |||
1 | /* | ||
2 | ** This file contains all sources (including headers) to the LEMON | ||
3 | ** LALR(1) parser generator. The sources have been combined into a | ||
4 | ** single file to make it easy to include LEMON in the source tree | ||
5 | ** and Makefile of another program. | ||
6 | ** | ||
7 | ** The author of this program disclaims copyright. | ||
8 | */ | ||
9 | #include <stdio.h> | ||
10 | #include <stdarg.h> | ||
11 | #include <string.h> | ||
12 | #include <ctype.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <assert.h> | ||
15 | |||
16 | #ifndef __WIN32__ | ||
17 | # if defined(_WIN32) || defined(WIN32) | ||
18 | # define __WIN32__ | ||
19 | # endif | ||
20 | #endif | ||
21 | |||
22 | #ifdef __WIN32__ | ||
23 | #ifdef __cplusplus | ||
24 | extern "C" { | ||
25 | #endif | ||
26 | extern int access(const char *path, int mode); | ||
27 | #ifdef __cplusplus | ||
28 | } | ||
29 | #endif | ||
30 | #else | ||
31 | #include <unistd.h> | ||
32 | #endif | ||
33 | |||
34 | /* #define PRIVATE static */ | ||
35 | #define PRIVATE | ||
36 | |||
37 | #ifdef TEST | ||
38 | #define MAXRHS 5 /* Set low to exercise exception code */ | ||
39 | #else | ||
40 | #define MAXRHS 1000 | ||
41 | #endif | ||
42 | |||
43 | static int showPrecedenceConflict = 0; | ||
44 | static char *msort(char*,char**,int(*)(const char*,const char*)); | ||
45 | |||
46 | /* | ||
47 | ** Compilers are getting increasingly pedantic about type conversions | ||
48 | ** as C evolves ever closer to Ada.... To work around the latest problems | ||
49 | ** we have to define the following variant of strlen(). | ||
50 | */ | ||
51 | #define lemonStrlen(X) ((int)strlen(X)) | ||
52 | |||
53 | /* a few forward declarations... */ | ||
54 | struct rule; | ||
55 | struct lemon; | ||
56 | struct action; | ||
57 | |||
58 | static struct action *Action_new(void); | ||
59 | static struct action *Action_sort(struct action *); | ||
60 | |||
61 | /********** From the file "build.h" ************************************/ | ||
62 | void FindRulePrecedences(); | ||
63 | void FindFirstSets(); | ||
64 | void FindStates(); | ||
65 | void FindLinks(); | ||
66 | void FindFollowSets(); | ||
67 | void FindActions(); | ||
68 | |||
69 | /********* From the file "configlist.h" *********************************/ | ||
70 | void Configlist_init(void); | ||
71 | struct config *Configlist_add(struct rule *, int); | ||
72 | struct config *Configlist_addbasis(struct rule *, int); | ||
73 | void Configlist_closure(struct lemon *); | ||
74 | void Configlist_sort(void); | ||
75 | void Configlist_sortbasis(void); | ||
76 | struct config *Configlist_return(void); | ||
77 | struct config *Configlist_basis(void); | ||
78 | void Configlist_eat(struct config *); | ||
79 | void Configlist_reset(void); | ||
80 | |||
81 | /********* From the file "error.h" ***************************************/ | ||
82 | void ErrorMsg(const char *, int,const char *, ...); | ||
83 | |||
84 | /****** From the file "option.h" ******************************************/ | ||
85 | enum option_type { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, | ||
86 | OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR}; | ||
87 | struct s_options { | ||
88 | enum option_type type; | ||
89 | const char *label; | ||
90 | char *arg; | ||
91 | const char *message; | ||
92 | }; | ||
93 | int OptInit(char**,struct s_options*,FILE*); | ||
94 | int OptNArgs(void); | ||
95 | char *OptArg(int); | ||
96 | void OptErr(int); | ||
97 | void OptPrint(void); | ||
98 | |||
99 | /******** From the file "parse.h" *****************************************/ | ||
100 | void Parse(struct lemon *lemp); | ||
101 | |||
102 | /********* From the file "plink.h" ***************************************/ | ||
103 | struct plink *Plink_new(void); | ||
104 | void Plink_add(struct plink **, struct config *); | ||
105 | void Plink_copy(struct plink **, struct plink *); | ||
106 | void Plink_delete(struct plink *); | ||
107 | |||
108 | /********** From the file "report.h" *************************************/ | ||
109 | void Reprint(struct lemon *); | ||
110 | void ReportOutput(struct lemon *); | ||
111 | void ReportTable(struct lemon *, int); | ||
112 | void ReportHeader(struct lemon *); | ||
113 | void CompressTables(struct lemon *); | ||
114 | void ResortStates(struct lemon *); | ||
115 | |||
116 | /********** From the file "set.h" ****************************************/ | ||
117 | void SetSize(int); /* All sets will be of size N */ | ||
118 | char *SetNew(void); /* A new set for element 0..N */ | ||
119 | void SetFree(char*); /* Deallocate a set */ | ||
120 | |||
121 | char *SetNew(void); /* A new set for element 0..N */ | ||
122 | int SetAdd(char*,int); /* Add element to a set */ | ||
123 | int SetUnion(char *,char *); /* A <- A U B, thru element N */ | ||
124 | #define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ | ||
125 | |||
126 | /********** From the file "struct.h" *************************************/ | ||
127 | /* | ||
128 | ** Principal data structures for the LEMON parser generator. | ||
129 | */ | ||
130 | |||
131 | typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean; | ||
132 | |||
133 | /* Symbols (terminals and nonterminals) of the grammar are stored | ||
134 | ** in the following: */ | ||
135 | enum symbol_type { | ||
136 | TERMINAL, | ||
137 | NONTERMINAL, | ||
138 | MULTITERMINAL | ||
139 | }; | ||
140 | enum e_assoc { | ||
141 | LEFT, | ||
142 | RIGHT, | ||
143 | NONE, | ||
144 | UNK | ||
145 | }; | ||
146 | struct symbol { | ||
147 | const char *name; /* Name of the symbol */ | ||
148 | int index; /* Index number for this symbol */ | ||
149 | enum symbol_type type; /* Symbols are all either TERMINALS or NTs */ | ||
150 | struct rule *rule; /* Linked list of rules of this (if an NT) */ | ||
151 | struct symbol *fallback; /* fallback token in case this token doesn't parse */ | ||
152 | int prec; /* Precedence if defined (-1 otherwise) */ | ||
153 | enum e_assoc assoc; /* Associativity if precedence is defined */ | ||
154 | char *firstset; /* First-set for all rules of this symbol */ | ||
155 | Boolean lambda; /* True if NT and can generate an empty string */ | ||
156 | int useCnt; /* Number of times used */ | ||
157 | char *destructor; /* Code which executes whenever this symbol is | ||
158 | ** popped from the stack during error processing */ | ||
159 | int destLineno; /* Line number for start of destructor */ | ||
160 | char *datatype; /* The data type of information held by this | ||
161 | ** object. Only used if type==NONTERMINAL */ | ||
162 | int dtnum; /* The data type number. In the parser, the value | ||
163 | ** stack is a union. The .yy%d element of this | ||
164 | ** union is the correct data type for this object */ | ||
165 | /* The following fields are used by MULTITERMINALs only */ | ||
166 | int nsubsym; /* Number of constituent symbols in the MULTI */ | ||
167 | struct symbol **subsym; /* Array of constituent symbols */ | ||
168 | }; | ||
169 | |||
170 | /* Each production rule in the grammar is stored in the following | ||
171 | ** structure. */ | ||
172 | struct rule { | ||
173 | struct symbol *lhs; /* Left-hand side of the rule */ | ||
174 | const char *lhsalias; /* Alias for the LHS (NULL if none) */ | ||
175 | int lhsStart; /* True if left-hand side is the start symbol */ | ||
176 | int ruleline; /* Line number for the rule */ | ||
177 | int nrhs; /* Number of RHS symbols */ | ||
178 | struct symbol **rhs; /* The RHS symbols */ | ||
179 | const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ | ||
180 | int line; /* Line number at which code begins */ | ||
181 | const char *code; /* The code executed when this rule is reduced */ | ||
182 | struct symbol *precsym; /* Precedence symbol for this rule */ | ||
183 | int index; /* An index number for this rule */ | ||
184 | Boolean canReduce; /* True if this rule is ever reduced */ | ||
185 | struct rule *nextlhs; /* Next rule with the same LHS */ | ||
186 | struct rule *next; /* Next rule in the global list */ | ||
187 | }; | ||
188 | |||
189 | /* A configuration is a production rule of the grammar together with | ||
190 | ** a mark (dot) showing how much of that rule has been processed so far. | ||
191 | ** Configurations also contain a follow-set which is a list of terminal | ||
192 | ** symbols which are allowed to immediately follow the end of the rule. | ||
193 | ** Every configuration is recorded as an instance of the following: */ | ||
194 | enum cfgstatus { | ||
195 | COMPLETE, | ||
196 | INCOMPLETE | ||
197 | }; | ||
198 | struct config { | ||
199 | struct rule *rp; /* The rule upon which the configuration is based */ | ||
200 | int dot; /* The parse point */ | ||
201 | char *fws; /* Follow-set for this configuration only */ | ||
202 | struct plink *fplp; /* Follow-set forward propagation links */ | ||
203 | struct plink *bplp; /* Follow-set backwards propagation links */ | ||
204 | struct state *stp; /* Pointer to state which contains this */ | ||
205 | enum cfgstatus status; /* used during followset and shift computations */ | ||
206 | struct config *next; /* Next configuration in the state */ | ||
207 | struct config *bp; /* The next basis configuration */ | ||
208 | }; | ||
209 | |||
210 | enum e_action { | ||
211 | SHIFT, | ||
212 | ACCEPT, | ||
213 | REDUCE, | ||
214 | ERROR, | ||
215 | SSCONFLICT, /* A shift/shift conflict */ | ||
216 | SRCONFLICT, /* Was a reduce, but part of a conflict */ | ||
217 | RRCONFLICT, /* Was a reduce, but part of a conflict */ | ||
218 | SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ | ||
219 | RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ | ||
220 | NOT_USED /* Deleted by compression */ | ||
221 | }; | ||
222 | |||
223 | /* Every shift or reduce operation is stored as one of the following */ | ||
224 | struct action { | ||
225 | struct symbol *sp; /* The look-ahead symbol */ | ||
226 | enum e_action type; | ||
227 | union { | ||
228 | struct state *stp; /* The new state, if a shift */ | ||
229 | struct rule *rp; /* The rule, if a reduce */ | ||
230 | } x; | ||
231 | struct action *next; /* Next action for this state */ | ||
232 | struct action *collide; /* Next action with the same hash */ | ||
233 | }; | ||
234 | |||
235 | /* Each state of the generated parser's finite state machine | ||
236 | ** is encoded as an instance of the following structure. */ | ||
237 | struct state { | ||
238 | struct config *bp; /* The basis configurations for this state */ | ||
239 | struct config *cfp; /* All configurations in this set */ | ||
240 | int statenum; /* Sequential number for this state */ | ||
241 | struct action *ap; /* Array of actions for this state */ | ||
242 | int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ | ||
243 | int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ | ||
244 | int iDflt; /* Default action */ | ||
245 | }; | ||
246 | #define NO_OFFSET (-2147483647) | ||
247 | |||
248 | /* A followset propagation link indicates that the contents of one | ||
249 | ** configuration followset should be propagated to another whenever | ||
250 | ** the first changes. */ | ||
251 | struct plink { | ||
252 | struct config *cfp; /* The configuration to which linked */ | ||
253 | struct plink *next; /* The next propagate link */ | ||
254 | }; | ||
255 | |||
256 | /* The state vector for the entire parser generator is recorded as | ||
257 | ** follows. (LEMON uses no global variables and makes little use of | ||
258 | ** static variables. Fields in the following structure can be thought | ||
259 | ** of as begin global variables in the program.) */ | ||
260 | struct lemon { | ||
261 | struct state **sorted; /* Table of states sorted by state number */ | ||
262 | struct rule *rule; /* List of all rules */ | ||
263 | int nstate; /* Number of states */ | ||
264 | int nrule; /* Number of rules */ | ||
265 | int nsymbol; /* Number of terminal and nonterminal symbols */ | ||
266 | int nterminal; /* Number of terminal symbols */ | ||
267 | struct symbol **symbols; /* Sorted array of pointers to symbols */ | ||
268 | int errorcnt; /* Number of errors */ | ||
269 | struct symbol *errsym; /* The error symbol */ | ||
270 | struct symbol *wildcard; /* Token that matches anything */ | ||
271 | char *name; /* Name of the generated parser */ | ||
272 | char *arg; /* Declaration of the 3th argument to parser */ | ||
273 | char *tokentype; /* Type of terminal symbols in the parser stack */ | ||
274 | char *vartype; /* The default type of non-terminal symbols */ | ||
275 | char *start; /* Name of the start symbol for the grammar */ | ||
276 | char *stacksize; /* Size of the parser stack */ | ||
277 | char *include; /* Code to put at the start of the C file */ | ||
278 | char *error; /* Code to execute when an error is seen */ | ||
279 | char *overflow; /* Code to execute on a stack overflow */ | ||
280 | char *failure; /* Code to execute on parser failure */ | ||
281 | char *accept; /* Code to execute when the parser excepts */ | ||
282 | char *extracode; /* Code appended to the generated file */ | ||
283 | char *tokendest; /* Code to execute to destroy token data */ | ||
284 | char *vardest; /* Code for the default non-terminal destructor */ | ||
285 | char *filename; /* Name of the input file */ | ||
286 | char *outname; /* Name of the current output file */ | ||
287 | char *tokenprefix; /* A prefix added to token names in the .h file */ | ||
288 | int nconflict; /* Number of parsing conflicts */ | ||
289 | int tablesize; /* Size of the parse tables */ | ||
290 | int basisflag; /* Print only basis configurations */ | ||
291 | int has_fallback; /* True if any %fallback is seen in the grammar */ | ||
292 | int nolinenosflag; /* True if #line statements should not be printed */ | ||
293 | char *argv0; /* Name of the program */ | ||
294 | }; | ||
295 | |||
296 | #define MemoryCheck(X) if((X)==0){ \ | ||
297 | extern void memory_error(); \ | ||
298 | memory_error(); \ | ||
299 | } | ||
300 | |||
301 | /**************** From the file "table.h" *********************************/ | ||
302 | /* | ||
303 | ** All code in this file has been automatically generated | ||
304 | ** from a specification in the file | ||
305 | ** "table.q" | ||
306 | ** by the associative array code building program "aagen". | ||
307 | ** Do not edit this file! Instead, edit the specification | ||
308 | ** file, then rerun aagen. | ||
309 | */ | ||
310 | /* | ||
311 | ** Code for processing tables in the LEMON parser generator. | ||
312 | */ | ||
313 | /* Routines for handling a strings */ | ||
314 | |||
315 | const char *Strsafe(const char *); | ||
316 | |||
317 | void Strsafe_init(void); | ||
318 | int Strsafe_insert(const char *); | ||
319 | const char *Strsafe_find(const char *); | ||
320 | |||
321 | /* Routines for handling symbols of the grammar */ | ||
322 | |||
323 | struct symbol *Symbol_new(const char *); | ||
324 | int Symbolcmpp(const void *, const void *); | ||
325 | void Symbol_init(void); | ||
326 | int Symbol_insert(struct symbol *, const char *); | ||
327 | struct symbol *Symbol_find(const char *); | ||
328 | struct symbol *Symbol_Nth(int); | ||
329 | int Symbol_count(void); | ||
330 | struct symbol **Symbol_arrayof(void); | ||
331 | |||
332 | /* Routines to manage the state table */ | ||
333 | |||
334 | int Configcmp(const char *, const char *); | ||
335 | struct state *State_new(void); | ||
336 | void State_init(void); | ||
337 | int State_insert(struct state *, struct config *); | ||
338 | struct state *State_find(struct config *); | ||
339 | struct state **State_arrayof(/* */); | ||
340 | |||
341 | /* Routines used for efficiency in Configlist_add */ | ||
342 | |||
343 | void Configtable_init(void); | ||
344 | int Configtable_insert(struct config *); | ||
345 | struct config *Configtable_find(struct config *); | ||
346 | void Configtable_clear(int(*)(struct config *)); | ||
347 | |||
348 | /****************** From the file "action.c" *******************************/ | ||
349 | /* | ||
350 | ** Routines processing parser actions in the LEMON parser generator. | ||
351 | */ | ||
352 | |||
353 | /* Allocate a new parser action */ | ||
354 | static struct action *Action_new(void){ | ||
355 | static struct action *freelist = 0; | ||
356 | struct action *newaction; | ||
357 | |||
358 | if( freelist==0 ){ | ||
359 | int i; | ||
360 | int amt = 100; | ||
361 | freelist = (struct action *)calloc(amt, sizeof(struct action)); | ||
362 | if( freelist==0 ){ | ||
363 | fprintf(stderr,"Unable to allocate memory for a new parser action."); | ||
364 | exit(1); | ||
365 | } | ||
366 | for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; | ||
367 | freelist[amt-1].next = 0; | ||
368 | } | ||
369 | newaction = freelist; | ||
370 | freelist = freelist->next; | ||
371 | return newaction; | ||
372 | } | ||
373 | |||
374 | /* Compare two actions for sorting purposes. Return negative, zero, or | ||
375 | ** positive if the first action is less than, equal to, or greater than | ||
376 | ** the first | ||
377 | */ | ||
378 | static int actioncmp( | ||
379 | struct action *ap1, | ||
380 | struct action *ap2 | ||
381 | ){ | ||
382 | int rc; | ||
383 | rc = ap1->sp->index - ap2->sp->index; | ||
384 | if( rc==0 ){ | ||
385 | rc = (int)ap1->type - (int)ap2->type; | ||
386 | } | ||
387 | if( rc==0 && ap1->type==REDUCE ){ | ||
388 | rc = ap1->x.rp->index - ap2->x.rp->index; | ||
389 | } | ||
390 | if( rc==0 ){ | ||
391 | rc = (int) (ap2 - ap1); | ||
392 | } | ||
393 | return rc; | ||
394 | } | ||
395 | |||
396 | /* Sort parser actions */ | ||
397 | static struct action *Action_sort( | ||
398 | struct action *ap | ||
399 | ){ | ||
400 | ap = (struct action *)msort((char *)ap,(char **)&ap->next, | ||
401 | (int(*)(const char*,const char*))actioncmp); | ||
402 | return ap; | ||
403 | } | ||
404 | |||
405 | void Action_add( | ||
406 | struct action **app, | ||
407 | enum e_action type, | ||
408 | struct symbol *sp, | ||
409 | char *arg | ||
410 | ){ | ||
411 | struct action *newaction; | ||
412 | newaction = Action_new(); | ||
413 | newaction->next = *app; | ||
414 | *app = newaction; | ||
415 | newaction->type = type; | ||
416 | newaction->sp = sp; | ||
417 | if( type==SHIFT ){ | ||
418 | newaction->x.stp = (struct state *)arg; | ||
419 | }else{ | ||
420 | newaction->x.rp = (struct rule *)arg; | ||
421 | } | ||
422 | } | ||
423 | /********************** New code to implement the "acttab" module ***********/ | ||
424 | /* | ||
425 | ** This module implements routines use to construct the yy_action[] table. | ||
426 | */ | ||
427 | |||
428 | /* | ||
429 | ** The state of the yy_action table under construction is an instance of | ||
430 | ** the following structure. | ||
431 | ** | ||
432 | ** The yy_action table maps the pair (state_number, lookahead) into an | ||
433 | ** action_number. The table is an array of integers pairs. The state_number | ||
434 | ** determines an initial offset into the yy_action array. The lookahead | ||
435 | ** value is then added to this initial offset to get an index X into the | ||
436 | ** yy_action array. If the aAction[X].lookahead equals the value of the | ||
437 | ** of the lookahead input, then the value of the action_number output is | ||
438 | ** aAction[X].action. If the lookaheads do not match then the | ||
439 | ** default action for the state_number is returned. | ||
440 | ** | ||
441 | ** All actions associated with a single state_number are first entered | ||
442 | ** into aLookahead[] using multiple calls to acttab_action(). Then the | ||
443 | ** actions for that single state_number are placed into the aAction[] | ||
444 | ** array with a single call to acttab_insert(). The acttab_insert() call | ||
445 | ** also resets the aLookahead[] array in preparation for the next | ||
446 | ** state number. | ||
447 | */ | ||
448 | struct lookahead_action { | ||
449 | int lookahead; /* Value of the lookahead token */ | ||
450 | int action; /* Action to take on the given lookahead */ | ||
451 | }; | ||
452 | typedef struct acttab acttab; | ||
453 | struct acttab { | ||
454 | int nAction; /* Number of used slots in aAction[] */ | ||
455 | int nActionAlloc; /* Slots allocated for aAction[] */ | ||
456 | struct lookahead_action | ||
457 | *aAction, /* The yy_action[] table under construction */ | ||
458 | *aLookahead; /* A single new transaction set */ | ||
459 | int mnLookahead; /* Minimum aLookahead[].lookahead */ | ||
460 | int mnAction; /* Action associated with mnLookahead */ | ||
461 | int mxLookahead; /* Maximum aLookahead[].lookahead */ | ||
462 | int nLookahead; /* Used slots in aLookahead[] */ | ||
463 | int nLookaheadAlloc; /* Slots allocated in aLookahead[] */ | ||
464 | }; | ||
465 | |||
466 | /* Return the number of entries in the yy_action table */ | ||
467 | #define acttab_size(X) ((X)->nAction) | ||
468 | |||
469 | /* The value for the N-th entry in yy_action */ | ||
470 | #define acttab_yyaction(X,N) ((X)->aAction[N].action) | ||
471 | |||
472 | /* The value for the N-th entry in yy_lookahead */ | ||
473 | #define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead) | ||
474 | |||
475 | /* Free all memory associated with the given acttab */ | ||
476 | void acttab_free(acttab *p){ | ||
477 | free( p->aAction ); | ||
478 | free( p->aLookahead ); | ||
479 | free( p ); | ||
480 | } | ||
481 | |||
482 | /* Allocate a new acttab structure */ | ||
483 | acttab *acttab_alloc(void){ | ||
484 | acttab *p = (acttab *) calloc( 1, sizeof(*p) ); | ||
485 | if( p==0 ){ | ||
486 | fprintf(stderr,"Unable to allocate memory for a new acttab."); | ||
487 | exit(1); | ||
488 | } | ||
489 | memset(p, 0, sizeof(*p)); | ||
490 | return p; | ||
491 | } | ||
492 | |||
493 | /* Add a new action to the current transaction set. | ||
494 | ** | ||
495 | ** This routine is called once for each lookahead for a particular | ||
496 | ** state. | ||
497 | */ | ||
498 | void acttab_action(acttab *p, int lookahead, int action){ | ||
499 | if( p->nLookahead>=p->nLookaheadAlloc ){ | ||
500 | p->nLookaheadAlloc += 25; | ||
501 | p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead, | ||
502 | sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); | ||
503 | if( p->aLookahead==0 ){ | ||
504 | fprintf(stderr,"malloc failed\n"); | ||
505 | exit(1); | ||
506 | } | ||
507 | } | ||
508 | if( p->nLookahead==0 ){ | ||
509 | p->mxLookahead = lookahead; | ||
510 | p->mnLookahead = lookahead; | ||
511 | p->mnAction = action; | ||
512 | }else{ | ||
513 | if( p->mxLookahead<lookahead ) p->mxLookahead = lookahead; | ||
514 | if( p->mnLookahead>lookahead ){ | ||
515 | p->mnLookahead = lookahead; | ||
516 | p->mnAction = action; | ||
517 | } | ||
518 | } | ||
519 | p->aLookahead[p->nLookahead].lookahead = lookahead; | ||
520 | p->aLookahead[p->nLookahead].action = action; | ||
521 | p->nLookahead++; | ||
522 | } | ||
523 | |||
524 | /* | ||
525 | ** Add the transaction set built up with prior calls to acttab_action() | ||
526 | ** into the current action table. Then reset the transaction set back | ||
527 | ** to an empty set in preparation for a new round of acttab_action() calls. | ||
528 | ** | ||
529 | ** Return the offset into the action table of the new transaction. | ||
530 | */ | ||
531 | int acttab_insert(acttab *p){ | ||
532 | int i, j, k, n; | ||
533 | assert( p->nLookahead>0 ); | ||
534 | |||
535 | /* Make sure we have enough space to hold the expanded action table | ||
536 | ** in the worst case. The worst case occurs if the transaction set | ||
537 | ** must be appended to the current action table | ||
538 | */ | ||
539 | n = p->mxLookahead + 1; | ||
540 | if( p->nAction + n >= p->nActionAlloc ){ | ||
541 | int oldAlloc = p->nActionAlloc; | ||
542 | p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20; | ||
543 | p->aAction = (struct lookahead_action *) realloc( p->aAction, | ||
544 | sizeof(p->aAction[0])*p->nActionAlloc); | ||
545 | if( p->aAction==0 ){ | ||
546 | fprintf(stderr,"malloc failed\n"); | ||
547 | exit(1); | ||
548 | } | ||
549 | for(i=oldAlloc; i<p->nActionAlloc; i++){ | ||
550 | p->aAction[i].lookahead = -1; | ||
551 | p->aAction[i].action = -1; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | /* Scan the existing action table looking for an offset that is a | ||
556 | ** duplicate of the current transaction set. Fall out of the loop | ||
557 | ** if and when the duplicate is found. | ||
558 | ** | ||
559 | ** i is the index in p->aAction[] where p->mnLookahead is inserted. | ||
560 | */ | ||
561 | for(i=p->nAction-1; i>=0; i--){ | ||
562 | if( p->aAction[i].lookahead==p->mnLookahead ){ | ||
563 | /* All lookaheads and actions in the aLookahead[] transaction | ||
564 | ** must match against the candidate aAction[i] entry. */ | ||
565 | if( p->aAction[i].action!=p->mnAction ) continue; | ||
566 | for(j=0; j<p->nLookahead; j++){ | ||
567 | k = p->aLookahead[j].lookahead - p->mnLookahead + i; | ||
568 | if( k<0 || k>=p->nAction ) break; | ||
569 | if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break; | ||
570 | if( p->aLookahead[j].action!=p->aAction[k].action ) break; | ||
571 | } | ||
572 | if( j<p->nLookahead ) continue; | ||
573 | |||
574 | /* No possible lookahead value that is not in the aLookahead[] | ||
575 | ** transaction is allowed to match aAction[i] */ | ||
576 | n = 0; | ||
577 | for(j=0; j<p->nAction; j++){ | ||
578 | if( p->aAction[j].lookahead<0 ) continue; | ||
579 | if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++; | ||
580 | } | ||
581 | if( n==p->nLookahead ){ | ||
582 | break; /* An exact match is found at offset i */ | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | /* If no existing offsets exactly match the current transaction, find an | ||
588 | ** an empty offset in the aAction[] table in which we can add the | ||
589 | ** aLookahead[] transaction. | ||
590 | */ | ||
591 | if( i<0 ){ | ||
592 | /* Look for holes in the aAction[] table that fit the current | ||
593 | ** aLookahead[] transaction. Leave i set to the offset of the hole. | ||
594 | ** If no holes are found, i is left at p->nAction, which means the | ||
595 | ** transaction will be appended. */ | ||
596 | for(i=0; i<p->nActionAlloc - p->mxLookahead; i++){ | ||
597 | if( p->aAction[i].lookahead<0 ){ | ||
598 | for(j=0; j<p->nLookahead; j++){ | ||
599 | k = p->aLookahead[j].lookahead - p->mnLookahead + i; | ||
600 | if( k<0 ) break; | ||
601 | if( p->aAction[k].lookahead>=0 ) break; | ||
602 | } | ||
603 | if( j<p->nLookahead ) continue; | ||
604 | for(j=0; j<p->nAction; j++){ | ||
605 | if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; | ||
606 | } | ||
607 | if( j==p->nAction ){ | ||
608 | break; /* Fits in empty slots */ | ||
609 | } | ||
610 | } | ||
611 | } | ||
612 | } | ||
613 | /* Insert transaction set at index i. */ | ||
614 | for(j=0; j<p->nLookahead; j++){ | ||
615 | k = p->aLookahead[j].lookahead - p->mnLookahead + i; | ||
616 | p->aAction[k] = p->aLookahead[j]; | ||
617 | if( k>=p->nAction ) p->nAction = k+1; | ||
618 | } | ||
619 | p->nLookahead = 0; | ||
620 | |||
621 | /* Return the offset that is added to the lookahead in order to get the | ||
622 | ** index into yy_action of the action */ | ||
623 | return i - p->mnLookahead; | ||
624 | } | ||
625 | |||
626 | /********************** From the file "build.c" *****************************/ | ||
627 | /* | ||
628 | ** Routines to construction the finite state machine for the LEMON | ||
629 | ** parser generator. | ||
630 | */ | ||
631 | |||
632 | /* Find a precedence symbol of every rule in the grammar. | ||
633 | ** | ||
634 | ** Those rules which have a precedence symbol coded in the input | ||
635 | ** grammar using the "[symbol]" construct will already have the | ||
636 | ** rp->precsym field filled. Other rules take as their precedence | ||
637 | ** symbol the first RHS symbol with a defined precedence. If there | ||
638 | ** are not RHS symbols with a defined precedence, the precedence | ||
639 | ** symbol field is left blank. | ||
640 | */ | ||
641 | void FindRulePrecedences(struct lemon *xp) | ||
642 | { | ||
643 | struct rule *rp; | ||
644 | for(rp=xp->rule; rp; rp=rp->next){ | ||
645 | if( rp->precsym==0 ){ | ||
646 | int i, j; | ||
647 | for(i=0; i<rp->nrhs && rp->precsym==0; i++){ | ||
648 | struct symbol *sp = rp->rhs[i]; | ||
649 | if( sp->type==MULTITERMINAL ){ | ||
650 | for(j=0; j<sp->nsubsym; j++){ | ||
651 | if( sp->subsym[j]->prec>=0 ){ | ||
652 | rp->precsym = sp->subsym[j]; | ||
653 | break; | ||
654 | } | ||
655 | } | ||
656 | }else if( sp->prec>=0 ){ | ||
657 | rp->precsym = rp->rhs[i]; | ||
658 | } | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | return; | ||
663 | } | ||
664 | |||
665 | /* Find all nonterminals which will generate the empty string. | ||
666 | ** Then go back and compute the first sets of every nonterminal. | ||
667 | ** The first set is the set of all terminal symbols which can begin | ||
668 | ** a string generated by that nonterminal. | ||
669 | */ | ||
670 | void FindFirstSets(struct lemon *lemp) | ||
671 | { | ||
672 | int i, j; | ||
673 | struct rule *rp; | ||
674 | int progress; | ||
675 | |||
676 | for(i=0; i<lemp->nsymbol; i++){ | ||
677 | lemp->symbols[i]->lambda = LEMON_FALSE; | ||
678 | } | ||
679 | for(i=lemp->nterminal; i<lemp->nsymbol; i++){ | ||
680 | lemp->symbols[i]->firstset = SetNew(); | ||
681 | } | ||
682 | |||
683 | /* First compute all lambdas */ | ||
684 | do{ | ||
685 | progress = 0; | ||
686 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
687 | if( rp->lhs->lambda ) continue; | ||
688 | for(i=0; i<rp->nrhs; i++){ | ||
689 | struct symbol *sp = rp->rhs[i]; | ||
690 | assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE ); | ||
691 | if( sp->lambda==LEMON_FALSE ) break; | ||
692 | } | ||
693 | if( i==rp->nrhs ){ | ||
694 | rp->lhs->lambda = LEMON_TRUE; | ||
695 | progress = 1; | ||
696 | } | ||
697 | } | ||
698 | }while( progress ); | ||
699 | |||
700 | /* Now compute all first sets */ | ||
701 | do{ | ||
702 | struct symbol *s1, *s2; | ||
703 | progress = 0; | ||
704 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
705 | s1 = rp->lhs; | ||
706 | for(i=0; i<rp->nrhs; i++){ | ||
707 | s2 = rp->rhs[i]; | ||
708 | if( s2->type==TERMINAL ){ | ||
709 | progress += SetAdd(s1->firstset,s2->index); | ||
710 | break; | ||
711 | }else if( s2->type==MULTITERMINAL ){ | ||
712 | for(j=0; j<s2->nsubsym; j++){ | ||
713 | progress += SetAdd(s1->firstset,s2->subsym[j]->index); | ||
714 | } | ||
715 | break; | ||
716 | }else if( s1==s2 ){ | ||
717 | if( s1->lambda==LEMON_FALSE ) break; | ||
718 | }else{ | ||
719 | progress += SetUnion(s1->firstset,s2->firstset); | ||
720 | if( s2->lambda==LEMON_FALSE ) break; | ||
721 | } | ||
722 | } | ||
723 | } | ||
724 | }while( progress ); | ||
725 | return; | ||
726 | } | ||
727 | |||
728 | /* Compute all LR(0) states for the grammar. Links | ||
729 | ** are added to between some states so that the LR(1) follow sets | ||
730 | ** can be computed later. | ||
731 | */ | ||
732 | PRIVATE struct state *getstate(struct lemon *); /* forward reference */ | ||
733 | void FindStates(struct lemon *lemp) | ||
734 | { | ||
735 | struct symbol *sp; | ||
736 | struct rule *rp; | ||
737 | |||
738 | Configlist_init(); | ||
739 | |||
740 | /* Find the start symbol */ | ||
741 | if( lemp->start ){ | ||
742 | sp = Symbol_find(lemp->start); | ||
743 | if( sp==0 ){ | ||
744 | ErrorMsg(lemp->filename,0, | ||
745 | "The specified start symbol \"%s\" is not \ | ||
746 | in a nonterminal of the grammar. \"%s\" will be used as the start \ | ||
747 | symbol instead.",lemp->start,lemp->rule->lhs->name); | ||
748 | lemp->errorcnt++; | ||
749 | sp = lemp->rule->lhs; | ||
750 | } | ||
751 | }else{ | ||
752 | sp = lemp->rule->lhs; | ||
753 | } | ||
754 | |||
755 | /* Make sure the start symbol doesn't occur on the right-hand side of | ||
756 | ** any rule. Report an error if it does. (YACC would generate a new | ||
757 | ** start symbol in this case.) */ | ||
758 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
759 | int i; | ||
760 | for(i=0; i<rp->nrhs; i++){ | ||
761 | if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */ | ||
762 | ErrorMsg(lemp->filename,0, | ||
763 | "The start symbol \"%s\" occurs on the \ | ||
764 | right-hand side of a rule. This will result in a parser which \ | ||
765 | does not work properly.",sp->name); | ||
766 | lemp->errorcnt++; | ||
767 | } | ||
768 | } | ||
769 | } | ||
770 | |||
771 | /* The basis configuration set for the first state | ||
772 | ** is all rules which have the start symbol as their | ||
773 | ** left-hand side */ | ||
774 | for(rp=sp->rule; rp; rp=rp->nextlhs){ | ||
775 | struct config *newcfp; | ||
776 | rp->lhsStart = 1; | ||
777 | newcfp = Configlist_addbasis(rp,0); | ||
778 | SetAdd(newcfp->fws,0); | ||
779 | } | ||
780 | |||
781 | /* Compute the first state. All other states will be | ||
782 | ** computed automatically during the computation of the first one. | ||
783 | ** The returned pointer to the first state is not used. */ | ||
784 | (void)getstate(lemp); | ||
785 | return; | ||
786 | } | ||
787 | |||
788 | /* Return a pointer to a state which is described by the configuration | ||
789 | ** list which has been built from calls to Configlist_add. | ||
790 | */ | ||
791 | PRIVATE void buildshifts(struct lemon *, struct state *); /* Forwd ref */ | ||
792 | PRIVATE struct state *getstate(struct lemon *lemp) | ||
793 | { | ||
794 | struct config *cfp, *bp; | ||
795 | struct state *stp; | ||
796 | |||
797 | /* Extract the sorted basis of the new state. The basis was constructed | ||
798 | ** by prior calls to "Configlist_addbasis()". */ | ||
799 | Configlist_sortbasis(); | ||
800 | bp = Configlist_basis(); | ||
801 | |||
802 | /* Get a state with the same basis */ | ||
803 | stp = State_find(bp); | ||
804 | if( stp ){ | ||
805 | /* A state with the same basis already exists! Copy all the follow-set | ||
806 | ** propagation links from the state under construction into the | ||
807 | ** preexisting state, then return a pointer to the preexisting state */ | ||
808 | struct config *x, *y; | ||
809 | for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){ | ||
810 | Plink_copy(&y->bplp,x->bplp); | ||
811 | Plink_delete(x->fplp); | ||
812 | x->fplp = x->bplp = 0; | ||
813 | } | ||
814 | cfp = Configlist_return(); | ||
815 | Configlist_eat(cfp); | ||
816 | }else{ | ||
817 | /* This really is a new state. Construct all the details */ | ||
818 | Configlist_closure(lemp); /* Compute the configuration closure */ | ||
819 | Configlist_sort(); /* Sort the configuration closure */ | ||
820 | cfp = Configlist_return(); /* Get a pointer to the config list */ | ||
821 | stp = State_new(); /* A new state structure */ | ||
822 | MemoryCheck(stp); | ||
823 | stp->bp = bp; /* Remember the configuration basis */ | ||
824 | stp->cfp = cfp; /* Remember the configuration closure */ | ||
825 | stp->statenum = lemp->nstate++; /* Every state gets a sequence number */ | ||
826 | stp->ap = 0; /* No actions, yet. */ | ||
827 | State_insert(stp,stp->bp); /* Add to the state table */ | ||
828 | buildshifts(lemp,stp); /* Recursively compute successor states */ | ||
829 | } | ||
830 | return stp; | ||
831 | } | ||
832 | |||
833 | /* | ||
834 | ** Return true if two symbols are the same. | ||
835 | */ | ||
836 | int same_symbol(struct symbol *a, struct symbol *b) | ||
837 | { | ||
838 | int i; | ||
839 | if( a==b ) return 1; | ||
840 | if( a->type!=MULTITERMINAL ) return 0; | ||
841 | if( b->type!=MULTITERMINAL ) return 0; | ||
842 | if( a->nsubsym!=b->nsubsym ) return 0; | ||
843 | for(i=0; i<a->nsubsym; i++){ | ||
844 | if( a->subsym[i]!=b->subsym[i] ) return 0; | ||
845 | } | ||
846 | return 1; | ||
847 | } | ||
848 | |||
849 | /* Construct all successor states to the given state. A "successor" | ||
850 | ** state is any state which can be reached by a shift action. | ||
851 | */ | ||
852 | PRIVATE void buildshifts(struct lemon *lemp, struct state *stp) | ||
853 | { | ||
854 | struct config *cfp; /* For looping thru the config closure of "stp" */ | ||
855 | struct config *bcfp; /* For the inner loop on config closure of "stp" */ | ||
856 | struct config *newcfg; /* */ | ||
857 | struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ | ||
858 | struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ | ||
859 | struct state *newstp; /* A pointer to a successor state */ | ||
860 | |||
861 | /* Each configuration becomes complete after it contibutes to a successor | ||
862 | ** state. Initially, all configurations are incomplete */ | ||
863 | for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE; | ||
864 | |||
865 | /* Loop through all configurations of the state "stp" */ | ||
866 | for(cfp=stp->cfp; cfp; cfp=cfp->next){ | ||
867 | if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */ | ||
868 | if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */ | ||
869 | Configlist_reset(); /* Reset the new config set */ | ||
870 | sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */ | ||
871 | |||
872 | /* For every configuration in the state "stp" which has the symbol "sp" | ||
873 | ** following its dot, add the same configuration to the basis set under | ||
874 | ** construction but with the dot shifted one symbol to the right. */ | ||
875 | for(bcfp=cfp; bcfp; bcfp=bcfp->next){ | ||
876 | if( bcfp->status==COMPLETE ) continue; /* Already used */ | ||
877 | if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */ | ||
878 | bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */ | ||
879 | if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */ | ||
880 | bcfp->status = COMPLETE; /* Mark this config as used */ | ||
881 | newcfg = Configlist_addbasis(bcfp->rp,bcfp->dot+1); | ||
882 | Plink_add(&newcfg->bplp,bcfp); | ||
883 | } | ||
884 | |||
885 | /* Get a pointer to the state described by the basis configuration set | ||
886 | ** constructed in the preceding loop */ | ||
887 | newstp = getstate(lemp); | ||
888 | |||
889 | /* The state "newstp" is reached from the state "stp" by a shift action | ||
890 | ** on the symbol "sp" */ | ||
891 | if( sp->type==MULTITERMINAL ){ | ||
892 | int i; | ||
893 | for(i=0; i<sp->nsubsym; i++){ | ||
894 | Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp); | ||
895 | } | ||
896 | }else{ | ||
897 | Action_add(&stp->ap,SHIFT,sp,(char *)newstp); | ||
898 | } | ||
899 | } | ||
900 | } | ||
901 | |||
902 | /* | ||
903 | ** Construct the propagation links | ||
904 | */ | ||
905 | void FindLinks(struct lemon *lemp) | ||
906 | { | ||
907 | int i; | ||
908 | struct config *cfp, *other; | ||
909 | struct state *stp; | ||
910 | struct plink *plp; | ||
911 | |||
912 | /* Housekeeping detail: | ||
913 | ** Add to every propagate link a pointer back to the state to | ||
914 | ** which the link is attached. */ | ||
915 | for(i=0; i<lemp->nstate; i++){ | ||
916 | stp = lemp->sorted[i]; | ||
917 | for(cfp=stp->cfp; cfp; cfp=cfp->next){ | ||
918 | cfp->stp = stp; | ||
919 | } | ||
920 | } | ||
921 | |||
922 | /* Convert all backlinks into forward links. Only the forward | ||
923 | ** links are used in the follow-set computation. */ | ||
924 | for(i=0; i<lemp->nstate; i++){ | ||
925 | stp = lemp->sorted[i]; | ||
926 | for(cfp=stp->cfp; cfp; cfp=cfp->next){ | ||
927 | for(plp=cfp->bplp; plp; plp=plp->next){ | ||
928 | other = plp->cfp; | ||
929 | Plink_add(&other->fplp,cfp); | ||
930 | } | ||
931 | } | ||
932 | } | ||
933 | } | ||
934 | |||
935 | /* Compute all followsets. | ||
936 | ** | ||
937 | ** A followset is the set of all symbols which can come immediately | ||
938 | ** after a configuration. | ||
939 | */ | ||
940 | void FindFollowSets(struct lemon *lemp) | ||
941 | { | ||
942 | int i; | ||
943 | struct config *cfp; | ||
944 | struct plink *plp; | ||
945 | int progress; | ||
946 | int change; | ||
947 | |||
948 | for(i=0; i<lemp->nstate; i++){ | ||
949 | for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ | ||
950 | cfp->status = INCOMPLETE; | ||
951 | } | ||
952 | } | ||
953 | |||
954 | do{ | ||
955 | progress = 0; | ||
956 | for(i=0; i<lemp->nstate; i++){ | ||
957 | for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ | ||
958 | if( cfp->status==COMPLETE ) continue; | ||
959 | for(plp=cfp->fplp; plp; plp=plp->next){ | ||
960 | change = SetUnion(plp->cfp->fws,cfp->fws); | ||
961 | if( change ){ | ||
962 | plp->cfp->status = INCOMPLETE; | ||
963 | progress = 1; | ||
964 | } | ||
965 | } | ||
966 | cfp->status = COMPLETE; | ||
967 | } | ||
968 | } | ||
969 | }while( progress ); | ||
970 | } | ||
971 | |||
972 | static int resolve_conflict(struct action *,struct action *, struct symbol *); | ||
973 | |||
974 | /* Compute the reduce actions, and resolve conflicts. | ||
975 | */ | ||
976 | void FindActions(struct lemon *lemp) | ||
977 | { | ||
978 | int i,j; | ||
979 | struct config *cfp; | ||
980 | struct state *stp; | ||
981 | struct symbol *sp; | ||
982 | struct rule *rp; | ||
983 | |||
984 | /* Add all of the reduce actions | ||
985 | ** A reduce action is added for each element of the followset of | ||
986 | ** a configuration which has its dot at the extreme right. | ||
987 | */ | ||
988 | for(i=0; i<lemp->nstate; i++){ /* Loop over all states */ | ||
989 | stp = lemp->sorted[i]; | ||
990 | for(cfp=stp->cfp; cfp; cfp=cfp->next){ /* Loop over all configurations */ | ||
991 | if( cfp->rp->nrhs==cfp->dot ){ /* Is dot at extreme right? */ | ||
992 | for(j=0; j<lemp->nterminal; j++){ | ||
993 | if( SetFind(cfp->fws,j) ){ | ||
994 | /* Add a reduce action to the state "stp" which will reduce by the | ||
995 | ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */ | ||
996 | Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp); | ||
997 | } | ||
998 | } | ||
999 | } | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | /* Add the accepting token */ | ||
1004 | if( lemp->start ){ | ||
1005 | sp = Symbol_find(lemp->start); | ||
1006 | if( sp==0 ) sp = lemp->rule->lhs; | ||
1007 | }else{ | ||
1008 | sp = lemp->rule->lhs; | ||
1009 | } | ||
1010 | /* Add to the first state (which is always the starting state of the | ||
1011 | ** finite state machine) an action to ACCEPT if the lookahead is the | ||
1012 | ** start nonterminal. */ | ||
1013 | Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0); | ||
1014 | |||
1015 | /* Resolve conflicts */ | ||
1016 | for(i=0; i<lemp->nstate; i++){ | ||
1017 | struct action *ap, *nap; | ||
1018 | struct state *stp; | ||
1019 | stp = lemp->sorted[i]; | ||
1020 | /* assert( stp->ap ); */ | ||
1021 | stp->ap = Action_sort(stp->ap); | ||
1022 | for(ap=stp->ap; ap && ap->next; ap=ap->next){ | ||
1023 | for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){ | ||
1024 | /* The two actions "ap" and "nap" have the same lookahead. | ||
1025 | ** Figure out which one should be used */ | ||
1026 | lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym); | ||
1027 | } | ||
1028 | } | ||
1029 | } | ||
1030 | |||
1031 | /* Report an error for each rule that can never be reduced. */ | ||
1032 | for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE; | ||
1033 | for(i=0; i<lemp->nstate; i++){ | ||
1034 | struct action *ap; | ||
1035 | for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ | ||
1036 | if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE; | ||
1037 | } | ||
1038 | } | ||
1039 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
1040 | if( rp->canReduce ) continue; | ||
1041 | ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n"); | ||
1042 | lemp->errorcnt++; | ||
1043 | } | ||
1044 | } | ||
1045 | |||
1046 | /* Resolve a conflict between the two given actions. If the | ||
1047 | ** conflict can't be resolved, return non-zero. | ||
1048 | ** | ||
1049 | ** NO LONGER TRUE: | ||
1050 | ** To resolve a conflict, first look to see if either action | ||
1051 | ** is on an error rule. In that case, take the action which | ||
1052 | ** is not associated with the error rule. If neither or both | ||
1053 | ** actions are associated with an error rule, then try to | ||
1054 | ** use precedence to resolve the conflict. | ||
1055 | ** | ||
1056 | ** If either action is a SHIFT, then it must be apx. This | ||
1057 | ** function won't work if apx->type==REDUCE and apy->type==SHIFT. | ||
1058 | */ | ||
1059 | static int resolve_conflict( | ||
1060 | struct action *apx, | ||
1061 | struct action *apy, | ||
1062 | struct symbol *errsym /* The error symbol (if defined. NULL otherwise) */ | ||
1063 | ){ | ||
1064 | struct symbol *spx, *spy; | ||
1065 | int errcnt = 0; | ||
1066 | assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ | ||
1067 | if( apx->type==SHIFT && apy->type==SHIFT ){ | ||
1068 | apy->type = SSCONFLICT; | ||
1069 | errcnt++; | ||
1070 | } | ||
1071 | if( apx->type==SHIFT && apy->type==REDUCE ){ | ||
1072 | spx = apx->sp; | ||
1073 | spy = apy->x.rp->precsym; | ||
1074 | if( spy==0 || spx->prec<0 || spy->prec<0 ){ | ||
1075 | /* Not enough precedence information. */ | ||
1076 | apy->type = SRCONFLICT; | ||
1077 | errcnt++; | ||
1078 | }else if( spx->prec>spy->prec ){ /* higher precedence wins */ | ||
1079 | apy->type = RD_RESOLVED; | ||
1080 | }else if( spx->prec<spy->prec ){ | ||
1081 | apx->type = SH_RESOLVED; | ||
1082 | }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */ | ||
1083 | apy->type = RD_RESOLVED; /* associativity */ | ||
1084 | }else if( spx->prec==spy->prec && spx->assoc==LEFT ){ /* to break tie */ | ||
1085 | apx->type = SH_RESOLVED; | ||
1086 | }else{ | ||
1087 | assert( spx->prec==spy->prec && spx->assoc==NONE ); | ||
1088 | apy->type = SRCONFLICT; | ||
1089 | errcnt++; | ||
1090 | } | ||
1091 | }else if( apx->type==REDUCE && apy->type==REDUCE ){ | ||
1092 | spx = apx->x.rp->precsym; | ||
1093 | spy = apy->x.rp->precsym; | ||
1094 | if( spx==0 || spy==0 || spx->prec<0 || | ||
1095 | spy->prec<0 || spx->prec==spy->prec ){ | ||
1096 | apy->type = RRCONFLICT; | ||
1097 | errcnt++; | ||
1098 | }else if( spx->prec>spy->prec ){ | ||
1099 | apy->type = RD_RESOLVED; | ||
1100 | }else if( spx->prec<spy->prec ){ | ||
1101 | apx->type = RD_RESOLVED; | ||
1102 | } | ||
1103 | }else{ | ||
1104 | assert( | ||
1105 | apx->type==SH_RESOLVED || | ||
1106 | apx->type==RD_RESOLVED || | ||
1107 | apx->type==SSCONFLICT || | ||
1108 | apx->type==SRCONFLICT || | ||
1109 | apx->type==RRCONFLICT || | ||
1110 | apy->type==SH_RESOLVED || | ||
1111 | apy->type==RD_RESOLVED || | ||
1112 | apy->type==SSCONFLICT || | ||
1113 | apy->type==SRCONFLICT || | ||
1114 | apy->type==RRCONFLICT | ||
1115 | ); | ||
1116 | /* The REDUCE/SHIFT case cannot happen because SHIFTs come before | ||
1117 | ** REDUCEs on the list. If we reach this point it must be because | ||
1118 | ** the parser conflict had already been resolved. */ | ||
1119 | } | ||
1120 | return errcnt; | ||
1121 | } | ||
1122 | /********************* From the file "configlist.c" *************************/ | ||
1123 | /* | ||
1124 | ** Routines to processing a configuration list and building a state | ||
1125 | ** in the LEMON parser generator. | ||
1126 | */ | ||
1127 | |||
1128 | static struct config *freelist = 0; /* List of free configurations */ | ||
1129 | static struct config *current = 0; /* Top of list of configurations */ | ||
1130 | static struct config **currentend = 0; /* Last on list of configs */ | ||
1131 | static struct config *basis = 0; /* Top of list of basis configs */ | ||
1132 | static struct config **basisend = 0; /* End of list of basis configs */ | ||
1133 | |||
1134 | /* Return a pointer to a new configuration */ | ||
1135 | PRIVATE struct config *newconfig(){ | ||
1136 | struct config *newcfg; | ||
1137 | if( freelist==0 ){ | ||
1138 | int i; | ||
1139 | int amt = 3; | ||
1140 | freelist = (struct config *)calloc( amt, sizeof(struct config) ); | ||
1141 | if( freelist==0 ){ | ||
1142 | fprintf(stderr,"Unable to allocate memory for a new configuration."); | ||
1143 | exit(1); | ||
1144 | } | ||
1145 | for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; | ||
1146 | freelist[amt-1].next = 0; | ||
1147 | } | ||
1148 | newcfg = freelist; | ||
1149 | freelist = freelist->next; | ||
1150 | return newcfg; | ||
1151 | } | ||
1152 | |||
1153 | /* The configuration "old" is no longer used */ | ||
1154 | PRIVATE void deleteconfig(struct config *old) | ||
1155 | { | ||
1156 | old->next = freelist; | ||
1157 | freelist = old; | ||
1158 | } | ||
1159 | |||
1160 | /* Initialized the configuration list builder */ | ||
1161 | void Configlist_init(){ | ||
1162 | current = 0; | ||
1163 | currentend = ¤t; | ||
1164 | basis = 0; | ||
1165 | basisend = &basis; | ||
1166 | Configtable_init(); | ||
1167 | return; | ||
1168 | } | ||
1169 | |||
1170 | /* Initialized the configuration list builder */ | ||
1171 | void Configlist_reset(){ | ||
1172 | current = 0; | ||
1173 | currentend = ¤t; | ||
1174 | basis = 0; | ||
1175 | basisend = &basis; | ||
1176 | Configtable_clear(0); | ||
1177 | return; | ||
1178 | } | ||
1179 | |||
1180 | /* Add another configuration to the configuration list */ | ||
1181 | struct config *Configlist_add( | ||
1182 | struct rule *rp, /* The rule */ | ||
1183 | int dot /* Index into the RHS of the rule where the dot goes */ | ||
1184 | ){ | ||
1185 | struct config *cfp, model; | ||
1186 | |||
1187 | assert( currentend!=0 ); | ||
1188 | model.rp = rp; | ||
1189 | model.dot = dot; | ||
1190 | cfp = Configtable_find(&model); | ||
1191 | if( cfp==0 ){ | ||
1192 | cfp = newconfig(); | ||
1193 | cfp->rp = rp; | ||
1194 | cfp->dot = dot; | ||
1195 | cfp->fws = SetNew(); | ||
1196 | cfp->stp = 0; | ||
1197 | cfp->fplp = cfp->bplp = 0; | ||
1198 | cfp->next = 0; | ||
1199 | cfp->bp = 0; | ||
1200 | *currentend = cfp; | ||
1201 | currentend = &cfp->next; | ||
1202 | Configtable_insert(cfp); | ||
1203 | } | ||
1204 | return cfp; | ||
1205 | } | ||
1206 | |||
1207 | /* Add a basis configuration to the configuration list */ | ||
1208 | struct config *Configlist_addbasis(struct rule *rp, int dot) | ||
1209 | { | ||
1210 | struct config *cfp, model; | ||
1211 | |||
1212 | assert( basisend!=0 ); | ||
1213 | assert( currentend!=0 ); | ||
1214 | model.rp = rp; | ||
1215 | model.dot = dot; | ||
1216 | cfp = Configtable_find(&model); | ||
1217 | if( cfp==0 ){ | ||
1218 | cfp = newconfig(); | ||
1219 | cfp->rp = rp; | ||
1220 | cfp->dot = dot; | ||
1221 | cfp->fws = SetNew(); | ||
1222 | cfp->stp = 0; | ||
1223 | cfp->fplp = cfp->bplp = 0; | ||
1224 | cfp->next = 0; | ||
1225 | cfp->bp = 0; | ||
1226 | *currentend = cfp; | ||
1227 | currentend = &cfp->next; | ||
1228 | *basisend = cfp; | ||
1229 | basisend = &cfp->bp; | ||
1230 | Configtable_insert(cfp); | ||
1231 | } | ||
1232 | return cfp; | ||
1233 | } | ||
1234 | |||
1235 | /* Compute the closure of the configuration list */ | ||
1236 | void Configlist_closure(struct lemon *lemp) | ||
1237 | { | ||
1238 | struct config *cfp, *newcfp; | ||
1239 | struct rule *rp, *newrp; | ||
1240 | struct symbol *sp, *xsp; | ||
1241 | int i, dot; | ||
1242 | |||
1243 | assert( currentend!=0 ); | ||
1244 | for(cfp=current; cfp; cfp=cfp->next){ | ||
1245 | rp = cfp->rp; | ||
1246 | dot = cfp->dot; | ||
1247 | if( dot>=rp->nrhs ) continue; | ||
1248 | sp = rp->rhs[dot]; | ||
1249 | if( sp->type==NONTERMINAL ){ | ||
1250 | if( sp->rule==0 && sp!=lemp->errsym ){ | ||
1251 | ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.", | ||
1252 | sp->name); | ||
1253 | lemp->errorcnt++; | ||
1254 | } | ||
1255 | for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){ | ||
1256 | newcfp = Configlist_add(newrp,0); | ||
1257 | for(i=dot+1; i<rp->nrhs; i++){ | ||
1258 | xsp = rp->rhs[i]; | ||
1259 | if( xsp->type==TERMINAL ){ | ||
1260 | SetAdd(newcfp->fws,xsp->index); | ||
1261 | break; | ||
1262 | }else if( xsp->type==MULTITERMINAL ){ | ||
1263 | int k; | ||
1264 | for(k=0; k<xsp->nsubsym; k++){ | ||
1265 | SetAdd(newcfp->fws, xsp->subsym[k]->index); | ||
1266 | } | ||
1267 | break; | ||
1268 | }else{ | ||
1269 | SetUnion(newcfp->fws,xsp->firstset); | ||
1270 | if( xsp->lambda==LEMON_FALSE ) break; | ||
1271 | } | ||
1272 | } | ||
1273 | if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp); | ||
1274 | } | ||
1275 | } | ||
1276 | } | ||
1277 | return; | ||
1278 | } | ||
1279 | |||
1280 | /* Sort the configuration list */ | ||
1281 | void Configlist_sort(){ | ||
1282 | current = (struct config *)msort((char *)current,(char **)&(current->next),Configcmp); | ||
1283 | currentend = 0; | ||
1284 | return; | ||
1285 | } | ||
1286 | |||
1287 | /* Sort the basis configuration list */ | ||
1288 | void Configlist_sortbasis(){ | ||
1289 | basis = (struct config *)msort((char *)current,(char **)&(current->bp),Configcmp); | ||
1290 | basisend = 0; | ||
1291 | return; | ||
1292 | } | ||
1293 | |||
1294 | /* Return a pointer to the head of the configuration list and | ||
1295 | ** reset the list */ | ||
1296 | struct config *Configlist_return(){ | ||
1297 | struct config *old; | ||
1298 | old = current; | ||
1299 | current = 0; | ||
1300 | currentend = 0; | ||
1301 | return old; | ||
1302 | } | ||
1303 | |||
1304 | /* Return a pointer to the head of the configuration list and | ||
1305 | ** reset the list */ | ||
1306 | struct config *Configlist_basis(){ | ||
1307 | struct config *old; | ||
1308 | old = basis; | ||
1309 | basis = 0; | ||
1310 | basisend = 0; | ||
1311 | return old; | ||
1312 | } | ||
1313 | |||
1314 | /* Free all elements of the given configuration list */ | ||
1315 | void Configlist_eat(struct config *cfp) | ||
1316 | { | ||
1317 | struct config *nextcfp; | ||
1318 | for(; cfp; cfp=nextcfp){ | ||
1319 | nextcfp = cfp->next; | ||
1320 | assert( cfp->fplp==0 ); | ||
1321 | assert( cfp->bplp==0 ); | ||
1322 | if( cfp->fws ) SetFree(cfp->fws); | ||
1323 | deleteconfig(cfp); | ||
1324 | } | ||
1325 | return; | ||
1326 | } | ||
1327 | /***************** From the file "error.c" *********************************/ | ||
1328 | /* | ||
1329 | ** Code for printing error message. | ||
1330 | */ | ||
1331 | |||
1332 | void ErrorMsg(const char *filename, int lineno, const char *format, ...){ | ||
1333 | va_list ap; | ||
1334 | fprintf(stderr, "%s:%d: ", filename, lineno); | ||
1335 | va_start(ap, format); | ||
1336 | vfprintf(stderr,format,ap); | ||
1337 | va_end(ap); | ||
1338 | fprintf(stderr, "\n"); | ||
1339 | } | ||
1340 | /**************** From the file "main.c" ************************************/ | ||
1341 | /* | ||
1342 | ** Main program file for the LEMON parser generator. | ||
1343 | */ | ||
1344 | |||
1345 | /* Report an out-of-memory condition and abort. This function | ||
1346 | ** is used mostly by the "MemoryCheck" macro in struct.h | ||
1347 | */ | ||
1348 | void memory_error(){ | ||
1349 | fprintf(stderr,"Out of memory. Aborting...\n"); | ||
1350 | exit(1); | ||
1351 | } | ||
1352 | |||
1353 | static int nDefine = 0; /* Number of -D options on the command line */ | ||
1354 | static char **azDefine = 0; /* Name of the -D macros */ | ||
1355 | |||
1356 | /* This routine is called with the argument to each -D command-line option. | ||
1357 | ** Add the macro defined to the azDefine array. | ||
1358 | */ | ||
1359 | static void handle_D_option(char *z){ | ||
1360 | char **paz; | ||
1361 | nDefine++; | ||
1362 | azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine); | ||
1363 | if( azDefine==0 ){ | ||
1364 | fprintf(stderr,"out of memory\n"); | ||
1365 | exit(1); | ||
1366 | } | ||
1367 | paz = &azDefine[nDefine-1]; | ||
1368 | *paz = (char *) malloc( lemonStrlen(z)+1 ); | ||
1369 | if( *paz==0 ){ | ||
1370 | fprintf(stderr,"out of memory\n"); | ||
1371 | exit(1); | ||
1372 | } | ||
1373 | strcpy(*paz, z); | ||
1374 | for(z=*paz; *z && *z!='='; z++){} | ||
1375 | *z = 0; | ||
1376 | } | ||
1377 | |||
1378 | static char *user_templatename = NULL; | ||
1379 | static void handle_T_option(char *z){ | ||
1380 | user_templatename = (char *) malloc( lemonStrlen(z)+1 ); | ||
1381 | if( user_templatename==0 ){ | ||
1382 | memory_error(); | ||
1383 | } | ||
1384 | strcpy(user_templatename, z); | ||
1385 | } | ||
1386 | |||
1387 | /* The main program. Parse the command line and do it... */ | ||
1388 | int main(int argc, char **argv) | ||
1389 | { | ||
1390 | static int version = 0; | ||
1391 | static int rpflag = 0; | ||
1392 | static int basisflag = 0; | ||
1393 | static int compress = 0; | ||
1394 | static int quiet = 0; | ||
1395 | static int statistics = 0; | ||
1396 | static int mhflag = 0; | ||
1397 | static int nolinenosflag = 0; | ||
1398 | static int noResort = 0; | ||
1399 | static struct s_options options[] = { | ||
1400 | {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, | ||
1401 | {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, | ||
1402 | {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, | ||
1403 | {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, | ||
1404 | {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, | ||
1405 | {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, | ||
1406 | {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, | ||
1407 | {OPT_FLAG, "p", (char*)&showPrecedenceConflict, | ||
1408 | "Show conflicts resolved by precedence rules"}, | ||
1409 | {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, | ||
1410 | {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"}, | ||
1411 | {OPT_FLAG, "s", (char*)&statistics, | ||
1412 | "Print parser stats to standard output."}, | ||
1413 | {OPT_FLAG, "x", (char*)&version, "Print the version number."}, | ||
1414 | {OPT_FLAG,0,0,0} | ||
1415 | }; | ||
1416 | int i; | ||
1417 | int exitcode; | ||
1418 | struct lemon lem; | ||
1419 | |||
1420 | OptInit(argv,options,stderr); | ||
1421 | if( version ){ | ||
1422 | printf("Lemon version 1.0\n"); | ||
1423 | exit(0); | ||
1424 | } | ||
1425 | if( OptNArgs()!=1 ){ | ||
1426 | fprintf(stderr,"Exactly one filename argument is required.\n"); | ||
1427 | exit(1); | ||
1428 | } | ||
1429 | memset(&lem, 0, sizeof(lem)); | ||
1430 | lem.errorcnt = 0; | ||
1431 | |||
1432 | /* Initialize the machine */ | ||
1433 | Strsafe_init(); | ||
1434 | Symbol_init(); | ||
1435 | State_init(); | ||
1436 | lem.argv0 = argv[0]; | ||
1437 | lem.filename = OptArg(0); | ||
1438 | lem.basisflag = basisflag; | ||
1439 | lem.nolinenosflag = nolinenosflag; | ||
1440 | Symbol_new("$"); | ||
1441 | lem.errsym = Symbol_new("error"); | ||
1442 | lem.errsym->useCnt = 0; | ||
1443 | |||
1444 | /* Parse the input file */ | ||
1445 | Parse(&lem); | ||
1446 | if( lem.errorcnt ) exit(lem.errorcnt); | ||
1447 | if( lem.nrule==0 ){ | ||
1448 | fprintf(stderr,"Empty grammar.\n"); | ||
1449 | exit(1); | ||
1450 | } | ||
1451 | |||
1452 | /* Count and index the symbols of the grammar */ | ||
1453 | lem.nsymbol = Symbol_count(); | ||
1454 | Symbol_new("{default}"); | ||
1455 | lem.symbols = Symbol_arrayof(); | ||
1456 | for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; | ||
1457 | qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*), Symbolcmpp); | ||
1458 | for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; | ||
1459 | for(i=1; isupper(lem.symbols[i]->name[0]); i++); | ||
1460 | lem.nterminal = i; | ||
1461 | |||
1462 | /* Generate a reprint of the grammar, if requested on the command line */ | ||
1463 | if( rpflag ){ | ||
1464 | Reprint(&lem); | ||
1465 | }else{ | ||
1466 | /* Initialize the size for all follow and first sets */ | ||
1467 | SetSize(lem.nterminal+1); | ||
1468 | |||
1469 | /* Find the precedence for every production rule (that has one) */ | ||
1470 | FindRulePrecedences(&lem); | ||
1471 | |||
1472 | /* Compute the lambda-nonterminals and the first-sets for every | ||
1473 | ** nonterminal */ | ||
1474 | FindFirstSets(&lem); | ||
1475 | |||
1476 | /* Compute all LR(0) states. Also record follow-set propagation | ||
1477 | ** links so that the follow-set can be computed later */ | ||
1478 | lem.nstate = 0; | ||
1479 | FindStates(&lem); | ||
1480 | lem.sorted = State_arrayof(); | ||
1481 | |||
1482 | /* Tie up loose ends on the propagation links */ | ||
1483 | FindLinks(&lem); | ||
1484 | |||
1485 | /* Compute the follow set of every reducible configuration */ | ||
1486 | FindFollowSets(&lem); | ||
1487 | |||
1488 | /* Compute the action tables */ | ||
1489 | FindActions(&lem); | ||
1490 | |||
1491 | /* Compress the action tables */ | ||
1492 | if( compress==0 ) CompressTables(&lem); | ||
1493 | |||
1494 | /* Reorder and renumber the states so that states with fewer choices | ||
1495 | ** occur at the end. This is an optimization that helps make the | ||
1496 | ** generated parser tables smaller. */ | ||
1497 | if( noResort==0 ) ResortStates(&lem); | ||
1498 | |||
1499 | /* Generate a report of the parser generated. (the "y.output" file) */ | ||
1500 | if( !quiet ) ReportOutput(&lem); | ||
1501 | |||
1502 | /* Generate the source code for the parser */ | ||
1503 | ReportTable(&lem, mhflag); | ||
1504 | |||
1505 | /* Produce a header file for use by the scanner. (This step is | ||
1506 | ** omitted if the "-m" option is used because makeheaders will | ||
1507 | ** generate the file for us.) */ | ||
1508 | if( !mhflag ) ReportHeader(&lem); | ||
1509 | } | ||
1510 | if( statistics ){ | ||
1511 | printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", | ||
1512 | lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); | ||
1513 | printf(" %d states, %d parser table entries, %d conflicts\n", | ||
1514 | lem.nstate, lem.tablesize, lem.nconflict); | ||
1515 | } | ||
1516 | if( lem.nconflict > 0 ){ | ||
1517 | fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); | ||
1518 | } | ||
1519 | |||
1520 | /* return 0 on success, 1 on failure. */ | ||
1521 | exitcode = ((lem.errorcnt > 0) || (lem.nconflict > 0)) ? 1 : 0; | ||
1522 | exit(exitcode); | ||
1523 | return (exitcode); | ||
1524 | } | ||
1525 | /******************** From the file "msort.c" *******************************/ | ||
1526 | /* | ||
1527 | ** A generic merge-sort program. | ||
1528 | ** | ||
1529 | ** USAGE: | ||
1530 | ** Let "ptr" be a pointer to some structure which is at the head of | ||
1531 | ** a null-terminated list. Then to sort the list call: | ||
1532 | ** | ||
1533 | ** ptr = msort(ptr,&(ptr->next),cmpfnc); | ||
1534 | ** | ||
1535 | ** In the above, "cmpfnc" is a pointer to a function which compares | ||
1536 | ** two instances of the structure and returns an integer, as in | ||
1537 | ** strcmp. The second argument is a pointer to the pointer to the | ||
1538 | ** second element of the linked list. This address is used to compute | ||
1539 | ** the offset to the "next" field within the structure. The offset to | ||
1540 | ** the "next" field must be constant for all structures in the list. | ||
1541 | ** | ||
1542 | ** The function returns a new pointer which is the head of the list | ||
1543 | ** after sorting. | ||
1544 | ** | ||
1545 | ** ALGORITHM: | ||
1546 | ** Merge-sort. | ||
1547 | */ | ||
1548 | |||
1549 | /* | ||
1550 | ** Return a pointer to the next structure in the linked list. | ||
1551 | */ | ||
1552 | #define NEXT(A) (*(char**)(((unsigned long)A)+offset)) | ||
1553 | |||
1554 | /* | ||
1555 | ** Inputs: | ||
1556 | ** a: A sorted, null-terminated linked list. (May be null). | ||
1557 | ** b: A sorted, null-terminated linked list. (May be null). | ||
1558 | ** cmp: A pointer to the comparison function. | ||
1559 | ** offset: Offset in the structure to the "next" field. | ||
1560 | ** | ||
1561 | ** Return Value: | ||
1562 | ** A pointer to the head of a sorted list containing the elements | ||
1563 | ** of both a and b. | ||
1564 | ** | ||
1565 | ** Side effects: | ||
1566 | ** The "next" pointers for elements in the lists a and b are | ||
1567 | ** changed. | ||
1568 | */ | ||
1569 | static char *merge( | ||
1570 | char *a, | ||
1571 | char *b, | ||
1572 | int (*cmp)(const char*,const char*), | ||
1573 | int offset | ||
1574 | ){ | ||
1575 | char *ptr, *head; | ||
1576 | |||
1577 | if( a==0 ){ | ||
1578 | head = b; | ||
1579 | }else if( b==0 ){ | ||
1580 | head = a; | ||
1581 | }else{ | ||
1582 | if( (*cmp)(a,b)<=0 ){ | ||
1583 | ptr = a; | ||
1584 | a = NEXT(a); | ||
1585 | }else{ | ||
1586 | ptr = b; | ||
1587 | b = NEXT(b); | ||
1588 | } | ||
1589 | head = ptr; | ||
1590 | while( a && b ){ | ||
1591 | if( (*cmp)(a,b)<=0 ){ | ||
1592 | NEXT(ptr) = a; | ||
1593 | ptr = a; | ||
1594 | a = NEXT(a); | ||
1595 | }else{ | ||
1596 | NEXT(ptr) = b; | ||
1597 | ptr = b; | ||
1598 | b = NEXT(b); | ||
1599 | } | ||
1600 | } | ||
1601 | if( a ) NEXT(ptr) = a; | ||
1602 | else NEXT(ptr) = b; | ||
1603 | } | ||
1604 | return head; | ||
1605 | } | ||
1606 | |||
1607 | /* | ||
1608 | ** Inputs: | ||
1609 | ** list: Pointer to a singly-linked list of structures. | ||
1610 | ** next: Pointer to pointer to the second element of the list. | ||
1611 | ** cmp: A comparison function. | ||
1612 | ** | ||
1613 | ** Return Value: | ||
1614 | ** A pointer to the head of a sorted list containing the elements | ||
1615 | ** orginally in list. | ||
1616 | ** | ||
1617 | ** Side effects: | ||
1618 | ** The "next" pointers for elements in list are changed. | ||
1619 | */ | ||
1620 | #define LISTSIZE 30 | ||
1621 | static char *msort( | ||
1622 | char *list, | ||
1623 | char **next, | ||
1624 | int (*cmp)(const char*,const char*) | ||
1625 | ){ | ||
1626 | unsigned long offset; | ||
1627 | char *ep; | ||
1628 | char *set[LISTSIZE]; | ||
1629 | int i; | ||
1630 | offset = (unsigned long)next - (unsigned long)list; | ||
1631 | for(i=0; i<LISTSIZE; i++) set[i] = 0; | ||
1632 | while( list ){ | ||
1633 | ep = list; | ||
1634 | list = NEXT(list); | ||
1635 | NEXT(ep) = 0; | ||
1636 | for(i=0; i<LISTSIZE-1 && set[i]!=0; i++){ | ||
1637 | ep = merge(ep,set[i],cmp,offset); | ||
1638 | set[i] = 0; | ||
1639 | } | ||
1640 | set[i] = ep; | ||
1641 | } | ||
1642 | ep = 0; | ||
1643 | for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(set[i],ep,cmp,offset); | ||
1644 | return ep; | ||
1645 | } | ||
1646 | /************************ From the file "option.c" **************************/ | ||
1647 | static char **argv; | ||
1648 | static struct s_options *op; | ||
1649 | static FILE *errstream; | ||
1650 | |||
1651 | #define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0) | ||
1652 | |||
1653 | /* | ||
1654 | ** Print the command line with a carrot pointing to the k-th character | ||
1655 | ** of the n-th field. | ||
1656 | */ | ||
1657 | static void errline(int n, int k, FILE *err) | ||
1658 | { | ||
1659 | int spcnt, i; | ||
1660 | if( argv[0] ) fprintf(err,"%s",argv[0]); | ||
1661 | spcnt = lemonStrlen(argv[0]) + 1; | ||
1662 | for(i=1; i<n && argv[i]; i++){ | ||
1663 | fprintf(err," %s",argv[i]); | ||
1664 | spcnt += lemonStrlen(argv[i])+1; | ||
1665 | } | ||
1666 | spcnt += k; | ||
1667 | for(; argv[i]; i++) fprintf(err," %s",argv[i]); | ||
1668 | if( spcnt<20 ){ | ||
1669 | fprintf(err,"\n%*s^-- here\n",spcnt,""); | ||
1670 | }else{ | ||
1671 | fprintf(err,"\n%*shere --^\n",spcnt-7,""); | ||
1672 | } | ||
1673 | } | ||
1674 | |||
1675 | /* | ||
1676 | ** Return the index of the N-th non-switch argument. Return -1 | ||
1677 | ** if N is out of range. | ||
1678 | */ | ||
1679 | static int argindex(int n) | ||
1680 | { | ||
1681 | int i; | ||
1682 | int dashdash = 0; | ||
1683 | if( argv!=0 && *argv!=0 ){ | ||
1684 | for(i=1; argv[i]; i++){ | ||
1685 | if( dashdash || !ISOPT(argv[i]) ){ | ||
1686 | if( n==0 ) return i; | ||
1687 | n--; | ||
1688 | } | ||
1689 | if( strcmp(argv[i],"--")==0 ) dashdash = 1; | ||
1690 | } | ||
1691 | } | ||
1692 | return -1; | ||
1693 | } | ||
1694 | |||
1695 | static char emsg[] = "Command line syntax error: "; | ||
1696 | |||
1697 | /* | ||
1698 | ** Process a flag command line argument. | ||
1699 | */ | ||
1700 | static int handleflags(int i, FILE *err) | ||
1701 | { | ||
1702 | int v; | ||
1703 | int errcnt = 0; | ||
1704 | int j; | ||
1705 | for(j=0; op[j].label; j++){ | ||
1706 | if( strncmp(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break; | ||
1707 | } | ||
1708 | v = argv[i][0]=='-' ? 1 : 0; | ||
1709 | if( op[j].label==0 ){ | ||
1710 | if( err ){ | ||
1711 | fprintf(err,"%sundefined option.\n",emsg); | ||
1712 | errline(i,1,err); | ||
1713 | } | ||
1714 | errcnt++; | ||
1715 | }else if( op[j].type==OPT_FLAG ){ | ||
1716 | *((int*)op[j].arg) = v; | ||
1717 | }else if( op[j].type==OPT_FFLAG ){ | ||
1718 | (*(void(*)(int))(op[j].arg))(v); | ||
1719 | }else if( op[j].type==OPT_FSTR ){ | ||
1720 | (*(void(*)(char *))(op[j].arg))(&argv[i][2]); | ||
1721 | }else{ | ||
1722 | if( err ){ | ||
1723 | fprintf(err,"%smissing argument on switch.\n",emsg); | ||
1724 | errline(i,1,err); | ||
1725 | } | ||
1726 | errcnt++; | ||
1727 | } | ||
1728 | return errcnt; | ||
1729 | } | ||
1730 | |||
1731 | /* | ||
1732 | ** Process a command line switch which has an argument. | ||
1733 | */ | ||
1734 | static int handleswitch(int i, FILE *err) | ||
1735 | { | ||
1736 | int lv = 0; | ||
1737 | double dv = 0.0; | ||
1738 | char *sv = 0, *end; | ||
1739 | char *cp; | ||
1740 | int j; | ||
1741 | int errcnt = 0; | ||
1742 | cp = strchr(argv[i],'='); | ||
1743 | assert( cp!=0 ); | ||
1744 | *cp = 0; | ||
1745 | for(j=0; op[j].label; j++){ | ||
1746 | if( strcmp(argv[i],op[j].label)==0 ) break; | ||
1747 | } | ||
1748 | *cp = '='; | ||
1749 | if( op[j].label==0 ){ | ||
1750 | if( err ){ | ||
1751 | fprintf(err,"%sundefined option.\n",emsg); | ||
1752 | errline(i,0,err); | ||
1753 | } | ||
1754 | errcnt++; | ||
1755 | }else{ | ||
1756 | cp++; | ||
1757 | switch( op[j].type ){ | ||
1758 | case OPT_FLAG: | ||
1759 | case OPT_FFLAG: | ||
1760 | if( err ){ | ||
1761 | fprintf(err,"%soption requires an argument.\n",emsg); | ||
1762 | errline(i,0,err); | ||
1763 | } | ||
1764 | errcnt++; | ||
1765 | break; | ||
1766 | case OPT_DBL: | ||
1767 | case OPT_FDBL: | ||
1768 | dv = strtod(cp,&end); | ||
1769 | if( *end ){ | ||
1770 | if( err ){ | ||
1771 | fprintf(err,"%sillegal character in floating-point argument.\n",emsg); | ||
1772 | errline(i,((unsigned long)end)-(unsigned long)argv[i],err); | ||
1773 | } | ||
1774 | errcnt++; | ||
1775 | } | ||
1776 | break; | ||
1777 | case OPT_INT: | ||
1778 | case OPT_FINT: | ||
1779 | lv = strtol(cp,&end,0); | ||
1780 | if( *end ){ | ||
1781 | if( err ){ | ||
1782 | fprintf(err,"%sillegal character in integer argument.\n",emsg); | ||
1783 | errline(i,((unsigned long)end)-(unsigned long)argv[i],err); | ||
1784 | } | ||
1785 | errcnt++; | ||
1786 | } | ||
1787 | break; | ||
1788 | case OPT_STR: | ||
1789 | case OPT_FSTR: | ||
1790 | sv = cp; | ||
1791 | break; | ||
1792 | } | ||
1793 | switch( op[j].type ){ | ||
1794 | case OPT_FLAG: | ||
1795 | case OPT_FFLAG: | ||
1796 | break; | ||
1797 | case OPT_DBL: | ||
1798 | *(double*)(op[j].arg) = dv; | ||
1799 | break; | ||
1800 | case OPT_FDBL: | ||
1801 | (*(void(*)(double))(op[j].arg))(dv); | ||
1802 | break; | ||
1803 | case OPT_INT: | ||
1804 | *(int*)(op[j].arg) = lv; | ||
1805 | break; | ||
1806 | case OPT_FINT: | ||
1807 | (*(void(*)(int))(op[j].arg))((int)lv); | ||
1808 | break; | ||
1809 | case OPT_STR: | ||
1810 | *(char**)(op[j].arg) = sv; | ||
1811 | break; | ||
1812 | case OPT_FSTR: | ||
1813 | (*(void(*)(char *))(op[j].arg))(sv); | ||
1814 | break; | ||
1815 | } | ||
1816 | } | ||
1817 | return errcnt; | ||
1818 | } | ||
1819 | |||
1820 | int OptInit(char **a, struct s_options *o, FILE *err) | ||
1821 | { | ||
1822 | int errcnt = 0; | ||
1823 | argv = a; | ||
1824 | op = o; | ||
1825 | errstream = err; | ||
1826 | if( argv && *argv && op ){ | ||
1827 | int i; | ||
1828 | for(i=1; argv[i]; i++){ | ||
1829 | if( argv[i][0]=='+' || argv[i][0]=='-' ){ | ||
1830 | errcnt += handleflags(i,err); | ||
1831 | }else if( strchr(argv[i],'=') ){ | ||
1832 | errcnt += handleswitch(i,err); | ||
1833 | } | ||
1834 | } | ||
1835 | } | ||
1836 | if( errcnt>0 ){ | ||
1837 | fprintf(err,"Valid command line options for \"%s\" are:\n",*a); | ||
1838 | OptPrint(); | ||
1839 | exit(1); | ||
1840 | } | ||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | int OptNArgs(){ | ||
1845 | int cnt = 0; | ||
1846 | int dashdash = 0; | ||
1847 | int i; | ||
1848 | if( argv!=0 && argv[0]!=0 ){ | ||
1849 | for(i=1; argv[i]; i++){ | ||
1850 | if( dashdash || !ISOPT(argv[i]) ) cnt++; | ||
1851 | if( strcmp(argv[i],"--")==0 ) dashdash = 1; | ||
1852 | } | ||
1853 | } | ||
1854 | return cnt; | ||
1855 | } | ||
1856 | |||
1857 | char *OptArg(int n) | ||
1858 | { | ||
1859 | int i; | ||
1860 | i = argindex(n); | ||
1861 | return i>=0 ? argv[i] : 0; | ||
1862 | } | ||
1863 | |||
1864 | void OptErr(int n) | ||
1865 | { | ||
1866 | int i; | ||
1867 | i = argindex(n); | ||
1868 | if( i>=0 ) errline(i,0,errstream); | ||
1869 | } | ||
1870 | |||
1871 | void OptPrint(){ | ||
1872 | int i; | ||
1873 | int max, len; | ||
1874 | max = 0; | ||
1875 | for(i=0; op[i].label; i++){ | ||
1876 | len = lemonStrlen(op[i].label) + 1; | ||
1877 | switch( op[i].type ){ | ||
1878 | case OPT_FLAG: | ||
1879 | case OPT_FFLAG: | ||
1880 | break; | ||
1881 | case OPT_INT: | ||
1882 | case OPT_FINT: | ||
1883 | len += 9; /* length of "<integer>" */ | ||
1884 | break; | ||
1885 | case OPT_DBL: | ||
1886 | case OPT_FDBL: | ||
1887 | len += 6; /* length of "<real>" */ | ||
1888 | break; | ||
1889 | case OPT_STR: | ||
1890 | case OPT_FSTR: | ||
1891 | len += 8; /* length of "<string>" */ | ||
1892 | break; | ||
1893 | } | ||
1894 | if( len>max ) max = len; | ||
1895 | } | ||
1896 | for(i=0; op[i].label; i++){ | ||
1897 | switch( op[i].type ){ | ||
1898 | case OPT_FLAG: | ||
1899 | case OPT_FFLAG: | ||
1900 | fprintf(errstream," -%-*s %s\n",max,op[i].label,op[i].message); | ||
1901 | break; | ||
1902 | case OPT_INT: | ||
1903 | case OPT_FINT: | ||
1904 | fprintf(errstream," %s=<integer>%*s %s\n",op[i].label, | ||
1905 | (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); | ||
1906 | break; | ||
1907 | case OPT_DBL: | ||
1908 | case OPT_FDBL: | ||
1909 | fprintf(errstream," %s=<real>%*s %s\n",op[i].label, | ||
1910 | (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); | ||
1911 | break; | ||
1912 | case OPT_STR: | ||
1913 | case OPT_FSTR: | ||
1914 | fprintf(errstream," %s=<string>%*s %s\n",op[i].label, | ||
1915 | (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); | ||
1916 | break; | ||
1917 | } | ||
1918 | } | ||
1919 | } | ||
1920 | /*********************** From the file "parse.c" ****************************/ | ||
1921 | /* | ||
1922 | ** Input file parser for the LEMON parser generator. | ||
1923 | */ | ||
1924 | |||
1925 | /* The state of the parser */ | ||
1926 | enum e_state { | ||
1927 | INITIALIZE, | ||
1928 | WAITING_FOR_DECL_OR_RULE, | ||
1929 | WAITING_FOR_DECL_KEYWORD, | ||
1930 | WAITING_FOR_DECL_ARG, | ||
1931 | WAITING_FOR_PRECEDENCE_SYMBOL, | ||
1932 | WAITING_FOR_ARROW, | ||
1933 | IN_RHS, | ||
1934 | LHS_ALIAS_1, | ||
1935 | LHS_ALIAS_2, | ||
1936 | LHS_ALIAS_3, | ||
1937 | RHS_ALIAS_1, | ||
1938 | RHS_ALIAS_2, | ||
1939 | PRECEDENCE_MARK_1, | ||
1940 | PRECEDENCE_MARK_2, | ||
1941 | RESYNC_AFTER_RULE_ERROR, | ||
1942 | RESYNC_AFTER_DECL_ERROR, | ||
1943 | WAITING_FOR_DESTRUCTOR_SYMBOL, | ||
1944 | WAITING_FOR_DATATYPE_SYMBOL, | ||
1945 | WAITING_FOR_FALLBACK_ID, | ||
1946 | WAITING_FOR_WILDCARD_ID | ||
1947 | }; | ||
1948 | struct pstate { | ||
1949 | char *filename; /* Name of the input file */ | ||
1950 | int tokenlineno; /* Linenumber at which current token starts */ | ||
1951 | int errorcnt; /* Number of errors so far */ | ||
1952 | char *tokenstart; /* Text of current token */ | ||
1953 | struct lemon *gp; /* Global state vector */ | ||
1954 | enum e_state state; /* The state of the parser */ | ||
1955 | struct symbol *fallback; /* The fallback token */ | ||
1956 | struct symbol *lhs; /* Left-hand side of current rule */ | ||
1957 | const char *lhsalias; /* Alias for the LHS */ | ||
1958 | int nrhs; /* Number of right-hand side symbols seen */ | ||
1959 | struct symbol *rhs[MAXRHS]; /* RHS symbols */ | ||
1960 | const char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */ | ||
1961 | struct rule *prevrule; /* Previous rule parsed */ | ||
1962 | const char *declkeyword; /* Keyword of a declaration */ | ||
1963 | char **declargslot; /* Where the declaration argument should be put */ | ||
1964 | int insertLineMacro; /* Add #line before declaration insert */ | ||
1965 | int *decllinenoslot; /* Where to write declaration line number */ | ||
1966 | enum e_assoc declassoc; /* Assign this association to decl arguments */ | ||
1967 | int preccounter; /* Assign this precedence to decl arguments */ | ||
1968 | struct rule *firstrule; /* Pointer to first rule in the grammar */ | ||
1969 | struct rule *lastrule; /* Pointer to the most recently parsed rule */ | ||
1970 | }; | ||
1971 | |||
1972 | /* Parse a single token */ | ||
1973 | static void parseonetoken(struct pstate *psp) | ||
1974 | { | ||
1975 | const char *x; | ||
1976 | x = Strsafe(psp->tokenstart); /* Save the token permanently */ | ||
1977 | #if 0 | ||
1978 | printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno, | ||
1979 | x,psp->state); | ||
1980 | #endif | ||
1981 | switch( psp->state ){ | ||
1982 | case INITIALIZE: | ||
1983 | psp->prevrule = 0; | ||
1984 | psp->preccounter = 0; | ||
1985 | psp->firstrule = psp->lastrule = 0; | ||
1986 | psp->gp->nrule = 0; | ||
1987 | /* Fall thru to next case */ | ||
1988 | case WAITING_FOR_DECL_OR_RULE: | ||
1989 | if( x[0]=='%' ){ | ||
1990 | psp->state = WAITING_FOR_DECL_KEYWORD; | ||
1991 | }else if( islower(x[0]) ){ | ||
1992 | psp->lhs = Symbol_new(x); | ||
1993 | psp->nrhs = 0; | ||
1994 | psp->lhsalias = 0; | ||
1995 | psp->state = WAITING_FOR_ARROW; | ||
1996 | }else if( x[0]=='{' ){ | ||
1997 | if( psp->prevrule==0 ){ | ||
1998 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
1999 | "There is no prior rule opon which to attach the code \ | ||
2000 | fragment which begins on this line."); | ||
2001 | psp->errorcnt++; | ||
2002 | }else if( psp->prevrule->code!=0 ){ | ||
2003 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2004 | "Code fragment beginning on this line is not the first \ | ||
2005 | to follow the previous rule."); | ||
2006 | psp->errorcnt++; | ||
2007 | }else{ | ||
2008 | psp->prevrule->line = psp->tokenlineno; | ||
2009 | psp->prevrule->code = &x[1]; | ||
2010 | } | ||
2011 | }else if( x[0]=='[' ){ | ||
2012 | psp->state = PRECEDENCE_MARK_1; | ||
2013 | }else{ | ||
2014 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2015 | "Token \"%s\" should be either \"%%\" or a nonterminal name.", | ||
2016 | x); | ||
2017 | psp->errorcnt++; | ||
2018 | } | ||
2019 | break; | ||
2020 | case PRECEDENCE_MARK_1: | ||
2021 | if( !isupper(x[0]) ){ | ||
2022 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2023 | "The precedence symbol must be a terminal."); | ||
2024 | psp->errorcnt++; | ||
2025 | }else if( psp->prevrule==0 ){ | ||
2026 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2027 | "There is no prior rule to assign precedence \"[%s]\".",x); | ||
2028 | psp->errorcnt++; | ||
2029 | }else if( psp->prevrule->precsym!=0 ){ | ||
2030 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2031 | "Precedence mark on this line is not the first \ | ||
2032 | to follow the previous rule."); | ||
2033 | psp->errorcnt++; | ||
2034 | }else{ | ||
2035 | psp->prevrule->precsym = Symbol_new(x); | ||
2036 | } | ||
2037 | psp->state = PRECEDENCE_MARK_2; | ||
2038 | break; | ||
2039 | case PRECEDENCE_MARK_2: | ||
2040 | if( x[0]!=']' ){ | ||
2041 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2042 | "Missing \"]\" on precedence mark."); | ||
2043 | psp->errorcnt++; | ||
2044 | } | ||
2045 | psp->state = WAITING_FOR_DECL_OR_RULE; | ||
2046 | break; | ||
2047 | case WAITING_FOR_ARROW: | ||
2048 | if( x[0]==':' && x[1]==':' && x[2]=='=' ){ | ||
2049 | psp->state = IN_RHS; | ||
2050 | }else if( x[0]=='(' ){ | ||
2051 | psp->state = LHS_ALIAS_1; | ||
2052 | }else{ | ||
2053 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2054 | "Expected to see a \":\" following the LHS symbol \"%s\".", | ||
2055 | psp->lhs->name); | ||
2056 | psp->errorcnt++; | ||
2057 | psp->state = RESYNC_AFTER_RULE_ERROR; | ||
2058 | } | ||
2059 | break; | ||
2060 | case LHS_ALIAS_1: | ||
2061 | if( isalpha(x[0]) ){ | ||
2062 | psp->lhsalias = x; | ||
2063 | psp->state = LHS_ALIAS_2; | ||
2064 | }else{ | ||
2065 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2066 | "\"%s\" is not a valid alias for the LHS \"%s\"\n", | ||
2067 | x,psp->lhs->name); | ||
2068 | psp->errorcnt++; | ||
2069 | psp->state = RESYNC_AFTER_RULE_ERROR; | ||
2070 | } | ||
2071 | break; | ||
2072 | case LHS_ALIAS_2: | ||
2073 | if( x[0]==')' ){ | ||
2074 | psp->state = LHS_ALIAS_3; | ||
2075 | }else{ | ||
2076 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2077 | "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); | ||
2078 | psp->errorcnt++; | ||
2079 | psp->state = RESYNC_AFTER_RULE_ERROR; | ||
2080 | } | ||
2081 | break; | ||
2082 | case LHS_ALIAS_3: | ||
2083 | if( x[0]==':' && x[1]==':' && x[2]=='=' ){ | ||
2084 | psp->state = IN_RHS; | ||
2085 | }else{ | ||
2086 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2087 | "Missing \"->\" following: \"%s(%s)\".", | ||
2088 | psp->lhs->name,psp->lhsalias); | ||
2089 | psp->errorcnt++; | ||
2090 | psp->state = RESYNC_AFTER_RULE_ERROR; | ||
2091 | } | ||
2092 | break; | ||
2093 | case IN_RHS: | ||
2094 | if( x[0]=='.' ){ | ||
2095 | struct rule *rp; | ||
2096 | rp = (struct rule *)calloc( sizeof(struct rule) + | ||
2097 | sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1); | ||
2098 | if( rp==0 ){ | ||
2099 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2100 | "Can't allocate enough memory for this rule."); | ||
2101 | psp->errorcnt++; | ||
2102 | psp->prevrule = 0; | ||
2103 | }else{ | ||
2104 | int i; | ||
2105 | rp->ruleline = psp->tokenlineno; | ||
2106 | rp->rhs = (struct symbol**)&rp[1]; | ||
2107 | rp->rhsalias = (const char**)&(rp->rhs[psp->nrhs]); | ||
2108 | for(i=0; i<psp->nrhs; i++){ | ||
2109 | rp->rhs[i] = psp->rhs[i]; | ||
2110 | rp->rhsalias[i] = psp->alias[i]; | ||
2111 | } | ||
2112 | rp->lhs = psp->lhs; | ||
2113 | rp->lhsalias = psp->lhsalias; | ||
2114 | rp->nrhs = psp->nrhs; | ||
2115 | rp->code = 0; | ||
2116 | rp->precsym = 0; | ||
2117 | rp->index = psp->gp->nrule++; | ||
2118 | rp->nextlhs = rp->lhs->rule; | ||
2119 | rp->lhs->rule = rp; | ||
2120 | rp->next = 0; | ||
2121 | if( psp->firstrule==0 ){ | ||
2122 | psp->firstrule = psp->lastrule = rp; | ||
2123 | }else{ | ||
2124 | psp->lastrule->next = rp; | ||
2125 | psp->lastrule = rp; | ||
2126 | } | ||
2127 | psp->prevrule = rp; | ||
2128 | } | ||
2129 | psp->state = WAITING_FOR_DECL_OR_RULE; | ||
2130 | }else if( isalpha(x[0]) ){ | ||
2131 | if( psp->nrhs>=MAXRHS ){ | ||
2132 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2133 | "Too many symbols on RHS of rule beginning at \"%s\".", | ||
2134 | x); | ||
2135 | psp->errorcnt++; | ||
2136 | psp->state = RESYNC_AFTER_RULE_ERROR; | ||
2137 | }else{ | ||
2138 | psp->rhs[psp->nrhs] = Symbol_new(x); | ||
2139 | psp->alias[psp->nrhs] = 0; | ||
2140 | psp->nrhs++; | ||
2141 | } | ||
2142 | }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){ | ||
2143 | struct symbol *msp = psp->rhs[psp->nrhs-1]; | ||
2144 | if( msp->type!=MULTITERMINAL ){ | ||
2145 | struct symbol *origsp = msp; | ||
2146 | msp = (struct symbol *) calloc(1,sizeof(*msp)); | ||
2147 | memset(msp, 0, sizeof(*msp)); | ||
2148 | msp->type = MULTITERMINAL; | ||
2149 | msp->nsubsym = 1; | ||
2150 | msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*)); | ||
2151 | msp->subsym[0] = origsp; | ||
2152 | msp->name = origsp->name; | ||
2153 | psp->rhs[psp->nrhs-1] = msp; | ||
2154 | } | ||
2155 | msp->nsubsym++; | ||
2156 | msp->subsym = (struct symbol **) realloc(msp->subsym, | ||
2157 | sizeof(struct symbol*)*msp->nsubsym); | ||
2158 | msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]); | ||
2159 | if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){ | ||
2160 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2161 | "Cannot form a compound containing a non-terminal"); | ||
2162 | psp->errorcnt++; | ||
2163 | } | ||
2164 | }else if( x[0]=='(' && psp->nrhs>0 ){ | ||
2165 | psp->state = RHS_ALIAS_1; | ||
2166 | }else{ | ||
2167 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2168 | "Illegal character on RHS of rule: \"%s\".",x); | ||
2169 | psp->errorcnt++; | ||
2170 | psp->state = RESYNC_AFTER_RULE_ERROR; | ||
2171 | } | ||
2172 | break; | ||
2173 | case RHS_ALIAS_1: | ||
2174 | if( isalpha(x[0]) ){ | ||
2175 | psp->alias[psp->nrhs-1] = x; | ||
2176 | psp->state = RHS_ALIAS_2; | ||
2177 | }else{ | ||
2178 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2179 | "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n", | ||
2180 | x,psp->rhs[psp->nrhs-1]->name); | ||
2181 | psp->errorcnt++; | ||
2182 | psp->state = RESYNC_AFTER_RULE_ERROR; | ||
2183 | } | ||
2184 | break; | ||
2185 | case RHS_ALIAS_2: | ||
2186 | if( x[0]==')' ){ | ||
2187 | psp->state = IN_RHS; | ||
2188 | }else{ | ||
2189 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2190 | "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); | ||
2191 | psp->errorcnt++; | ||
2192 | psp->state = RESYNC_AFTER_RULE_ERROR; | ||
2193 | } | ||
2194 | break; | ||
2195 | case WAITING_FOR_DECL_KEYWORD: | ||
2196 | if( isalpha(x[0]) ){ | ||
2197 | psp->declkeyword = x; | ||
2198 | psp->declargslot = 0; | ||
2199 | psp->decllinenoslot = 0; | ||
2200 | psp->insertLineMacro = 1; | ||
2201 | psp->state = WAITING_FOR_DECL_ARG; | ||
2202 | if( strcmp(x,"name")==0 ){ | ||
2203 | psp->declargslot = &(psp->gp->name); | ||
2204 | psp->insertLineMacro = 0; | ||
2205 | }else if( strcmp(x,"include")==0 ){ | ||
2206 | psp->declargslot = &(psp->gp->include); | ||
2207 | }else if( strcmp(x,"code")==0 ){ | ||
2208 | psp->declargslot = &(psp->gp->extracode); | ||
2209 | }else if( strcmp(x,"token_destructor")==0 ){ | ||
2210 | psp->declargslot = &psp->gp->tokendest; | ||
2211 | }else if( strcmp(x,"default_destructor")==0 ){ | ||
2212 | psp->declargslot = &psp->gp->vardest; | ||
2213 | }else if( strcmp(x,"token_prefix")==0 ){ | ||
2214 | psp->declargslot = &psp->gp->tokenprefix; | ||
2215 | psp->insertLineMacro = 0; | ||
2216 | }else if( strcmp(x,"syntax_error")==0 ){ | ||
2217 | psp->declargslot = &(psp->gp->error); | ||
2218 | }else if( strcmp(x,"parse_accept")==0 ){ | ||
2219 | psp->declargslot = &(psp->gp->accept); | ||
2220 | }else if( strcmp(x,"parse_failure")==0 ){ | ||
2221 | psp->declargslot = &(psp->gp->failure); | ||
2222 | }else if( strcmp(x,"stack_overflow")==0 ){ | ||
2223 | psp->declargslot = &(psp->gp->overflow); | ||
2224 | }else if( strcmp(x,"extra_argument")==0 ){ | ||
2225 | psp->declargslot = &(psp->gp->arg); | ||
2226 | psp->insertLineMacro = 0; | ||
2227 | }else if( strcmp(x,"token_type")==0 ){ | ||
2228 | psp->declargslot = &(psp->gp->tokentype); | ||
2229 | psp->insertLineMacro = 0; | ||
2230 | }else if( strcmp(x,"default_type")==0 ){ | ||
2231 | psp->declargslot = &(psp->gp->vartype); | ||
2232 | psp->insertLineMacro = 0; | ||
2233 | }else if( strcmp(x,"stack_size")==0 ){ | ||
2234 | psp->declargslot = &(psp->gp->stacksize); | ||
2235 | psp->insertLineMacro = 0; | ||
2236 | }else if( strcmp(x,"start_symbol")==0 ){ | ||
2237 | psp->declargslot = &(psp->gp->start); | ||
2238 | psp->insertLineMacro = 0; | ||
2239 | }else if( strcmp(x,"left")==0 ){ | ||
2240 | psp->preccounter++; | ||
2241 | psp->declassoc = LEFT; | ||
2242 | psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; | ||
2243 | }else if( strcmp(x,"right")==0 ){ | ||
2244 | psp->preccounter++; | ||
2245 | psp->declassoc = RIGHT; | ||
2246 | psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; | ||
2247 | }else if( strcmp(x,"nonassoc")==0 ){ | ||
2248 | psp->preccounter++; | ||
2249 | psp->declassoc = NONE; | ||
2250 | psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; | ||
2251 | }else if( strcmp(x,"destructor")==0 ){ | ||
2252 | psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL; | ||
2253 | }else if( strcmp(x,"type")==0 ){ | ||
2254 | psp->state = WAITING_FOR_DATATYPE_SYMBOL; | ||
2255 | }else if( strcmp(x,"fallback")==0 ){ | ||
2256 | psp->fallback = 0; | ||
2257 | psp->state = WAITING_FOR_FALLBACK_ID; | ||
2258 | }else if( strcmp(x,"wildcard")==0 ){ | ||
2259 | psp->state = WAITING_FOR_WILDCARD_ID; | ||
2260 | }else{ | ||
2261 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2262 | "Unknown declaration keyword: \"%%%s\".",x); | ||
2263 | psp->errorcnt++; | ||
2264 | psp->state = RESYNC_AFTER_DECL_ERROR; | ||
2265 | } | ||
2266 | }else{ | ||
2267 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2268 | "Illegal declaration keyword: \"%s\".",x); | ||
2269 | psp->errorcnt++; | ||
2270 | psp->state = RESYNC_AFTER_DECL_ERROR; | ||
2271 | } | ||
2272 | break; | ||
2273 | case WAITING_FOR_DESTRUCTOR_SYMBOL: | ||
2274 | if( !isalpha(x[0]) ){ | ||
2275 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2276 | "Symbol name missing after %%destructor keyword"); | ||
2277 | psp->errorcnt++; | ||
2278 | psp->state = RESYNC_AFTER_DECL_ERROR; | ||
2279 | }else{ | ||
2280 | struct symbol *sp = Symbol_new(x); | ||
2281 | psp->declargslot = &sp->destructor; | ||
2282 | psp->decllinenoslot = &sp->destLineno; | ||
2283 | psp->insertLineMacro = 1; | ||
2284 | psp->state = WAITING_FOR_DECL_ARG; | ||
2285 | } | ||
2286 | break; | ||
2287 | case WAITING_FOR_DATATYPE_SYMBOL: | ||
2288 | if( !isalpha(x[0]) ){ | ||
2289 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2290 | "Symbol name missing after %%type keyword"); | ||
2291 | psp->errorcnt++; | ||
2292 | psp->state = RESYNC_AFTER_DECL_ERROR; | ||
2293 | }else{ | ||
2294 | struct symbol *sp = Symbol_find(x); | ||
2295 | if((sp) && (sp->datatype)){ | ||
2296 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2297 | "Symbol %%type \"%s\" already defined", x); | ||
2298 | psp->errorcnt++; | ||
2299 | psp->state = RESYNC_AFTER_DECL_ERROR; | ||
2300 | }else{ | ||
2301 | if (!sp){ | ||
2302 | sp = Symbol_new(x); | ||
2303 | } | ||
2304 | psp->declargslot = &sp->datatype; | ||
2305 | psp->insertLineMacro = 0; | ||
2306 | psp->state = WAITING_FOR_DECL_ARG; | ||
2307 | } | ||
2308 | } | ||
2309 | break; | ||
2310 | case WAITING_FOR_PRECEDENCE_SYMBOL: | ||
2311 | if( x[0]=='.' ){ | ||
2312 | psp->state = WAITING_FOR_DECL_OR_RULE; | ||
2313 | }else if( isupper(x[0]) ){ | ||
2314 | struct symbol *sp; | ||
2315 | sp = Symbol_new(x); | ||
2316 | if( sp->prec>=0 ){ | ||
2317 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2318 | "Symbol \"%s\" has already be given a precedence.",x); | ||
2319 | psp->errorcnt++; | ||
2320 | }else{ | ||
2321 | sp->prec = psp->preccounter; | ||
2322 | sp->assoc = psp->declassoc; | ||
2323 | } | ||
2324 | }else{ | ||
2325 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2326 | "Can't assign a precedence to \"%s\".",x); | ||
2327 | psp->errorcnt++; | ||
2328 | } | ||
2329 | break; | ||
2330 | case WAITING_FOR_DECL_ARG: | ||
2331 | if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ | ||
2332 | const char *zOld, *zNew; | ||
2333 | char *zBuf, *z; | ||
2334 | int nOld, n, nLine, nNew, nBack; | ||
2335 | int addLineMacro; | ||
2336 | char zLine[50]; | ||
2337 | zNew = x; | ||
2338 | if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; | ||
2339 | nNew = lemonStrlen(zNew); | ||
2340 | if( *psp->declargslot ){ | ||
2341 | zOld = *psp->declargslot; | ||
2342 | }else{ | ||
2343 | zOld = ""; | ||
2344 | } | ||
2345 | nOld = lemonStrlen(zOld); | ||
2346 | n = nOld + nNew + 20; | ||
2347 | addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && | ||
2348 | (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); | ||
2349 | if( addLineMacro ){ | ||
2350 | for(z=psp->filename, nBack=0; *z; z++){ | ||
2351 | if( *z=='\\' ) nBack++; | ||
2352 | } | ||
2353 | sprintf(zLine, "#line %d ", psp->tokenlineno); | ||
2354 | nLine = lemonStrlen(zLine); | ||
2355 | n += nLine + lemonStrlen(psp->filename) + nBack; | ||
2356 | } | ||
2357 | *psp->declargslot = (char *) realloc(*psp->declargslot, n); | ||
2358 | zBuf = *psp->declargslot + nOld; | ||
2359 | if( addLineMacro ){ | ||
2360 | if( nOld && zBuf[-1]!='\n' ){ | ||
2361 | *(zBuf++) = '\n'; | ||
2362 | } | ||
2363 | memcpy(zBuf, zLine, nLine); | ||
2364 | zBuf += nLine; | ||
2365 | *(zBuf++) = '"'; | ||
2366 | for(z=psp->filename; *z; z++){ | ||
2367 | if( *z=='\\' ){ | ||
2368 | *(zBuf++) = '\\'; | ||
2369 | } | ||
2370 | *(zBuf++) = *z; | ||
2371 | } | ||
2372 | *(zBuf++) = '"'; | ||
2373 | *(zBuf++) = '\n'; | ||
2374 | } | ||
2375 | if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ | ||
2376 | psp->decllinenoslot[0] = psp->tokenlineno; | ||
2377 | } | ||
2378 | memcpy(zBuf, zNew, nNew); | ||
2379 | zBuf += nNew; | ||
2380 | *zBuf = 0; | ||
2381 | psp->state = WAITING_FOR_DECL_OR_RULE; | ||
2382 | }else{ | ||
2383 | ErrorMsg(psp->filename,psp->tokenlineno, | ||
2384 | "Illegal argument to %%%s: %s",psp->declkeyword,x); | ||
2385 | psp->errorcnt++; | ||
2386 | psp->state = RESYNC_AFTER_DECL_ERROR; | ||
2387 | } | ||
2388 | break; | ||
2389 | case WAITING_FOR_FALLBACK_ID: | ||
2390 | if( x[0]=='.' ){ | ||
2391 | psp->state = WAITING_FOR_DECL_OR_RULE; | ||
2392 | }else if( !isupper(x[0]) ){ | ||
2393 | ErrorMsg(psp->filename, psp->tokenlineno, | ||
2394 | "%%fallback argument \"%s\" should be a token", x); | ||
2395 | psp->errorcnt++; | ||
2396 | }else{ | ||
2397 | struct symbol *sp = Symbol_new(x); | ||
2398 | if( psp->fallback==0 ){ | ||
2399 | psp->fallback = sp; | ||
2400 | }else if( sp->fallback ){ | ||
2401 | ErrorMsg(psp->filename, psp->tokenlineno, | ||
2402 | "More than one fallback assigned to token %s", x); | ||
2403 | psp->errorcnt++; | ||
2404 | }else{ | ||
2405 | sp->fallback = psp->fallback; | ||
2406 | psp->gp->has_fallback = 1; | ||
2407 | } | ||
2408 | } | ||
2409 | break; | ||
2410 | case WAITING_FOR_WILDCARD_ID: | ||
2411 | if( x[0]=='.' ){ | ||
2412 | psp->state = WAITING_FOR_DECL_OR_RULE; | ||
2413 | }else if( !isupper(x[0]) ){ | ||
2414 | ErrorMsg(psp->filename, psp->tokenlineno, | ||
2415 | "%%wildcard argument \"%s\" should be a token", x); | ||
2416 | psp->errorcnt++; | ||
2417 | }else{ | ||
2418 | struct symbol *sp = Symbol_new(x); | ||
2419 | if( psp->gp->wildcard==0 ){ | ||
2420 | psp->gp->wildcard = sp; | ||
2421 | }else{ | ||
2422 | ErrorMsg(psp->filename, psp->tokenlineno, | ||
2423 | "Extra wildcard to token: %s", x); | ||
2424 | psp->errorcnt++; | ||
2425 | } | ||
2426 | } | ||
2427 | break; | ||
2428 | case RESYNC_AFTER_RULE_ERROR: | ||
2429 | /* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; | ||
2430 | ** break; */ | ||
2431 | case RESYNC_AFTER_DECL_ERROR: | ||
2432 | if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; | ||
2433 | if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD; | ||
2434 | break; | ||
2435 | } | ||
2436 | } | ||
2437 | |||
2438 | /* Run the preprocessor over the input file text. The global variables | ||
2439 | ** azDefine[0] through azDefine[nDefine-1] contains the names of all defined | ||
2440 | ** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and | ||
2441 | ** comments them out. Text in between is also commented out as appropriate. | ||
2442 | */ | ||
2443 | static void preprocess_input(char *z){ | ||
2444 | int i, j, k, n; | ||
2445 | int exclude = 0; | ||
2446 | int start = 0; | ||
2447 | int lineno = 1; | ||
2448 | int start_lineno = 1; | ||
2449 | for(i=0; z[i]; i++){ | ||
2450 | if( z[i]=='\n' ) lineno++; | ||
2451 | if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue; | ||
2452 | if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){ | ||
2453 | if( exclude ){ | ||
2454 | exclude--; | ||
2455 | if( exclude==0 ){ | ||
2456 | for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' '; | ||
2457 | } | ||
2458 | } | ||
2459 | for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; | ||
2460 | }else if( (strncmp(&z[i],"%ifdef",6)==0 && isspace(z[i+6])) | ||
2461 | || (strncmp(&z[i],"%ifndef",7)==0 && isspace(z[i+7])) ){ | ||
2462 | if( exclude ){ | ||
2463 | exclude++; | ||
2464 | }else{ | ||
2465 | for(j=i+7; isspace(z[j]); j++){} | ||
2466 | for(n=0; z[j+n] && !isspace(z[j+n]); n++){} | ||
2467 | exclude = 1; | ||
2468 | for(k=0; k<nDefine; k++){ | ||
2469 | if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){ | ||
2470 | exclude = 0; | ||
2471 | break; | ||
2472 | } | ||
2473 | } | ||
2474 | if( z[i+3]=='n' ) exclude = !exclude; | ||
2475 | if( exclude ){ | ||
2476 | start = i; | ||
2477 | start_lineno = lineno; | ||
2478 | } | ||
2479 | } | ||
2480 | for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; | ||
2481 | } | ||
2482 | } | ||
2483 | if( exclude ){ | ||
2484 | fprintf(stderr,"unterminated %%ifdef starting on line %d\n", start_lineno); | ||
2485 | exit(1); | ||
2486 | } | ||
2487 | } | ||
2488 | |||
2489 | /* In spite of its name, this function is really a scanner. It read | ||
2490 | ** in the entire input file (all at once) then tokenizes it. Each | ||
2491 | ** token is passed to the function "parseonetoken" which builds all | ||
2492 | ** the appropriate data structures in the global state vector "gp". | ||
2493 | */ | ||
2494 | void Parse(struct lemon *gp) | ||
2495 | { | ||
2496 | struct pstate ps; | ||
2497 | FILE *fp; | ||
2498 | char *filebuf; | ||
2499 | int filesize; | ||
2500 | int lineno; | ||
2501 | int c; | ||
2502 | char *cp, *nextcp; | ||
2503 | int startline = 0; | ||
2504 | |||
2505 | memset(&ps, '\0', sizeof(ps)); | ||
2506 | ps.gp = gp; | ||
2507 | ps.filename = gp->filename; | ||
2508 | ps.errorcnt = 0; | ||
2509 | ps.state = INITIALIZE; | ||
2510 | |||
2511 | /* Begin by reading the input file */ | ||
2512 | fp = fopen(ps.filename,"rb"); | ||
2513 | if( fp==0 ){ | ||
2514 | ErrorMsg(ps.filename,0,"Can't open this file for reading."); | ||
2515 | gp->errorcnt++; | ||
2516 | return; | ||
2517 | } | ||
2518 | fseek(fp,0,2); | ||
2519 | filesize = ftell(fp); | ||
2520 | rewind(fp); | ||
2521 | filebuf = (char *)malloc( filesize+1 ); | ||
2522 | if( filebuf==0 ){ | ||
2523 | ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.", | ||
2524 | filesize+1); | ||
2525 | gp->errorcnt++; | ||
2526 | fclose(fp); | ||
2527 | return; | ||
2528 | } | ||
2529 | if( fread(filebuf,1,filesize,fp)!=filesize ){ | ||
2530 | ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", | ||
2531 | filesize); | ||
2532 | free(filebuf); | ||
2533 | gp->errorcnt++; | ||
2534 | fclose(fp); | ||
2535 | return; | ||
2536 | } | ||
2537 | fclose(fp); | ||
2538 | filebuf[filesize] = 0; | ||
2539 | |||
2540 | /* Make an initial pass through the file to handle %ifdef and %ifndef */ | ||
2541 | preprocess_input(filebuf); | ||
2542 | |||
2543 | /* Now scan the text of the input file */ | ||
2544 | lineno = 1; | ||
2545 | for(cp=filebuf; (c= *cp)!=0; ){ | ||
2546 | if( c=='\n' ) lineno++; /* Keep track of the line number */ | ||
2547 | if( isspace(c) ){ cp++; continue; } /* Skip all white space */ | ||
2548 | if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ | ||
2549 | cp+=2; | ||
2550 | while( (c= *cp)!=0 && c!='\n' ) cp++; | ||
2551 | continue; | ||
2552 | } | ||
2553 | if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */ | ||
2554 | cp+=2; | ||
2555 | while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){ | ||
2556 | if( c=='\n' ) lineno++; | ||
2557 | cp++; | ||
2558 | } | ||
2559 | if( c ) cp++; | ||
2560 | continue; | ||
2561 | } | ||
2562 | ps.tokenstart = cp; /* Mark the beginning of the token */ | ||
2563 | ps.tokenlineno = lineno; /* Linenumber on which token begins */ | ||
2564 | if( c=='\"' ){ /* String literals */ | ||
2565 | cp++; | ||
2566 | while( (c= *cp)!=0 && c!='\"' ){ | ||
2567 | if( c=='\n' ) lineno++; | ||
2568 | cp++; | ||
2569 | } | ||
2570 | if( c==0 ){ | ||
2571 | ErrorMsg(ps.filename,startline, | ||
2572 | "String starting on this line is not terminated before the end of the file."); | ||
2573 | ps.errorcnt++; | ||
2574 | nextcp = cp; | ||
2575 | }else{ | ||
2576 | nextcp = cp+1; | ||
2577 | } | ||
2578 | }else if( c=='{' ){ /* A block of C code */ | ||
2579 | int level; | ||
2580 | cp++; | ||
2581 | for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){ | ||
2582 | if( c=='\n' ) lineno++; | ||
2583 | else if( c=='{' ) level++; | ||
2584 | else if( c=='}' ) level--; | ||
2585 | else if( c=='/' && cp[1]=='*' ){ /* Skip comments */ | ||
2586 | int prevc; | ||
2587 | cp = &cp[2]; | ||
2588 | prevc = 0; | ||
2589 | while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){ | ||
2590 | if( c=='\n' ) lineno++; | ||
2591 | prevc = c; | ||
2592 | cp++; | ||
2593 | } | ||
2594 | }else if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments too */ | ||
2595 | cp = &cp[2]; | ||
2596 | while( (c= *cp)!=0 && c!='\n' ) cp++; | ||
2597 | if( c ) lineno++; | ||
2598 | }else if( c=='\'' || c=='\"' ){ /* String a character literals */ | ||
2599 | int startchar, prevc; | ||
2600 | startchar = c; | ||
2601 | prevc = 0; | ||
2602 | for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){ | ||
2603 | if( c=='\n' ) lineno++; | ||
2604 | if( prevc=='\\' ) prevc = 0; | ||
2605 | else prevc = c; | ||
2606 | } | ||
2607 | } | ||
2608 | } | ||
2609 | if( c==0 ){ | ||
2610 | ErrorMsg(ps.filename,ps.tokenlineno, | ||
2611 | "C code starting on this line is not terminated before the end of the file."); | ||
2612 | ps.errorcnt++; | ||
2613 | nextcp = cp; | ||
2614 | }else{ | ||
2615 | nextcp = cp+1; | ||
2616 | } | ||
2617 | }else if( isalnum(c) ){ /* Identifiers */ | ||
2618 | while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++; | ||
2619 | nextcp = cp; | ||
2620 | }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */ | ||
2621 | cp += 3; | ||
2622 | nextcp = cp; | ||
2623 | }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){ | ||
2624 | cp += 2; | ||
2625 | while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++; | ||
2626 | nextcp = cp; | ||
2627 | }else{ /* All other (one character) operators */ | ||
2628 | cp++; | ||
2629 | nextcp = cp; | ||
2630 | } | ||
2631 | c = *cp; | ||
2632 | *cp = 0; /* Null terminate the token */ | ||
2633 | parseonetoken(&ps); /* Parse the token */ | ||
2634 | *cp = c; /* Restore the buffer */ | ||
2635 | cp = nextcp; | ||
2636 | } | ||
2637 | free(filebuf); /* Release the buffer after parsing */ | ||
2638 | gp->rule = ps.firstrule; | ||
2639 | gp->errorcnt = ps.errorcnt; | ||
2640 | } | ||
2641 | /*************************** From the file "plink.c" *********************/ | ||
2642 | /* | ||
2643 | ** Routines processing configuration follow-set propagation links | ||
2644 | ** in the LEMON parser generator. | ||
2645 | */ | ||
2646 | static struct plink *plink_freelist = 0; | ||
2647 | |||
2648 | /* Allocate a new plink */ | ||
2649 | struct plink *Plink_new(){ | ||
2650 | struct plink *newlink; | ||
2651 | |||
2652 | if( plink_freelist==0 ){ | ||
2653 | int i; | ||
2654 | int amt = 100; | ||
2655 | plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) ); | ||
2656 | if( plink_freelist==0 ){ | ||
2657 | fprintf(stderr, | ||
2658 | "Unable to allocate memory for a new follow-set propagation link.\n"); | ||
2659 | exit(1); | ||
2660 | } | ||
2661 | for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1]; | ||
2662 | plink_freelist[amt-1].next = 0; | ||
2663 | } | ||
2664 | newlink = plink_freelist; | ||
2665 | plink_freelist = plink_freelist->next; | ||
2666 | return newlink; | ||
2667 | } | ||
2668 | |||
2669 | /* Add a plink to a plink list */ | ||
2670 | void Plink_add(struct plink **plpp, struct config *cfp) | ||
2671 | { | ||
2672 | struct plink *newlink; | ||
2673 | newlink = Plink_new(); | ||
2674 | newlink->next = *plpp; | ||
2675 | *plpp = newlink; | ||
2676 | newlink->cfp = cfp; | ||
2677 | } | ||
2678 | |||
2679 | /* Transfer every plink on the list "from" to the list "to" */ | ||
2680 | void Plink_copy(struct plink **to, struct plink *from) | ||
2681 | { | ||
2682 | struct plink *nextpl; | ||
2683 | while( from ){ | ||
2684 | nextpl = from->next; | ||
2685 | from->next = *to; | ||
2686 | *to = from; | ||
2687 | from = nextpl; | ||
2688 | } | ||
2689 | } | ||
2690 | |||
2691 | /* Delete every plink on the list */ | ||
2692 | void Plink_delete(struct plink *plp) | ||
2693 | { | ||
2694 | struct plink *nextpl; | ||
2695 | |||
2696 | while( plp ){ | ||
2697 | nextpl = plp->next; | ||
2698 | plp->next = plink_freelist; | ||
2699 | plink_freelist = plp; | ||
2700 | plp = nextpl; | ||
2701 | } | ||
2702 | } | ||
2703 | /*********************** From the file "report.c" **************************/ | ||
2704 | /* | ||
2705 | ** Procedures for generating reports and tables in the LEMON parser generator. | ||
2706 | */ | ||
2707 | |||
2708 | /* Generate a filename with the given suffix. Space to hold the | ||
2709 | ** name comes from malloc() and must be freed by the calling | ||
2710 | ** function. | ||
2711 | */ | ||
2712 | PRIVATE char *file_makename(struct lemon *lemp, const char *suffix) | ||
2713 | { | ||
2714 | char *name; | ||
2715 | char *cp; | ||
2716 | |||
2717 | name = (char*)malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 ); | ||
2718 | if( name==0 ){ | ||
2719 | fprintf(stderr,"Can't allocate space for a filename.\n"); | ||
2720 | exit(1); | ||
2721 | } | ||
2722 | strcpy(name,lemp->filename); | ||
2723 | cp = strrchr(name,'.'); | ||
2724 | if( cp ) *cp = 0; | ||
2725 | strcat(name,suffix); | ||
2726 | return name; | ||
2727 | } | ||
2728 | |||
2729 | /* Open a file with a name based on the name of the input file, | ||
2730 | ** but with a different (specified) suffix, and return a pointer | ||
2731 | ** to the stream */ | ||
2732 | PRIVATE FILE *file_open( | ||
2733 | struct lemon *lemp, | ||
2734 | const char *suffix, | ||
2735 | const char *mode | ||
2736 | ){ | ||
2737 | FILE *fp; | ||
2738 | |||
2739 | if( lemp->outname ) free(lemp->outname); | ||
2740 | lemp->outname = file_makename(lemp, suffix); | ||
2741 | fp = fopen(lemp->outname,mode); | ||
2742 | if( fp==0 && *mode=='w' ){ | ||
2743 | fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname); | ||
2744 | lemp->errorcnt++; | ||
2745 | return 0; | ||
2746 | } | ||
2747 | return fp; | ||
2748 | } | ||
2749 | |||
2750 | /* Duplicate the input file without comments and without actions | ||
2751 | ** on rules */ | ||
2752 | void Reprint(struct lemon *lemp) | ||
2753 | { | ||
2754 | struct rule *rp; | ||
2755 | struct symbol *sp; | ||
2756 | int i, j, maxlen, len, ncolumns, skip; | ||
2757 | printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename); | ||
2758 | maxlen = 10; | ||
2759 | for(i=0; i<lemp->nsymbol; i++){ | ||
2760 | sp = lemp->symbols[i]; | ||
2761 | len = lemonStrlen(sp->name); | ||
2762 | if( len>maxlen ) maxlen = len; | ||
2763 | } | ||
2764 | ncolumns = 76/(maxlen+5); | ||
2765 | if( ncolumns<1 ) ncolumns = 1; | ||
2766 | skip = (lemp->nsymbol + ncolumns - 1)/ncolumns; | ||
2767 | for(i=0; i<skip; i++){ | ||
2768 | printf("//"); | ||
2769 | for(j=i; j<lemp->nsymbol; j+=skip){ | ||
2770 | sp = lemp->symbols[j]; | ||
2771 | assert( sp->index==j ); | ||
2772 | printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name); | ||
2773 | } | ||
2774 | printf("\n"); | ||
2775 | } | ||
2776 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
2777 | printf("%s",rp->lhs->name); | ||
2778 | /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */ | ||
2779 | printf(" ::="); | ||
2780 | for(i=0; i<rp->nrhs; i++){ | ||
2781 | sp = rp->rhs[i]; | ||
2782 | printf(" %s", sp->name); | ||
2783 | if( sp->type==MULTITERMINAL ){ | ||
2784 | for(j=1; j<sp->nsubsym; j++){ | ||
2785 | printf("|%s", sp->subsym[j]->name); | ||
2786 | } | ||
2787 | } | ||
2788 | /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */ | ||
2789 | } | ||
2790 | printf("."); | ||
2791 | if( rp->precsym ) printf(" [%s]",rp->precsym->name); | ||
2792 | /* if( rp->code ) printf("\n %s",rp->code); */ | ||
2793 | printf("\n"); | ||
2794 | } | ||
2795 | } | ||
2796 | |||
2797 | void ConfigPrint(FILE *fp, struct config *cfp) | ||
2798 | { | ||
2799 | struct rule *rp; | ||
2800 | struct symbol *sp; | ||
2801 | int i, j; | ||
2802 | rp = cfp->rp; | ||
2803 | fprintf(fp,"%s ::=",rp->lhs->name); | ||
2804 | for(i=0; i<=rp->nrhs; i++){ | ||
2805 | if( i==cfp->dot ) fprintf(fp," *"); | ||
2806 | if( i==rp->nrhs ) break; | ||
2807 | sp = rp->rhs[i]; | ||
2808 | fprintf(fp," %s", sp->name); | ||
2809 | if( sp->type==MULTITERMINAL ){ | ||
2810 | for(j=1; j<sp->nsubsym; j++){ | ||
2811 | fprintf(fp,"|%s",sp->subsym[j]->name); | ||
2812 | } | ||
2813 | } | ||
2814 | } | ||
2815 | } | ||
2816 | |||
2817 | /* #define TEST */ | ||
2818 | #if 0 | ||
2819 | /* Print a set */ | ||
2820 | PRIVATE void SetPrint(out,set,lemp) | ||
2821 | FILE *out; | ||
2822 | char *set; | ||
2823 | struct lemon *lemp; | ||
2824 | { | ||
2825 | int i; | ||
2826 | char *spacer; | ||
2827 | spacer = ""; | ||
2828 | fprintf(out,"%12s[",""); | ||
2829 | for(i=0; i<lemp->nterminal; i++){ | ||
2830 | if( SetFind(set,i) ){ | ||
2831 | fprintf(out,"%s%s",spacer,lemp->symbols[i]->name); | ||
2832 | spacer = " "; | ||
2833 | } | ||
2834 | } | ||
2835 | fprintf(out,"]\n"); | ||
2836 | } | ||
2837 | |||
2838 | /* Print a plink chain */ | ||
2839 | PRIVATE void PlinkPrint(out,plp,tag) | ||
2840 | FILE *out; | ||
2841 | struct plink *plp; | ||
2842 | char *tag; | ||
2843 | { | ||
2844 | while( plp ){ | ||
2845 | fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum); | ||
2846 | ConfigPrint(out,plp->cfp); | ||
2847 | fprintf(out,"\n"); | ||
2848 | plp = plp->next; | ||
2849 | } | ||
2850 | } | ||
2851 | #endif | ||
2852 | |||
2853 | /* Print an action to the given file descriptor. Return FALSE if | ||
2854 | ** nothing was actually printed. | ||
2855 | */ | ||
2856 | int PrintAction(struct action *ap, FILE *fp, int indent){ | ||
2857 | int result = 1; | ||
2858 | switch( ap->type ){ | ||
2859 | case SHIFT: | ||
2860 | fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); | ||
2861 | break; | ||
2862 | case REDUCE: | ||
2863 | fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index); | ||
2864 | break; | ||
2865 | case ACCEPT: | ||
2866 | fprintf(fp,"%*s accept",indent,ap->sp->name); | ||
2867 | break; | ||
2868 | case ERROR: | ||
2869 | fprintf(fp,"%*s error",indent,ap->sp->name); | ||
2870 | break; | ||
2871 | case SRCONFLICT: | ||
2872 | case RRCONFLICT: | ||
2873 | fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", | ||
2874 | indent,ap->sp->name,ap->x.rp->index); | ||
2875 | break; | ||
2876 | case SSCONFLICT: | ||
2877 | fprintf(fp,"%*s shift %-3d ** Parsing conflict **", | ||
2878 | indent,ap->sp->name,ap->x.stp->statenum); | ||
2879 | break; | ||
2880 | case SH_RESOLVED: | ||
2881 | if( showPrecedenceConflict ){ | ||
2882 | fprintf(fp,"%*s shift %-3d -- dropped by precedence", | ||
2883 | indent,ap->sp->name,ap->x.stp->statenum); | ||
2884 | }else{ | ||
2885 | result = 0; | ||
2886 | } | ||
2887 | break; | ||
2888 | case RD_RESOLVED: | ||
2889 | if( showPrecedenceConflict ){ | ||
2890 | fprintf(fp,"%*s reduce %-3d -- dropped by precedence", | ||
2891 | indent,ap->sp->name,ap->x.rp->index); | ||
2892 | }else{ | ||
2893 | result = 0; | ||
2894 | } | ||
2895 | break; | ||
2896 | case NOT_USED: | ||
2897 | result = 0; | ||
2898 | break; | ||
2899 | } | ||
2900 | return result; | ||
2901 | } | ||
2902 | |||
2903 | /* Generate the "y.output" log file */ | ||
2904 | void ReportOutput(struct lemon *lemp) | ||
2905 | { | ||
2906 | int i; | ||
2907 | struct state *stp; | ||
2908 | struct config *cfp; | ||
2909 | struct action *ap; | ||
2910 | FILE *fp; | ||
2911 | |||
2912 | fp = file_open(lemp,".out","wb"); | ||
2913 | if( fp==0 ) return; | ||
2914 | for(i=0; i<lemp->nstate; i++){ | ||
2915 | stp = lemp->sorted[i]; | ||
2916 | fprintf(fp,"State %d:\n",stp->statenum); | ||
2917 | if( lemp->basisflag ) cfp=stp->bp; | ||
2918 | else cfp=stp->cfp; | ||
2919 | while( cfp ){ | ||
2920 | char buf[20]; | ||
2921 | if( cfp->dot==cfp->rp->nrhs ){ | ||
2922 | sprintf(buf,"(%d)",cfp->rp->index); | ||
2923 | fprintf(fp," %5s ",buf); | ||
2924 | }else{ | ||
2925 | fprintf(fp," "); | ||
2926 | } | ||
2927 | ConfigPrint(fp,cfp); | ||
2928 | fprintf(fp,"\n"); | ||
2929 | #if 0 | ||
2930 | SetPrint(fp,cfp->fws,lemp); | ||
2931 | PlinkPrint(fp,cfp->fplp,"To "); | ||
2932 | PlinkPrint(fp,cfp->bplp,"From"); | ||
2933 | #endif | ||
2934 | if( lemp->basisflag ) cfp=cfp->bp; | ||
2935 | else cfp=cfp->next; | ||
2936 | } | ||
2937 | fprintf(fp,"\n"); | ||
2938 | for(ap=stp->ap; ap; ap=ap->next){ | ||
2939 | if( PrintAction(ap,fp,30) ) fprintf(fp,"\n"); | ||
2940 | } | ||
2941 | fprintf(fp,"\n"); | ||
2942 | } | ||
2943 | fprintf(fp, "----------------------------------------------------\n"); | ||
2944 | fprintf(fp, "Symbols:\n"); | ||
2945 | for(i=0; i<lemp->nsymbol; i++){ | ||
2946 | int j; | ||
2947 | struct symbol *sp; | ||
2948 | |||
2949 | sp = lemp->symbols[i]; | ||
2950 | fprintf(fp, " %3d: %s", i, sp->name); | ||
2951 | if( sp->type==NONTERMINAL ){ | ||
2952 | fprintf(fp, ":"); | ||
2953 | if( sp->lambda ){ | ||
2954 | fprintf(fp, " <lambda>"); | ||
2955 | } | ||
2956 | for(j=0; j<lemp->nterminal; j++){ | ||
2957 | if( sp->firstset && SetFind(sp->firstset, j) ){ | ||
2958 | fprintf(fp, " %s", lemp->symbols[j]->name); | ||
2959 | } | ||
2960 | } | ||
2961 | } | ||
2962 | fprintf(fp, "\n"); | ||
2963 | } | ||
2964 | fclose(fp); | ||
2965 | return; | ||
2966 | } | ||
2967 | |||
2968 | /* Search for the file "name" which is in the same directory as | ||
2969 | ** the exacutable */ | ||
2970 | PRIVATE char *pathsearch(char *argv0, char *name, int modemask) | ||
2971 | { | ||
2972 | const char *pathlist; | ||
2973 | char *pathbufptr; | ||
2974 | char *pathbuf; | ||
2975 | char *path,*cp; | ||
2976 | char c; | ||
2977 | |||
2978 | #ifdef __WIN32__ | ||
2979 | cp = strrchr(argv0,'\\'); | ||
2980 | #else | ||
2981 | cp = strrchr(argv0,'/'); | ||
2982 | #endif | ||
2983 | if( cp ){ | ||
2984 | c = *cp; | ||
2985 | *cp = 0; | ||
2986 | path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); | ||
2987 | if( path ) sprintf(path,"%s/%s",argv0,name); | ||
2988 | *cp = c; | ||
2989 | }else{ | ||
2990 | pathlist = getenv("PATH"); | ||
2991 | if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; | ||
2992 | pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 ); | ||
2993 | path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); | ||
2994 | if( (pathbuf != 0) && (path!=0) ){ | ||
2995 | pathbufptr = pathbuf; | ||
2996 | strcpy(pathbuf, pathlist); | ||
2997 | while( *pathbuf ){ | ||
2998 | cp = strchr(pathbuf,':'); | ||
2999 | if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)]; | ||
3000 | c = *cp; | ||
3001 | *cp = 0; | ||
3002 | sprintf(path,"%s/%s",pathbuf,name); | ||
3003 | *cp = c; | ||
3004 | if( c==0 ) pathbuf[0] = 0; | ||
3005 | else pathbuf = &cp[1]; | ||
3006 | if( access(path,modemask)==0 ) break; | ||
3007 | } | ||
3008 | free(pathbufptr); | ||
3009 | } | ||
3010 | } | ||
3011 | return path; | ||
3012 | } | ||
3013 | |||
3014 | /* Given an action, compute the integer value for that action | ||
3015 | ** which is to be put in the action table of the generated machine. | ||
3016 | ** Return negative if no action should be generated. | ||
3017 | */ | ||
3018 | PRIVATE int compute_action(struct lemon *lemp, struct action *ap) | ||
3019 | { | ||
3020 | int act; | ||
3021 | switch( ap->type ){ | ||
3022 | case SHIFT: act = ap->x.stp->statenum; break; | ||
3023 | case REDUCE: act = ap->x.rp->index + lemp->nstate; break; | ||
3024 | case ERROR: act = lemp->nstate + lemp->nrule; break; | ||
3025 | case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break; | ||
3026 | default: act = -1; break; | ||
3027 | } | ||
3028 | return act; | ||
3029 | } | ||
3030 | |||
3031 | #define LINESIZE 1000 | ||
3032 | /* The next cluster of routines are for reading the template file | ||
3033 | ** and writing the results to the generated parser */ | ||
3034 | /* The first function transfers data from "in" to "out" until | ||
3035 | ** a line is seen which begins with "%%". The line number is | ||
3036 | ** tracked. | ||
3037 | ** | ||
3038 | ** if name!=0, then any word that begin with "Parse" is changed to | ||
3039 | ** begin with *name instead. | ||
3040 | */ | ||
3041 | PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno) | ||
3042 | { | ||
3043 | int i, iStart; | ||
3044 | char line[LINESIZE]; | ||
3045 | while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){ | ||
3046 | (*lineno)++; | ||
3047 | iStart = 0; | ||
3048 | if( name ){ | ||
3049 | for(i=0; line[i]; i++){ | ||
3050 | if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0 | ||
3051 | && (i==0 || !isalpha(line[i-1])) | ||
3052 | ){ | ||
3053 | if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]); | ||
3054 | fprintf(out,"%s",name); | ||
3055 | i += 4; | ||
3056 | iStart = i+1; | ||
3057 | } | ||
3058 | } | ||
3059 | } | ||
3060 | fprintf(out,"%s",&line[iStart]); | ||
3061 | } | ||
3062 | } | ||
3063 | |||
3064 | /* The next function finds the template file and opens it, returning | ||
3065 | ** a pointer to the opened file. */ | ||
3066 | PRIVATE FILE *tplt_open(struct lemon *lemp) | ||
3067 | { | ||
3068 | static char templatename[] = "lempar.c"; | ||
3069 | char buf[1000]; | ||
3070 | FILE *in; | ||
3071 | char *tpltname; | ||
3072 | char *cp; | ||
3073 | |||
3074 | /* first, see if user specified a template filename on the command line. */ | ||
3075 | if (user_templatename != 0) { | ||
3076 | if( access(user_templatename,004)==-1 ){ | ||
3077 | fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", | ||
3078 | user_templatename); | ||
3079 | lemp->errorcnt++; | ||
3080 | return 0; | ||
3081 | } | ||
3082 | in = fopen(user_templatename,"rb"); | ||
3083 | if( in==0 ){ | ||
3084 | fprintf(stderr,"Can't open the template file \"%s\".\n",user_templatename); | ||
3085 | lemp->errorcnt++; | ||
3086 | return 0; | ||
3087 | } | ||
3088 | return in; | ||
3089 | } | ||
3090 | |||
3091 | cp = strrchr(lemp->filename,'.'); | ||
3092 | if( cp ){ | ||
3093 | sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename); | ||
3094 | }else{ | ||
3095 | sprintf(buf,"%s.lt",lemp->filename); | ||
3096 | } | ||
3097 | if( access(buf,004)==0 ){ | ||
3098 | tpltname = buf; | ||
3099 | }else if( access(templatename,004)==0 ){ | ||
3100 | tpltname = templatename; | ||
3101 | }else{ | ||
3102 | tpltname = pathsearch(lemp->argv0,templatename,0); | ||
3103 | } | ||
3104 | if( tpltname==0 ){ | ||
3105 | fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", | ||
3106 | templatename); | ||
3107 | lemp->errorcnt++; | ||
3108 | return 0; | ||
3109 | } | ||
3110 | in = fopen(tpltname,"rb"); | ||
3111 | if( in==0 ){ | ||
3112 | fprintf(stderr,"Can't open the template file \"%s\".\n",templatename); | ||
3113 | lemp->errorcnt++; | ||
3114 | return 0; | ||
3115 | } | ||
3116 | return in; | ||
3117 | } | ||
3118 | |||
3119 | /* Print a #line directive line to the output file. */ | ||
3120 | PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename) | ||
3121 | { | ||
3122 | fprintf(out,"#line %d \"",lineno); | ||
3123 | while( *filename ){ | ||
3124 | if( *filename == '\\' ) putc('\\',out); | ||
3125 | putc(*filename,out); | ||
3126 | filename++; | ||
3127 | } | ||
3128 | fprintf(out,"\"\n"); | ||
3129 | } | ||
3130 | |||
3131 | /* Print a string to the file and keep the linenumber up to date */ | ||
3132 | PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno) | ||
3133 | { | ||
3134 | if( str==0 ) return; | ||
3135 | while( *str ){ | ||
3136 | putc(*str,out); | ||
3137 | if( *str=='\n' ) (*lineno)++; | ||
3138 | str++; | ||
3139 | } | ||
3140 | if( str[-1]!='\n' ){ | ||
3141 | putc('\n',out); | ||
3142 | (*lineno)++; | ||
3143 | } | ||
3144 | if (!lemp->nolinenosflag) { | ||
3145 | (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); | ||
3146 | } | ||
3147 | return; | ||
3148 | } | ||
3149 | |||
3150 | /* | ||
3151 | ** The following routine emits code for the destructor for the | ||
3152 | ** symbol sp | ||
3153 | */ | ||
3154 | void emit_destructor_code( | ||
3155 | FILE *out, | ||
3156 | struct symbol *sp, | ||
3157 | struct lemon *lemp, | ||
3158 | int *lineno | ||
3159 | ){ | ||
3160 | char *cp = 0; | ||
3161 | |||
3162 | if( sp->type==TERMINAL ){ | ||
3163 | cp = lemp->tokendest; | ||
3164 | if( cp==0 ) return; | ||
3165 | fprintf(out,"{\n"); (*lineno)++; | ||
3166 | }else if( sp->destructor ){ | ||
3167 | cp = sp->destructor; | ||
3168 | fprintf(out,"{\n"); (*lineno)++; | ||
3169 | if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,sp->destLineno,lemp->filename); } | ||
3170 | }else if( lemp->vardest ){ | ||
3171 | cp = lemp->vardest; | ||
3172 | if( cp==0 ) return; | ||
3173 | fprintf(out,"{\n"); (*lineno)++; | ||
3174 | }else{ | ||
3175 | assert( 0 ); /* Cannot happen */ | ||
3176 | } | ||
3177 | for(; *cp; cp++){ | ||
3178 | if( *cp=='$' && cp[1]=='$' ){ | ||
3179 | fprintf(out,"(yypminor->yy%d)",sp->dtnum); | ||
3180 | cp++; | ||
3181 | continue; | ||
3182 | } | ||
3183 | if( *cp=='\n' ) (*lineno)++; | ||
3184 | fputc(*cp,out); | ||
3185 | } | ||
3186 | fprintf(out,"\n"); (*lineno)++; | ||
3187 | if (!lemp->nolinenosflag) { | ||
3188 | (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); | ||
3189 | } | ||
3190 | fprintf(out,"}\n"); (*lineno)++; | ||
3191 | return; | ||
3192 | } | ||
3193 | |||
3194 | /* | ||
3195 | ** Return TRUE (non-zero) if the given symbol has a destructor. | ||
3196 | */ | ||
3197 | int has_destructor(struct symbol *sp, struct lemon *lemp) | ||
3198 | { | ||
3199 | int ret; | ||
3200 | if( sp->type==TERMINAL ){ | ||
3201 | ret = lemp->tokendest!=0; | ||
3202 | }else{ | ||
3203 | ret = lemp->vardest!=0 || sp->destructor!=0; | ||
3204 | } | ||
3205 | return ret; | ||
3206 | } | ||
3207 | |||
3208 | /* | ||
3209 | ** Append text to a dynamically allocated string. If zText is 0 then | ||
3210 | ** reset the string to be empty again. Always return the complete text | ||
3211 | ** of the string (which is overwritten with each call). | ||
3212 | ** | ||
3213 | ** n bytes of zText are stored. If n==0 then all of zText up to the first | ||
3214 | ** \000 terminator is stored. zText can contain up to two instances of | ||
3215 | ** %d. The values of p1 and p2 are written into the first and second | ||
3216 | ** %d. | ||
3217 | ** | ||
3218 | ** If n==-1, then the previous character is overwritten. | ||
3219 | */ | ||
3220 | PRIVATE char *append_str(const char *zText, int n, int p1, int p2){ | ||
3221 | static char empty[1] = { 0 }; | ||
3222 | static char *z = 0; | ||
3223 | static int alloced = 0; | ||
3224 | static int used = 0; | ||
3225 | int c; | ||
3226 | char zInt[40]; | ||
3227 | if( zText==0 ){ | ||
3228 | used = 0; | ||
3229 | return z; | ||
3230 | } | ||
3231 | if( n<=0 ){ | ||
3232 | if( n<0 ){ | ||
3233 | used += n; | ||
3234 | assert( used>=0 ); | ||
3235 | } | ||
3236 | n = lemonStrlen(zText); | ||
3237 | } | ||
3238 | if( (int) (n+sizeof(zInt)*2+used) >= alloced ){ | ||
3239 | alloced = n + sizeof(zInt)*2 + used + 200; | ||
3240 | z = (char *) realloc(z, alloced); | ||
3241 | } | ||
3242 | if( z==0 ) return empty; | ||
3243 | while( n-- > 0 ){ | ||
3244 | c = *(zText++); | ||
3245 | if( c=='%' && n>0 && zText[0]=='d' ){ | ||
3246 | sprintf(zInt, "%d", p1); | ||
3247 | p1 = p2; | ||
3248 | strcpy(&z[used], zInt); | ||
3249 | used += lemonStrlen(&z[used]); | ||
3250 | zText++; | ||
3251 | n--; | ||
3252 | }else{ | ||
3253 | z[used++] = c; | ||
3254 | } | ||
3255 | } | ||
3256 | z[used] = 0; | ||
3257 | return z; | ||
3258 | } | ||
3259 | |||
3260 | /* | ||
3261 | ** zCode is a string that is the action associated with a rule. Expand | ||
3262 | ** the symbols in this string so that the refer to elements of the parser | ||
3263 | ** stack. | ||
3264 | */ | ||
3265 | PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ | ||
3266 | char *cp, *xp; | ||
3267 | int i; | ||
3268 | char lhsused = 0; /* True if the LHS element has been used */ | ||
3269 | char used[MAXRHS]; /* True for each RHS element which is used */ | ||
3270 | |||
3271 | for(i=0; i<rp->nrhs; i++) used[i] = 0; | ||
3272 | lhsused = 0; | ||
3273 | |||
3274 | if( rp->code==0 ){ | ||
3275 | static char newlinestr[2] = { '\n', '\0' }; | ||
3276 | rp->code = newlinestr; | ||
3277 | rp->line = rp->ruleline; | ||
3278 | } | ||
3279 | |||
3280 | append_str(0,0,0,0); | ||
3281 | |||
3282 | /* This const cast is wrong but harmless, if we're careful. */ | ||
3283 | for(cp=(char *)rp->code; *cp; cp++){ | ||
3284 | if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ | ||
3285 | char saved; | ||
3286 | for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++); | ||
3287 | saved = *xp; | ||
3288 | *xp = 0; | ||
3289 | if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ | ||
3290 | append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0); | ||
3291 | cp = xp; | ||
3292 | lhsused = 1; | ||
3293 | }else{ | ||
3294 | for(i=0; i<rp->nrhs; i++){ | ||
3295 | if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ | ||
3296 | if( cp!=rp->code && cp[-1]=='@' ){ | ||
3297 | /* If the argument is of the form @X then substituted | ||
3298 | ** the token number of X, not the value of X */ | ||
3299 | append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0); | ||
3300 | }else{ | ||
3301 | struct symbol *sp = rp->rhs[i]; | ||
3302 | int dtnum; | ||
3303 | if( sp->type==MULTITERMINAL ){ | ||
3304 | dtnum = sp->subsym[0]->dtnum; | ||
3305 | }else{ | ||
3306 | dtnum = sp->dtnum; | ||
3307 | } | ||
3308 | append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum); | ||
3309 | } | ||
3310 | cp = xp; | ||
3311 | used[i] = 1; | ||
3312 | break; | ||
3313 | } | ||
3314 | } | ||
3315 | } | ||
3316 | *xp = saved; | ||
3317 | } | ||
3318 | append_str(cp, 1, 0, 0); | ||
3319 | } /* End loop */ | ||
3320 | |||
3321 | /* Check to make sure the LHS has been used */ | ||
3322 | if( rp->lhsalias && !lhsused ){ | ||
3323 | ErrorMsg(lemp->filename,rp->ruleline, | ||
3324 | "Label \"%s\" for \"%s(%s)\" is never used.", | ||
3325 | rp->lhsalias,rp->lhs->name,rp->lhsalias); | ||
3326 | lemp->errorcnt++; | ||
3327 | } | ||
3328 | |||
3329 | /* Generate destructor code for RHS symbols which are not used in the | ||
3330 | ** reduce code */ | ||
3331 | for(i=0; i<rp->nrhs; i++){ | ||
3332 | if( rp->rhsalias[i] && !used[i] ){ | ||
3333 | ErrorMsg(lemp->filename,rp->ruleline, | ||
3334 | "Label %s for \"%s(%s)\" is never used.", | ||
3335 | rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); | ||
3336 | lemp->errorcnt++; | ||
3337 | }else if( rp->rhsalias[i]==0 ){ | ||
3338 | if( has_destructor(rp->rhs[i],lemp) ){ | ||
3339 | append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, | ||
3340 | rp->rhs[i]->index,i-rp->nrhs+1); | ||
3341 | }else{ | ||
3342 | /* No destructor defined for this term */ | ||
3343 | } | ||
3344 | } | ||
3345 | } | ||
3346 | if( rp->code ){ | ||
3347 | cp = append_str(0,0,0,0); | ||
3348 | rp->code = Strsafe(cp?cp:""); | ||
3349 | } | ||
3350 | } | ||
3351 | |||
3352 | /* | ||
3353 | ** Generate code which executes when the rule "rp" is reduced. Write | ||
3354 | ** the code to "out". Make sure lineno stays up-to-date. | ||
3355 | */ | ||
3356 | PRIVATE void emit_code( | ||
3357 | FILE *out, | ||
3358 | struct rule *rp, | ||
3359 | struct lemon *lemp, | ||
3360 | int *lineno | ||
3361 | ){ | ||
3362 | const char *cp; | ||
3363 | |||
3364 | /* Generate code to do the reduce action */ | ||
3365 | if( rp->code ){ | ||
3366 | if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,rp->line,lemp->filename); } | ||
3367 | fprintf(out,"{%s",rp->code); | ||
3368 | for(cp=rp->code; *cp; cp++){ | ||
3369 | if( *cp=='\n' ) (*lineno)++; | ||
3370 | } /* End loop */ | ||
3371 | fprintf(out,"}\n"); (*lineno)++; | ||
3372 | if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); } | ||
3373 | } /* End if( rp->code ) */ | ||
3374 | |||
3375 | return; | ||
3376 | } | ||
3377 | |||
3378 | /* | ||
3379 | ** Print the definition of the union used for the parser's data stack. | ||
3380 | ** This union contains fields for every possible data type for tokens | ||
3381 | ** and nonterminals. In the process of computing and printing this | ||
3382 | ** union, also set the ".dtnum" field of every terminal and nonterminal | ||
3383 | ** symbol. | ||
3384 | */ | ||
3385 | void print_stack_union( | ||
3386 | FILE *out, /* The output stream */ | ||
3387 | struct lemon *lemp, /* The main info structure for this parser */ | ||
3388 | int *plineno, /* Pointer to the line number */ | ||
3389 | int mhflag /* True if generating makeheaders output */ | ||
3390 | ){ | ||
3391 | int lineno = *plineno; /* The line number of the output */ | ||
3392 | char **types; /* A hash table of datatypes */ | ||
3393 | int arraysize; /* Size of the "types" array */ | ||
3394 | int maxdtlength; /* Maximum length of any ".datatype" field. */ | ||
3395 | char *stddt; /* Standardized name for a datatype */ | ||
3396 | int i,j; /* Loop counters */ | ||
3397 | int hash; /* For hashing the name of a type */ | ||
3398 | const char *name; /* Name of the parser */ | ||
3399 | |||
3400 | /* Allocate and initialize types[] and allocate stddt[] */ | ||
3401 | arraysize = lemp->nsymbol * 2; | ||
3402 | types = (char**)calloc( arraysize, sizeof(char*) ); | ||
3403 | if( types==0 ){ | ||
3404 | fprintf(stderr,"Out of memory.\n"); | ||
3405 | exit(1); | ||
3406 | } | ||
3407 | for(i=0; i<arraysize; i++) types[i] = 0; | ||
3408 | maxdtlength = 0; | ||
3409 | if( lemp->vartype ){ | ||
3410 | maxdtlength = lemonStrlen(lemp->vartype); | ||
3411 | } | ||
3412 | for(i=0; i<lemp->nsymbol; i++){ | ||
3413 | int len; | ||
3414 | struct symbol *sp = lemp->symbols[i]; | ||
3415 | if( sp->datatype==0 ) continue; | ||
3416 | len = lemonStrlen(sp->datatype); | ||
3417 | if( len>maxdtlength ) maxdtlength = len; | ||
3418 | } | ||
3419 | stddt = (char*)malloc( maxdtlength*2 + 1 ); | ||
3420 | if( stddt==0 ){ | ||
3421 | fprintf(stderr,"Out of memory.\n"); | ||
3422 | exit(1); | ||
3423 | } | ||
3424 | |||
3425 | /* Build a hash table of datatypes. The ".dtnum" field of each symbol | ||
3426 | ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is | ||
3427 | ** used for terminal symbols. If there is no %default_type defined then | ||
3428 | ** 0 is also used as the .dtnum value for nonterminals which do not specify | ||
3429 | ** a datatype using the %type directive. | ||
3430 | */ | ||
3431 | for(i=0; i<lemp->nsymbol; i++){ | ||
3432 | struct symbol *sp = lemp->symbols[i]; | ||
3433 | char *cp; | ||
3434 | if( sp==lemp->errsym ){ | ||
3435 | sp->dtnum = arraysize+1; | ||
3436 | continue; | ||
3437 | } | ||
3438 | if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){ | ||
3439 | sp->dtnum = 0; | ||
3440 | continue; | ||
3441 | } | ||
3442 | cp = sp->datatype; | ||
3443 | if( cp==0 ) cp = lemp->vartype; | ||
3444 | j = 0; | ||
3445 | while( isspace(*cp) ) cp++; | ||
3446 | while( *cp ) stddt[j++] = *cp++; | ||
3447 | while( j>0 && isspace(stddt[j-1]) ) j--; | ||
3448 | stddt[j] = 0; | ||
3449 | if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){ | ||
3450 | sp->dtnum = 0; | ||
3451 | continue; | ||
3452 | } | ||
3453 | hash = 0; | ||
3454 | for(j=0; stddt[j]; j++){ | ||
3455 | hash = hash*53 + stddt[j]; | ||
3456 | } | ||
3457 | hash = (hash & 0x7fffffff)%arraysize; | ||
3458 | while( types[hash] ){ | ||
3459 | if( strcmp(types[hash],stddt)==0 ){ | ||
3460 | sp->dtnum = hash + 1; | ||
3461 | break; | ||
3462 | } | ||
3463 | hash++; | ||
3464 | if( hash>=arraysize ) hash = 0; | ||
3465 | } | ||
3466 | if( types[hash]==0 ){ | ||
3467 | sp->dtnum = hash + 1; | ||
3468 | types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); | ||
3469 | if( types[hash]==0 ){ | ||
3470 | fprintf(stderr,"Out of memory.\n"); | ||
3471 | exit(1); | ||
3472 | } | ||
3473 | strcpy(types[hash],stddt); | ||
3474 | } | ||
3475 | } | ||
3476 | |||
3477 | /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */ | ||
3478 | name = lemp->name ? lemp->name : "Parse"; | ||
3479 | lineno = *plineno; | ||
3480 | if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; } | ||
3481 | fprintf(out,"#define %sTOKENTYPE %s\n",name, | ||
3482 | lemp->tokentype?lemp->tokentype:"void*"); lineno++; | ||
3483 | if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } | ||
3484 | fprintf(out,"typedef union {\n"); lineno++; | ||
3485 | fprintf(out," int yyinit;\n"); lineno++; | ||
3486 | fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; | ||
3487 | for(i=0; i<arraysize; i++){ | ||
3488 | if( types[i]==0 ) continue; | ||
3489 | fprintf(out," %s yy%d;\n",types[i],i+1); lineno++; | ||
3490 | free(types[i]); | ||
3491 | } | ||
3492 | if( lemp->errsym->useCnt ){ | ||
3493 | fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++; | ||
3494 | } | ||
3495 | free(stddt); | ||
3496 | free(types); | ||
3497 | fprintf(out,"} YYMINORTYPE;\n"); lineno++; | ||
3498 | *plineno = lineno; | ||
3499 | } | ||
3500 | |||
3501 | /* | ||
3502 | ** Return the name of a C datatype able to represent values between | ||
3503 | ** lwr and upr, inclusive. | ||
3504 | */ | ||
3505 | static const char *minimum_size_type(int lwr, int upr){ | ||
3506 | if( lwr>=0 ){ | ||
3507 | if( upr<=255 ){ | ||
3508 | return "unsigned char"; | ||
3509 | }else if( upr<65535 ){ | ||
3510 | return "unsigned short int"; | ||
3511 | }else{ | ||
3512 | return "unsigned int"; | ||
3513 | } | ||
3514 | }else if( lwr>=-127 && upr<=127 ){ | ||
3515 | return "signed char"; | ||
3516 | }else if( lwr>=-32767 && upr<32767 ){ | ||
3517 | return "short"; | ||
3518 | }else{ | ||
3519 | return "int"; | ||
3520 | } | ||
3521 | } | ||
3522 | |||
3523 | /* | ||
3524 | ** Each state contains a set of token transaction and a set of | ||
3525 | ** nonterminal transactions. Each of these sets makes an instance | ||
3526 | ** of the following structure. An array of these structures is used | ||
3527 | ** to order the creation of entries in the yy_action[] table. | ||
3528 | */ | ||
3529 | struct axset { | ||
3530 | struct state *stp; /* A pointer to a state */ | ||
3531 | int isTkn; /* True to use tokens. False for non-terminals */ | ||
3532 | int nAction; /* Number of actions */ | ||
3533 | int iOrder; /* Original order of action sets */ | ||
3534 | }; | ||
3535 | |||
3536 | /* | ||
3537 | ** Compare to axset structures for sorting purposes | ||
3538 | */ | ||
3539 | static int axset_compare(const void *a, const void *b){ | ||
3540 | struct axset *p1 = (struct axset*)a; | ||
3541 | struct axset *p2 = (struct axset*)b; | ||
3542 | int c; | ||
3543 | c = p2->nAction - p1->nAction; | ||
3544 | if( c==0 ){ | ||
3545 | c = p2->iOrder - p1->iOrder; | ||
3546 | } | ||
3547 | assert( c!=0 || p1==p2 ); | ||
3548 | return c; | ||
3549 | } | ||
3550 | |||
3551 | /* | ||
3552 | ** Write text on "out" that describes the rule "rp". | ||
3553 | */ | ||
3554 | static void writeRuleText(FILE *out, struct rule *rp){ | ||
3555 | int j; | ||
3556 | fprintf(out,"%s ::=", rp->lhs->name); | ||
3557 | for(j=0; j<rp->nrhs; j++){ | ||
3558 | struct symbol *sp = rp->rhs[j]; | ||
3559 | fprintf(out," %s", sp->name); | ||
3560 | if( sp->type==MULTITERMINAL ){ | ||
3561 | int k; | ||
3562 | for(k=1; k<sp->nsubsym; k++){ | ||
3563 | fprintf(out,"|%s",sp->subsym[k]->name); | ||
3564 | } | ||
3565 | } | ||
3566 | } | ||
3567 | } | ||
3568 | |||
3569 | |||
3570 | /* Generate C source code for the parser */ | ||
3571 | void ReportTable( | ||
3572 | struct lemon *lemp, | ||
3573 | int mhflag /* Output in makeheaders format if true */ | ||
3574 | ){ | ||
3575 | FILE *out, *in; | ||
3576 | char line[LINESIZE]; | ||
3577 | int lineno; | ||
3578 | struct state *stp; | ||
3579 | struct action *ap; | ||
3580 | struct rule *rp; | ||
3581 | struct acttab *pActtab; | ||
3582 | int i, j, n; | ||
3583 | const char *name; | ||
3584 | int mnTknOfst, mxTknOfst; | ||
3585 | int mnNtOfst, mxNtOfst; | ||
3586 | struct axset *ax; | ||
3587 | |||
3588 | in = tplt_open(lemp); | ||
3589 | if( in==0 ) return; | ||
3590 | out = file_open(lemp,".c","wb"); | ||
3591 | if( out==0 ){ | ||
3592 | fclose(in); | ||
3593 | return; | ||
3594 | } | ||
3595 | lineno = 1; | ||
3596 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3597 | |||
3598 | /* Generate the include code, if any */ | ||
3599 | tplt_print(out,lemp,lemp->include,&lineno); | ||
3600 | if( mhflag ){ | ||
3601 | char *name = file_makename(lemp, ".h"); | ||
3602 | fprintf(out,"#include \"%s\"\n", name); lineno++; | ||
3603 | free(name); | ||
3604 | } | ||
3605 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3606 | |||
3607 | /* Generate #defines for all tokens */ | ||
3608 | if( mhflag ){ | ||
3609 | const char *prefix; | ||
3610 | fprintf(out,"#if INTERFACE\n"); lineno++; | ||
3611 | if( lemp->tokenprefix ) prefix = lemp->tokenprefix; | ||
3612 | else prefix = ""; | ||
3613 | for(i=1; i<lemp->nterminal; i++){ | ||
3614 | fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); | ||
3615 | lineno++; | ||
3616 | } | ||
3617 | fprintf(out,"#endif\n"); lineno++; | ||
3618 | } | ||
3619 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3620 | |||
3621 | /* Generate the defines */ | ||
3622 | fprintf(out,"#define YYCODETYPE %s\n", | ||
3623 | minimum_size_type(0, lemp->nsymbol+1)); lineno++; | ||
3624 | fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; | ||
3625 | fprintf(out,"#define YYACTIONTYPE %s\n", | ||
3626 | minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; | ||
3627 | if( lemp->wildcard ){ | ||
3628 | fprintf(out,"#define YYWILDCARD %d\n", | ||
3629 | lemp->wildcard->index); lineno++; | ||
3630 | } | ||
3631 | print_stack_union(out,lemp,&lineno,mhflag); | ||
3632 | fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++; | ||
3633 | if( lemp->stacksize ){ | ||
3634 | fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++; | ||
3635 | }else{ | ||
3636 | fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++; | ||
3637 | } | ||
3638 | fprintf(out, "#endif\n"); lineno++; | ||
3639 | if( mhflag ){ | ||
3640 | fprintf(out,"#if INTERFACE\n"); lineno++; | ||
3641 | } | ||
3642 | name = lemp->name ? lemp->name : "Parse"; | ||
3643 | if( lemp->arg && lemp->arg[0] ){ | ||
3644 | int i; | ||
3645 | i = lemonStrlen(lemp->arg); | ||
3646 | while( i>=1 && isspace(lemp->arg[i-1]) ) i--; | ||
3647 | while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; | ||
3648 | fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; | ||
3649 | fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++; | ||
3650 | fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n", | ||
3651 | name,lemp->arg,&lemp->arg[i]); lineno++; | ||
3652 | fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n", | ||
3653 | name,&lemp->arg[i],&lemp->arg[i]); lineno++; | ||
3654 | }else{ | ||
3655 | fprintf(out,"#define %sARG_SDECL\n",name); lineno++; | ||
3656 | fprintf(out,"#define %sARG_PDECL\n",name); lineno++; | ||
3657 | fprintf(out,"#define %sARG_FETCH\n",name); lineno++; | ||
3658 | fprintf(out,"#define %sARG_STORE\n",name); lineno++; | ||
3659 | } | ||
3660 | if( mhflag ){ | ||
3661 | fprintf(out,"#endif\n"); lineno++; | ||
3662 | } | ||
3663 | fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++; | ||
3664 | fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; | ||
3665 | if( lemp->errsym->useCnt ){ | ||
3666 | fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; | ||
3667 | fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; | ||
3668 | } | ||
3669 | if( lemp->has_fallback ){ | ||
3670 | fprintf(out,"#define YYFALLBACK 1\n"); lineno++; | ||
3671 | } | ||
3672 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3673 | |||
3674 | /* Generate the action table and its associates: | ||
3675 | ** | ||
3676 | ** yy_action[] A single table containing all actions. | ||
3677 | ** yy_lookahead[] A table containing the lookahead for each entry in | ||
3678 | ** yy_action. Used to detect hash collisions. | ||
3679 | ** yy_shift_ofst[] For each state, the offset into yy_action for | ||
3680 | ** shifting terminals. | ||
3681 | ** yy_reduce_ofst[] For each state, the offset into yy_action for | ||
3682 | ** shifting non-terminals after a reduce. | ||
3683 | ** yy_default[] Default action for each state. | ||
3684 | */ | ||
3685 | |||
3686 | /* Compute the actions on all states and count them up */ | ||
3687 | ax = (struct axset *) calloc(lemp->nstate*2, sizeof(ax[0])); | ||
3688 | if( ax==0 ){ | ||
3689 | fprintf(stderr,"malloc failed\n"); | ||
3690 | exit(1); | ||
3691 | } | ||
3692 | for(i=0; i<lemp->nstate; i++){ | ||
3693 | stp = lemp->sorted[i]; | ||
3694 | ax[i*2].stp = stp; | ||
3695 | ax[i*2].isTkn = 1; | ||
3696 | ax[i*2].nAction = stp->nTknAct; | ||
3697 | ax[i*2+1].stp = stp; | ||
3698 | ax[i*2+1].isTkn = 0; | ||
3699 | ax[i*2+1].nAction = stp->nNtAct; | ||
3700 | } | ||
3701 | mxTknOfst = mnTknOfst = 0; | ||
3702 | mxNtOfst = mnNtOfst = 0; | ||
3703 | |||
3704 | /* Compute the action table. In order to try to keep the size of the | ||
3705 | ** action table to a minimum, the heuristic of placing the largest action | ||
3706 | ** sets first is used. | ||
3707 | */ | ||
3708 | for(i=0; i<lemp->nstate*2; i++) ax[i].iOrder = i; | ||
3709 | qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); | ||
3710 | pActtab = acttab_alloc(); | ||
3711 | for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){ | ||
3712 | stp = ax[i].stp; | ||
3713 | if( ax[i].isTkn ){ | ||
3714 | for(ap=stp->ap; ap; ap=ap->next){ | ||
3715 | int action; | ||
3716 | if( ap->sp->index>=lemp->nterminal ) continue; | ||
3717 | action = compute_action(lemp, ap); | ||
3718 | if( action<0 ) continue; | ||
3719 | acttab_action(pActtab, ap->sp->index, action); | ||
3720 | } | ||
3721 | stp->iTknOfst = acttab_insert(pActtab); | ||
3722 | if( stp->iTknOfst<mnTknOfst ) mnTknOfst = stp->iTknOfst; | ||
3723 | if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst; | ||
3724 | }else{ | ||
3725 | for(ap=stp->ap; ap; ap=ap->next){ | ||
3726 | int action; | ||
3727 | if( ap->sp->index<lemp->nterminal ) continue; | ||
3728 | if( ap->sp->index==lemp->nsymbol ) continue; | ||
3729 | action = compute_action(lemp, ap); | ||
3730 | if( action<0 ) continue; | ||
3731 | acttab_action(pActtab, ap->sp->index, action); | ||
3732 | } | ||
3733 | stp->iNtOfst = acttab_insert(pActtab); | ||
3734 | if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst; | ||
3735 | if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; | ||
3736 | } | ||
3737 | } | ||
3738 | free(ax); | ||
3739 | |||
3740 | /* Output the yy_action table */ | ||
3741 | n = acttab_size(pActtab); | ||
3742 | fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++; | ||
3743 | fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; | ||
3744 | for(i=j=0; i<n; i++){ | ||
3745 | int action = acttab_yyaction(pActtab, i); | ||
3746 | if( action<0 ) action = lemp->nstate + lemp->nrule + 2; | ||
3747 | if( j==0 ) fprintf(out," /* %5d */ ", i); | ||
3748 | fprintf(out, " %4d,", action); | ||
3749 | if( j==9 || i==n-1 ){ | ||
3750 | fprintf(out, "\n"); lineno++; | ||
3751 | j = 0; | ||
3752 | }else{ | ||
3753 | j++; | ||
3754 | } | ||
3755 | } | ||
3756 | fprintf(out, "};\n"); lineno++; | ||
3757 | |||
3758 | /* Output the yy_lookahead table */ | ||
3759 | fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; | ||
3760 | for(i=j=0; i<n; i++){ | ||
3761 | int la = acttab_yylookahead(pActtab, i); | ||
3762 | if( la<0 ) la = lemp->nsymbol; | ||
3763 | if( j==0 ) fprintf(out," /* %5d */ ", i); | ||
3764 | fprintf(out, " %4d,", la); | ||
3765 | if( j==9 || i==n-1 ){ | ||
3766 | fprintf(out, "\n"); lineno++; | ||
3767 | j = 0; | ||
3768 | }else{ | ||
3769 | j++; | ||
3770 | } | ||
3771 | } | ||
3772 | fprintf(out, "};\n"); lineno++; | ||
3773 | |||
3774 | /* Output the yy_shift_ofst[] table */ | ||
3775 | fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; | ||
3776 | n = lemp->nstate; | ||
3777 | while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; | ||
3778 | fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; | ||
3779 | fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; | ||
3780 | fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; | ||
3781 | fprintf(out, "static const %s yy_shift_ofst[] = {\n", | ||
3782 | minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; | ||
3783 | for(i=j=0; i<n; i++){ | ||
3784 | int ofst; | ||
3785 | stp = lemp->sorted[i]; | ||
3786 | ofst = stp->iTknOfst; | ||
3787 | if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; | ||
3788 | if( j==0 ) fprintf(out," /* %5d */ ", i); | ||
3789 | fprintf(out, " %4d,", ofst); | ||
3790 | if( j==9 || i==n-1 ){ | ||
3791 | fprintf(out, "\n"); lineno++; | ||
3792 | j = 0; | ||
3793 | }else{ | ||
3794 | j++; | ||
3795 | } | ||
3796 | } | ||
3797 | fprintf(out, "};\n"); lineno++; | ||
3798 | |||
3799 | /* Output the yy_reduce_ofst[] table */ | ||
3800 | fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; | ||
3801 | n = lemp->nstate; | ||
3802 | while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; | ||
3803 | fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++; | ||
3804 | fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; | ||
3805 | fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++; | ||
3806 | fprintf(out, "static const %s yy_reduce_ofst[] = {\n", | ||
3807 | minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; | ||
3808 | for(i=j=0; i<n; i++){ | ||
3809 | int ofst; | ||
3810 | stp = lemp->sorted[i]; | ||
3811 | ofst = stp->iNtOfst; | ||
3812 | if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1; | ||
3813 | if( j==0 ) fprintf(out," /* %5d */ ", i); | ||
3814 | fprintf(out, " %4d,", ofst); | ||
3815 | if( j==9 || i==n-1 ){ | ||
3816 | fprintf(out, "\n"); lineno++; | ||
3817 | j = 0; | ||
3818 | }else{ | ||
3819 | j++; | ||
3820 | } | ||
3821 | } | ||
3822 | fprintf(out, "};\n"); lineno++; | ||
3823 | |||
3824 | /* Output the default action table */ | ||
3825 | fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; | ||
3826 | n = lemp->nstate; | ||
3827 | for(i=j=0; i<n; i++){ | ||
3828 | stp = lemp->sorted[i]; | ||
3829 | if( j==0 ) fprintf(out," /* %5d */ ", i); | ||
3830 | fprintf(out, " %4d,", stp->iDflt); | ||
3831 | if( j==9 || i==n-1 ){ | ||
3832 | fprintf(out, "\n"); lineno++; | ||
3833 | j = 0; | ||
3834 | }else{ | ||
3835 | j++; | ||
3836 | } | ||
3837 | } | ||
3838 | fprintf(out, "};\n"); lineno++; | ||
3839 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3840 | |||
3841 | /* Generate the table of fallback tokens. | ||
3842 | */ | ||
3843 | if( lemp->has_fallback ){ | ||
3844 | int mx = lemp->nterminal - 1; | ||
3845 | while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } | ||
3846 | for(i=0; i<=mx; i++){ | ||
3847 | struct symbol *p = lemp->symbols[i]; | ||
3848 | if( p->fallback==0 ){ | ||
3849 | fprintf(out, " 0, /* %10s => nothing */\n", p->name); | ||
3850 | }else{ | ||
3851 | fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index, | ||
3852 | p->name, p->fallback->name); | ||
3853 | } | ||
3854 | lineno++; | ||
3855 | } | ||
3856 | } | ||
3857 | tplt_xfer(lemp->name, in, out, &lineno); | ||
3858 | |||
3859 | /* Generate a table containing the symbolic name of every symbol | ||
3860 | */ | ||
3861 | for(i=0; i<lemp->nsymbol; i++){ | ||
3862 | sprintf(line,"\"%s\",",lemp->symbols[i]->name); | ||
3863 | fprintf(out," %-15s",line); | ||
3864 | if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; } | ||
3865 | } | ||
3866 | if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; } | ||
3867 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3868 | |||
3869 | /* Generate a table containing a text string that describes every | ||
3870 | ** rule in the rule set of the grammar. This information is used | ||
3871 | ** when tracing REDUCE actions. | ||
3872 | */ | ||
3873 | for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ | ||
3874 | assert( rp->index==i ); | ||
3875 | fprintf(out," /* %3d */ \"", i); | ||
3876 | writeRuleText(out, rp); | ||
3877 | fprintf(out,"\",\n"); lineno++; | ||
3878 | } | ||
3879 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3880 | |||
3881 | /* Generate code which executes every time a symbol is popped from | ||
3882 | ** the stack while processing errors or while destroying the parser. | ||
3883 | ** (In other words, generate the %destructor actions) | ||
3884 | */ | ||
3885 | if( lemp->tokendest ){ | ||
3886 | int once = 1; | ||
3887 | for(i=0; i<lemp->nsymbol; i++){ | ||
3888 | struct symbol *sp = lemp->symbols[i]; | ||
3889 | if( sp==0 || sp->type!=TERMINAL ) continue; | ||
3890 | if( once ){ | ||
3891 | fprintf(out, " /* TERMINAL Destructor */\n"); lineno++; | ||
3892 | once = 0; | ||
3893 | } | ||
3894 | fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; | ||
3895 | } | ||
3896 | for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++); | ||
3897 | if( i<lemp->nsymbol ){ | ||
3898 | emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); | ||
3899 | fprintf(out," break;\n"); lineno++; | ||
3900 | } | ||
3901 | } | ||
3902 | if( lemp->vardest ){ | ||
3903 | struct symbol *dflt_sp = 0; | ||
3904 | int once = 1; | ||
3905 | for(i=0; i<lemp->nsymbol; i++){ | ||
3906 | struct symbol *sp = lemp->symbols[i]; | ||
3907 | if( sp==0 || sp->type==TERMINAL || | ||
3908 | sp->index<=0 || sp->destructor!=0 ) continue; | ||
3909 | if( once ){ | ||
3910 | fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++; | ||
3911 | once = 0; | ||
3912 | } | ||
3913 | fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; | ||
3914 | dflt_sp = sp; | ||
3915 | } | ||
3916 | if( dflt_sp!=0 ){ | ||
3917 | emit_destructor_code(out,dflt_sp,lemp,&lineno); | ||
3918 | } | ||
3919 | fprintf(out," break;\n"); lineno++; | ||
3920 | } | ||
3921 | for(i=0; i<lemp->nsymbol; i++){ | ||
3922 | struct symbol *sp = lemp->symbols[i]; | ||
3923 | if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; | ||
3924 | fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; | ||
3925 | |||
3926 | /* Combine duplicate destructors into a single case */ | ||
3927 | for(j=i+1; j<lemp->nsymbol; j++){ | ||
3928 | struct symbol *sp2 = lemp->symbols[j]; | ||
3929 | if( sp2 && sp2->type!=TERMINAL && sp2->destructor | ||
3930 | && sp2->dtnum==sp->dtnum | ||
3931 | && strcmp(sp->destructor,sp2->destructor)==0 ){ | ||
3932 | fprintf(out," case %d: /* %s */\n", | ||
3933 | sp2->index, sp2->name); lineno++; | ||
3934 | sp2->destructor = 0; | ||
3935 | } | ||
3936 | } | ||
3937 | |||
3938 | emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); | ||
3939 | fprintf(out," break;\n"); lineno++; | ||
3940 | } | ||
3941 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3942 | |||
3943 | /* Generate code which executes whenever the parser stack overflows */ | ||
3944 | tplt_print(out,lemp,lemp->overflow,&lineno); | ||
3945 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3946 | |||
3947 | /* Generate the table of rule information | ||
3948 | ** | ||
3949 | ** Note: This code depends on the fact that rules are number | ||
3950 | ** sequentually beginning with 0. | ||
3951 | */ | ||
3952 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
3953 | fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++; | ||
3954 | } | ||
3955 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3956 | |||
3957 | /* Generate code which execution during each REDUCE action */ | ||
3958 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
3959 | translate_code(lemp, rp); | ||
3960 | } | ||
3961 | /* First output rules other than the default: rule */ | ||
3962 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
3963 | struct rule *rp2; /* Other rules with the same action */ | ||
3964 | if( rp->code==0 ) continue; | ||
3965 | if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ | ||
3966 | fprintf(out," case %d: /* ", rp->index); | ||
3967 | writeRuleText(out, rp); | ||
3968 | fprintf(out, " */\n"); lineno++; | ||
3969 | for(rp2=rp->next; rp2; rp2=rp2->next){ | ||
3970 | if( rp2->code==rp->code ){ | ||
3971 | fprintf(out," case %d: /* ", rp2->index); | ||
3972 | writeRuleText(out, rp2); | ||
3973 | fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++; | ||
3974 | rp2->code = 0; | ||
3975 | } | ||
3976 | } | ||
3977 | emit_code(out,rp,lemp,&lineno); | ||
3978 | fprintf(out," break;\n"); lineno++; | ||
3979 | rp->code = 0; | ||
3980 | } | ||
3981 | /* Finally, output the default: rule. We choose as the default: all | ||
3982 | ** empty actions. */ | ||
3983 | fprintf(out," default:\n"); lineno++; | ||
3984 | for(rp=lemp->rule; rp; rp=rp->next){ | ||
3985 | if( rp->code==0 ) continue; | ||
3986 | assert( rp->code[0]=='\n' && rp->code[1]==0 ); | ||
3987 | fprintf(out," /* (%d) ", rp->index); | ||
3988 | writeRuleText(out, rp); | ||
3989 | fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->index); lineno++; | ||
3990 | } | ||
3991 | fprintf(out," break;\n"); lineno++; | ||
3992 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3993 | |||
3994 | /* Generate code which executes if a parse fails */ | ||
3995 | tplt_print(out,lemp,lemp->failure,&lineno); | ||
3996 | tplt_xfer(lemp->name,in,out,&lineno); | ||
3997 | |||
3998 | /* Generate code which executes when a syntax error occurs */ | ||
3999 | tplt_print(out,lemp,lemp->error,&lineno); | ||
4000 | tplt_xfer(lemp->name,in,out,&lineno); | ||
4001 | |||
4002 | /* Generate code which executes when the parser accepts its input */ | ||
4003 | tplt_print(out,lemp,lemp->accept,&lineno); | ||
4004 | tplt_xfer(lemp->name,in,out,&lineno); | ||
4005 | |||
4006 | /* Append any addition code the user desires */ | ||
4007 | tplt_print(out,lemp,lemp->extracode,&lineno); | ||
4008 | |||
4009 | fclose(in); | ||
4010 | fclose(out); | ||
4011 | return; | ||
4012 | } | ||
4013 | |||
4014 | /* Generate a header file for the parser */ | ||
4015 | void ReportHeader(struct lemon *lemp) | ||
4016 | { | ||
4017 | FILE *out, *in; | ||
4018 | const char *prefix; | ||
4019 | char line[LINESIZE]; | ||
4020 | char pattern[LINESIZE]; | ||
4021 | int i; | ||
4022 | |||
4023 | if( lemp->tokenprefix ) prefix = lemp->tokenprefix; | ||
4024 | else prefix = ""; | ||
4025 | in = file_open(lemp,".h","rb"); | ||
4026 | if( in ){ | ||
4027 | for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){ | ||
4028 | sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); | ||
4029 | if( strcmp(line,pattern) ) break; | ||
4030 | } | ||
4031 | fclose(in); | ||
4032 | if( i==lemp->nterminal ){ | ||
4033 | /* No change in the file. Don't rewrite it. */ | ||
4034 | return; | ||
4035 | } | ||
4036 | } | ||
4037 | out = file_open(lemp,".h","wb"); | ||
4038 | if( out ){ | ||
4039 | for(i=1; i<lemp->nterminal; i++){ | ||
4040 | fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); | ||
4041 | } | ||
4042 | fclose(out); | ||
4043 | } | ||
4044 | return; | ||
4045 | } | ||
4046 | |||
4047 | /* Reduce the size of the action tables, if possible, by making use | ||
4048 | ** of defaults. | ||
4049 | ** | ||
4050 | ** In this version, we take the most frequent REDUCE action and make | ||
4051 | ** it the default. Except, there is no default if the wildcard token | ||
4052 | ** is a possible look-ahead. | ||
4053 | */ | ||
4054 | void CompressTables(struct lemon *lemp) | ||
4055 | { | ||
4056 | struct state *stp; | ||
4057 | struct action *ap, *ap2; | ||
4058 | struct rule *rp, *rp2, *rbest; | ||
4059 | int nbest, n; | ||
4060 | int i; | ||
4061 | int usesWildcard; | ||
4062 | |||
4063 | for(i=0; i<lemp->nstate; i++){ | ||
4064 | stp = lemp->sorted[i]; | ||
4065 | nbest = 0; | ||
4066 | rbest = 0; | ||
4067 | usesWildcard = 0; | ||
4068 | |||
4069 | for(ap=stp->ap; ap; ap=ap->next){ | ||
4070 | if( ap->type==SHIFT && ap->sp==lemp->wildcard ){ | ||
4071 | usesWildcard = 1; | ||
4072 | } | ||
4073 | if( ap->type!=REDUCE ) continue; | ||
4074 | rp = ap->x.rp; | ||
4075 | if( rp->lhsStart ) continue; | ||
4076 | if( rp==rbest ) continue; | ||
4077 | n = 1; | ||
4078 | for(ap2=ap->next; ap2; ap2=ap2->next){ | ||
4079 | if( ap2->type!=REDUCE ) continue; | ||
4080 | rp2 = ap2->x.rp; | ||
4081 | if( rp2==rbest ) continue; | ||
4082 | if( rp2==rp ) n++; | ||
4083 | } | ||
4084 | if( n>nbest ){ | ||
4085 | nbest = n; | ||
4086 | rbest = rp; | ||
4087 | } | ||
4088 | } | ||
4089 | |||
4090 | /* Do not make a default if the number of rules to default | ||
4091 | ** is not at least 1 or if the wildcard token is a possible | ||
4092 | ** lookahead. | ||
4093 | */ | ||
4094 | if( nbest<1 || usesWildcard ) continue; | ||
4095 | |||
4096 | |||
4097 | /* Combine matching REDUCE actions into a single default */ | ||
4098 | for(ap=stp->ap; ap; ap=ap->next){ | ||
4099 | if( ap->type==REDUCE && ap->x.rp==rbest ) break; | ||
4100 | } | ||
4101 | assert( ap ); | ||
4102 | ap->sp = Symbol_new("{default}"); | ||
4103 | for(ap=ap->next; ap; ap=ap->next){ | ||
4104 | if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; | ||
4105 | } | ||
4106 | stp->ap = Action_sort(stp->ap); | ||
4107 | } | ||
4108 | } | ||
4109 | |||
4110 | |||
4111 | /* | ||
4112 | ** Compare two states for sorting purposes. The smaller state is the | ||
4113 | ** one with the most non-terminal actions. If they have the same number | ||
4114 | ** of non-terminal actions, then the smaller is the one with the most | ||
4115 | ** token actions. | ||
4116 | */ | ||
4117 | static int stateResortCompare(const void *a, const void *b){ | ||
4118 | const struct state *pA = *(const struct state**)a; | ||
4119 | const struct state *pB = *(const struct state**)b; | ||
4120 | int n; | ||
4121 | |||
4122 | n = pB->nNtAct - pA->nNtAct; | ||
4123 | if( n==0 ){ | ||
4124 | n = pB->nTknAct - pA->nTknAct; | ||
4125 | if( n==0 ){ | ||
4126 | n = pB->statenum - pA->statenum; | ||
4127 | } | ||
4128 | } | ||
4129 | assert( n!=0 ); | ||
4130 | return n; | ||
4131 | } | ||
4132 | |||
4133 | |||
4134 | /* | ||
4135 | ** Renumber and resort states so that states with fewer choices | ||
4136 | ** occur at the end. Except, keep state 0 as the first state. | ||
4137 | */ | ||
4138 | void ResortStates(struct lemon *lemp) | ||
4139 | { | ||
4140 | int i; | ||
4141 | struct state *stp; | ||
4142 | struct action *ap; | ||
4143 | |||
4144 | for(i=0; i<lemp->nstate; i++){ | ||
4145 | stp = lemp->sorted[i]; | ||
4146 | stp->nTknAct = stp->nNtAct = 0; | ||
4147 | stp->iDflt = lemp->nstate + lemp->nrule; | ||
4148 | stp->iTknOfst = NO_OFFSET; | ||
4149 | stp->iNtOfst = NO_OFFSET; | ||
4150 | for(ap=stp->ap; ap; ap=ap->next){ | ||
4151 | if( compute_action(lemp,ap)>=0 ){ | ||
4152 | if( ap->sp->index<lemp->nterminal ){ | ||
4153 | stp->nTknAct++; | ||
4154 | }else if( ap->sp->index<lemp->nsymbol ){ | ||
4155 | stp->nNtAct++; | ||
4156 | }else{ | ||
4157 | stp->iDflt = compute_action(lemp, ap); | ||
4158 | } | ||
4159 | } | ||
4160 | } | ||
4161 | } | ||
4162 | qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]), | ||
4163 | stateResortCompare); | ||
4164 | for(i=0; i<lemp->nstate; i++){ | ||
4165 | lemp->sorted[i]->statenum = i; | ||
4166 | } | ||
4167 | } | ||
4168 | |||
4169 | |||
4170 | /***************** From the file "set.c" ************************************/ | ||
4171 | /* | ||
4172 | ** Set manipulation routines for the LEMON parser generator. | ||
4173 | */ | ||
4174 | |||
4175 | static int size = 0; | ||
4176 | |||
4177 | /* Set the set size */ | ||
4178 | void SetSize(int n) | ||
4179 | { | ||
4180 | size = n+1; | ||
4181 | } | ||
4182 | |||
4183 | /* Allocate a new set */ | ||
4184 | char *SetNew(){ | ||
4185 | char *s; | ||
4186 | s = (char*)calloc( size, 1); | ||
4187 | if( s==0 ){ | ||
4188 | extern void memory_error(); | ||
4189 | memory_error(); | ||
4190 | } | ||
4191 | return s; | ||
4192 | } | ||
4193 | |||
4194 | /* Deallocate a set */ | ||
4195 | void SetFree(char *s) | ||
4196 | { | ||
4197 | free(s); | ||
4198 | } | ||
4199 | |||
4200 | /* Add a new element to the set. Return TRUE if the element was added | ||
4201 | ** and FALSE if it was already there. */ | ||
4202 | int SetAdd(char *s, int e) | ||
4203 | { | ||
4204 | int rv; | ||
4205 | assert( e>=0 && e<size ); | ||
4206 | rv = s[e]; | ||
4207 | s[e] = 1; | ||
4208 | return !rv; | ||
4209 | } | ||
4210 | |||
4211 | /* Add every element of s2 to s1. Return TRUE if s1 changes. */ | ||
4212 | int SetUnion(char *s1, char *s2) | ||
4213 | { | ||
4214 | int i, progress; | ||
4215 | progress = 0; | ||
4216 | for(i=0; i<size; i++){ | ||
4217 | if( s2[i]==0 ) continue; | ||
4218 | if( s1[i]==0 ){ | ||
4219 | progress = 1; | ||
4220 | s1[i] = 1; | ||
4221 | } | ||
4222 | } | ||
4223 | return progress; | ||
4224 | } | ||
4225 | /********************** From the file "table.c" ****************************/ | ||
4226 | /* | ||
4227 | ** All code in this file has been automatically generated | ||
4228 | ** from a specification in the file | ||
4229 | ** "table.q" | ||
4230 | ** by the associative array code building program "aagen". | ||
4231 | ** Do not edit this file! Instead, edit the specification | ||
4232 | ** file, then rerun aagen. | ||
4233 | */ | ||
4234 | /* | ||
4235 | ** Code for processing tables in the LEMON parser generator. | ||
4236 | */ | ||
4237 | |||
4238 | PRIVATE int strhash(const char *x) | ||
4239 | { | ||
4240 | int h = 0; | ||
4241 | while( *x) h = h*13 + *(x++); | ||
4242 | return h; | ||
4243 | } | ||
4244 | |||
4245 | /* Works like strdup, sort of. Save a string in malloced memory, but | ||
4246 | ** keep strings in a table so that the same string is not in more | ||
4247 | ** than one place. | ||
4248 | */ | ||
4249 | const char *Strsafe(const char *y) | ||
4250 | { | ||
4251 | const char *z; | ||
4252 | char *cpy; | ||
4253 | |||
4254 | if( y==0 ) return 0; | ||
4255 | z = Strsafe_find(y); | ||
4256 | if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){ | ||
4257 | strcpy(cpy,y); | ||
4258 | z = cpy; | ||
4259 | Strsafe_insert(z); | ||
4260 | } | ||
4261 | MemoryCheck(z); | ||
4262 | return z; | ||
4263 | } | ||
4264 | |||
4265 | /* There is one instance of the following structure for each | ||
4266 | ** associative array of type "x1". | ||
4267 | */ | ||
4268 | struct s_x1 { | ||
4269 | int size; /* The number of available slots. */ | ||
4270 | /* Must be a power of 2 greater than or */ | ||
4271 | /* equal to 1 */ | ||
4272 | int count; /* Number of currently slots filled */ | ||
4273 | struct s_x1node *tbl; /* The data stored here */ | ||
4274 | struct s_x1node **ht; /* Hash table for lookups */ | ||
4275 | }; | ||
4276 | |||
4277 | /* There is one instance of this structure for every data element | ||
4278 | ** in an associative array of type "x1". | ||
4279 | */ | ||
4280 | typedef struct s_x1node { | ||
4281 | const char *data; /* The data */ | ||
4282 | struct s_x1node *next; /* Next entry with the same hash */ | ||
4283 | struct s_x1node **from; /* Previous link */ | ||
4284 | } x1node; | ||
4285 | |||
4286 | /* There is only one instance of the array, which is the following */ | ||
4287 | static struct s_x1 *x1a; | ||
4288 | |||
4289 | /* Allocate a new associative array */ | ||
4290 | void Strsafe_init(){ | ||
4291 | if( x1a ) return; | ||
4292 | x1a = (struct s_x1*)malloc( sizeof(struct s_x1) ); | ||
4293 | if( x1a ){ | ||
4294 | x1a->size = 1024; | ||
4295 | x1a->count = 0; | ||
4296 | x1a->tbl = (x1node*)malloc( | ||
4297 | (sizeof(x1node) + sizeof(x1node*))*1024 ); | ||
4298 | if( x1a->tbl==0 ){ | ||
4299 | free(x1a); | ||
4300 | x1a = 0; | ||
4301 | }else{ | ||
4302 | int i; | ||
4303 | x1a->ht = (x1node**)&(x1a->tbl[1024]); | ||
4304 | for(i=0; i<1024; i++) x1a->ht[i] = 0; | ||
4305 | } | ||
4306 | } | ||
4307 | } | ||
4308 | /* Insert a new record into the array. Return TRUE if successful. | ||
4309 | ** Prior data with the same key is NOT overwritten */ | ||
4310 | int Strsafe_insert(const char *data) | ||
4311 | { | ||
4312 | x1node *np; | ||
4313 | int h; | ||
4314 | int ph; | ||
4315 | |||
4316 | if( x1a==0 ) return 0; | ||
4317 | ph = strhash(data); | ||
4318 | h = ph & (x1a->size-1); | ||
4319 | np = x1a->ht[h]; | ||
4320 | while( np ){ | ||
4321 | if( strcmp(np->data,data)==0 ){ | ||
4322 | /* An existing entry with the same key is found. */ | ||
4323 | /* Fail because overwrite is not allows. */ | ||
4324 | return 0; | ||
4325 | } | ||
4326 | np = np->next; | ||
4327 | } | ||
4328 | if( x1a->count>=x1a->size ){ | ||
4329 | /* Need to make the hash table bigger */ | ||
4330 | int i,size; | ||
4331 | struct s_x1 array; | ||
4332 | array.size = size = x1a->size*2; | ||
4333 | array.count = x1a->count; | ||
4334 | array.tbl = (x1node*)malloc( | ||
4335 | (sizeof(x1node) + sizeof(x1node*))*size ); | ||
4336 | if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ | ||
4337 | array.ht = (x1node**)&(array.tbl[size]); | ||
4338 | for(i=0; i<size; i++) array.ht[i] = 0; | ||
4339 | for(i=0; i<x1a->count; i++){ | ||
4340 | x1node *oldnp, *newnp; | ||
4341 | oldnp = &(x1a->tbl[i]); | ||
4342 | h = strhash(oldnp->data) & (size-1); | ||
4343 | newnp = &(array.tbl[i]); | ||
4344 | if( array.ht[h] ) array.ht[h]->from = &(newnp->next); | ||
4345 | newnp->next = array.ht[h]; | ||
4346 | newnp->data = oldnp->data; | ||
4347 | newnp->from = &(array.ht[h]); | ||
4348 | array.ht[h] = newnp; | ||
4349 | } | ||
4350 | free(x1a->tbl); | ||
4351 | *x1a = array; | ||
4352 | } | ||
4353 | /* Insert the new data */ | ||
4354 | h = ph & (x1a->size-1); | ||
4355 | np = &(x1a->tbl[x1a->count++]); | ||
4356 | np->data = data; | ||
4357 | if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next); | ||
4358 | np->next = x1a->ht[h]; | ||
4359 | x1a->ht[h] = np; | ||
4360 | np->from = &(x1a->ht[h]); | ||
4361 | return 1; | ||
4362 | } | ||
4363 | |||
4364 | /* Return a pointer to data assigned to the given key. Return NULL | ||
4365 | ** if no such key. */ | ||
4366 | const char *Strsafe_find(const char *key) | ||
4367 | { | ||
4368 | int h; | ||
4369 | x1node *np; | ||
4370 | |||
4371 | if( x1a==0 ) return 0; | ||
4372 | h = strhash(key) & (x1a->size-1); | ||
4373 | np = x1a->ht[h]; | ||
4374 | while( np ){ | ||
4375 | if( strcmp(np->data,key)==0 ) break; | ||
4376 | np = np->next; | ||
4377 | } | ||
4378 | return np ? np->data : 0; | ||
4379 | } | ||
4380 | |||
4381 | /* Return a pointer to the (terminal or nonterminal) symbol "x". | ||
4382 | ** Create a new symbol if this is the first time "x" has been seen. | ||
4383 | */ | ||
4384 | struct symbol *Symbol_new(const char *x) | ||
4385 | { | ||
4386 | struct symbol *sp; | ||
4387 | |||
4388 | sp = Symbol_find(x); | ||
4389 | if( sp==0 ){ | ||
4390 | sp = (struct symbol *)calloc(1, sizeof(struct symbol) ); | ||
4391 | MemoryCheck(sp); | ||
4392 | sp->name = Strsafe(x); | ||
4393 | sp->type = isupper(*x) ? TERMINAL : NONTERMINAL; | ||
4394 | sp->rule = 0; | ||
4395 | sp->fallback = 0; | ||
4396 | sp->prec = -1; | ||
4397 | sp->assoc = UNK; | ||
4398 | sp->firstset = 0; | ||
4399 | sp->lambda = LEMON_FALSE; | ||
4400 | sp->destructor = 0; | ||
4401 | sp->destLineno = 0; | ||
4402 | sp->datatype = 0; | ||
4403 | sp->useCnt = 0; | ||
4404 | Symbol_insert(sp,sp->name); | ||
4405 | } | ||
4406 | sp->useCnt++; | ||
4407 | return sp; | ||
4408 | } | ||
4409 | |||
4410 | /* Compare two symbols for working purposes | ||
4411 | ** | ||
4412 | ** Symbols that begin with upper case letters (terminals or tokens) | ||
4413 | ** must sort before symbols that begin with lower case letters | ||
4414 | ** (non-terminals). Other than that, the order does not matter. | ||
4415 | ** | ||
4416 | ** We find experimentally that leaving the symbols in their original | ||
4417 | ** order (the order they appeared in the grammar file) gives the | ||
4418 | ** smallest parser tables in SQLite. | ||
4419 | */ | ||
4420 | int Symbolcmpp(const void *_a, const void *_b) | ||
4421 | { | ||
4422 | const struct symbol **a = (const struct symbol **) _a; | ||
4423 | const struct symbol **b = (const struct symbol **) _b; | ||
4424 | int i1 = (**a).index + 10000000*((**a).name[0]>'Z'); | ||
4425 | int i2 = (**b).index + 10000000*((**b).name[0]>'Z'); | ||
4426 | assert( i1!=i2 || strcmp((**a).name,(**b).name)==0 ); | ||
4427 | return i1-i2; | ||
4428 | } | ||
4429 | |||
4430 | /* There is one instance of the following structure for each | ||
4431 | ** associative array of type "x2". | ||
4432 | */ | ||
4433 | struct s_x2 { | ||
4434 | int size; /* The number of available slots. */ | ||
4435 | /* Must be a power of 2 greater than or */ | ||
4436 | /* equal to 1 */ | ||
4437 | int count; /* Number of currently slots filled */ | ||
4438 | struct s_x2node *tbl; /* The data stored here */ | ||
4439 | struct s_x2node **ht; /* Hash table for lookups */ | ||
4440 | }; | ||
4441 | |||
4442 | /* There is one instance of this structure for every data element | ||
4443 | ** in an associative array of type "x2". | ||
4444 | */ | ||
4445 | typedef struct s_x2node { | ||
4446 | struct symbol *data; /* The data */ | ||
4447 | const char *key; /* The key */ | ||
4448 | struct s_x2node *next; /* Next entry with the same hash */ | ||
4449 | struct s_x2node **from; /* Previous link */ | ||
4450 | } x2node; | ||
4451 | |||
4452 | /* There is only one instance of the array, which is the following */ | ||
4453 | static struct s_x2 *x2a; | ||
4454 | |||
4455 | /* Allocate a new associative array */ | ||
4456 | void Symbol_init(){ | ||
4457 | if( x2a ) return; | ||
4458 | x2a = (struct s_x2*)malloc( sizeof(struct s_x2) ); | ||
4459 | if( x2a ){ | ||
4460 | x2a->size = 128; | ||
4461 | x2a->count = 0; | ||
4462 | x2a->tbl = (x2node*)malloc( | ||
4463 | (sizeof(x2node) + sizeof(x2node*))*128 ); | ||
4464 | if( x2a->tbl==0 ){ | ||
4465 | free(x2a); | ||
4466 | x2a = 0; | ||
4467 | }else{ | ||
4468 | int i; | ||
4469 | x2a->ht = (x2node**)&(x2a->tbl[128]); | ||
4470 | for(i=0; i<128; i++) x2a->ht[i] = 0; | ||
4471 | } | ||
4472 | } | ||
4473 | } | ||
4474 | /* Insert a new record into the array. Return TRUE if successful. | ||
4475 | ** Prior data with the same key is NOT overwritten */ | ||
4476 | int Symbol_insert(struct symbol *data, const char *key) | ||
4477 | { | ||
4478 | x2node *np; | ||
4479 | int h; | ||
4480 | int ph; | ||
4481 | |||
4482 | if( x2a==0 ) return 0; | ||
4483 | ph = strhash(key); | ||
4484 | h = ph & (x2a->size-1); | ||
4485 | np = x2a->ht[h]; | ||
4486 | while( np ){ | ||
4487 | if( strcmp(np->key,key)==0 ){ | ||
4488 | /* An existing entry with the same key is found. */ | ||
4489 | /* Fail because overwrite is not allows. */ | ||
4490 | return 0; | ||
4491 | } | ||
4492 | np = np->next; | ||
4493 | } | ||
4494 | if( x2a->count>=x2a->size ){ | ||
4495 | /* Need to make the hash table bigger */ | ||
4496 | int i,size; | ||
4497 | struct s_x2 array; | ||
4498 | array.size = size = x2a->size*2; | ||
4499 | array.count = x2a->count; | ||
4500 | array.tbl = (x2node*)malloc( | ||
4501 | (sizeof(x2node) + sizeof(x2node*))*size ); | ||
4502 | if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ | ||
4503 | array.ht = (x2node**)&(array.tbl[size]); | ||
4504 | for(i=0; i<size; i++) array.ht[i] = 0; | ||
4505 | for(i=0; i<x2a->count; i++){ | ||
4506 | x2node *oldnp, *newnp; | ||
4507 | oldnp = &(x2a->tbl[i]); | ||
4508 | h = strhash(oldnp->key) & (size-1); | ||
4509 | newnp = &(array.tbl[i]); | ||
4510 | if( array.ht[h] ) array.ht[h]->from = &(newnp->next); | ||
4511 | newnp->next = array.ht[h]; | ||
4512 | newnp->key = oldnp->key; | ||
4513 | newnp->data = oldnp->data; | ||
4514 | newnp->from = &(array.ht[h]); | ||
4515 | array.ht[h] = newnp; | ||
4516 | } | ||
4517 | free(x2a->tbl); | ||
4518 | *x2a = array; | ||
4519 | } | ||
4520 | /* Insert the new data */ | ||
4521 | h = ph & (x2a->size-1); | ||
4522 | np = &(x2a->tbl[x2a->count++]); | ||
4523 | np->key = key; | ||
4524 | np->data = data; | ||
4525 | if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next); | ||
4526 | np->next = x2a->ht[h]; | ||
4527 | x2a->ht[h] = np; | ||
4528 | np->from = &(x2a->ht[h]); | ||
4529 | return 1; | ||
4530 | } | ||
4531 | |||
4532 | /* Return a pointer to data assigned to the given key. Return NULL | ||
4533 | ** if no such key. */ | ||
4534 | struct symbol *Symbol_find(const char *key) | ||
4535 | { | ||
4536 | int h; | ||
4537 | x2node *np; | ||
4538 | |||
4539 | if( x2a==0 ) return 0; | ||
4540 | h = strhash(key) & (x2a->size-1); | ||
4541 | np = x2a->ht[h]; | ||
4542 | while( np ){ | ||
4543 | if( strcmp(np->key,key)==0 ) break; | ||
4544 | np = np->next; | ||
4545 | } | ||
4546 | return np ? np->data : 0; | ||
4547 | } | ||
4548 | |||
4549 | /* Return the n-th data. Return NULL if n is out of range. */ | ||
4550 | struct symbol *Symbol_Nth(int n) | ||
4551 | { | ||
4552 | struct symbol *data; | ||
4553 | if( x2a && n>0 && n<=x2a->count ){ | ||
4554 | data = x2a->tbl[n-1].data; | ||
4555 | }else{ | ||
4556 | data = 0; | ||
4557 | } | ||
4558 | return data; | ||
4559 | } | ||
4560 | |||
4561 | /* Return the size of the array */ | ||
4562 | int Symbol_count() | ||
4563 | { | ||
4564 | return x2a ? x2a->count : 0; | ||
4565 | } | ||
4566 | |||
4567 | /* Return an array of pointers to all data in the table. | ||
4568 | ** The array is obtained from malloc. Return NULL if memory allocation | ||
4569 | ** problems, or if the array is empty. */ | ||
4570 | struct symbol **Symbol_arrayof() | ||
4571 | { | ||
4572 | struct symbol **array; | ||
4573 | int i,size; | ||
4574 | if( x2a==0 ) return 0; | ||
4575 | size = x2a->count; | ||
4576 | array = (struct symbol **)calloc(size, sizeof(struct symbol *)); | ||
4577 | if( array ){ | ||
4578 | for(i=0; i<size; i++) array[i] = x2a->tbl[i].data; | ||
4579 | } | ||
4580 | return array; | ||
4581 | } | ||
4582 | |||
4583 | /* Compare two configurations */ | ||
4584 | int Configcmp(const char *_a,const char *_b) | ||
4585 | { | ||
4586 | const struct config *a = (struct config *) _a; | ||
4587 | const struct config *b = (struct config *) _b; | ||
4588 | int x; | ||
4589 | x = a->rp->index - b->rp->index; | ||
4590 | if( x==0 ) x = a->dot - b->dot; | ||
4591 | return x; | ||
4592 | } | ||
4593 | |||
4594 | /* Compare two states */ | ||
4595 | PRIVATE int statecmp(struct config *a, struct config *b) | ||
4596 | { | ||
4597 | int rc; | ||
4598 | for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){ | ||
4599 | rc = a->rp->index - b->rp->index; | ||
4600 | if( rc==0 ) rc = a->dot - b->dot; | ||
4601 | } | ||
4602 | if( rc==0 ){ | ||
4603 | if( a ) rc = 1; | ||
4604 | if( b ) rc = -1; | ||
4605 | } | ||
4606 | return rc; | ||
4607 | } | ||
4608 | |||
4609 | /* Hash a state */ | ||
4610 | PRIVATE int statehash(struct config *a) | ||
4611 | { | ||
4612 | int h=0; | ||
4613 | while( a ){ | ||
4614 | h = h*571 + a->rp->index*37 + a->dot; | ||
4615 | a = a->bp; | ||
4616 | } | ||
4617 | return h; | ||
4618 | } | ||
4619 | |||
4620 | /* Allocate a new state structure */ | ||
4621 | struct state *State_new() | ||
4622 | { | ||
4623 | struct state *newstate; | ||
4624 | newstate = (struct state *)calloc(1, sizeof(struct state) ); | ||
4625 | MemoryCheck(newstate); | ||
4626 | return newstate; | ||
4627 | } | ||
4628 | |||
4629 | /* There is one instance of the following structure for each | ||
4630 | ** associative array of type "x3". | ||
4631 | */ | ||
4632 | struct s_x3 { | ||
4633 | int size; /* The number of available slots. */ | ||
4634 | /* Must be a power of 2 greater than or */ | ||
4635 | /* equal to 1 */ | ||
4636 | int count; /* Number of currently slots filled */ | ||
4637 | struct s_x3node *tbl; /* The data stored here */ | ||
4638 | struct s_x3node **ht; /* Hash table for lookups */ | ||
4639 | }; | ||
4640 | |||
4641 | /* There is one instance of this structure for every data element | ||
4642 | ** in an associative array of type "x3". | ||
4643 | */ | ||
4644 | typedef struct s_x3node { | ||
4645 | struct state *data; /* The data */ | ||
4646 | struct config *key; /* The key */ | ||
4647 | struct s_x3node *next; /* Next entry with the same hash */ | ||
4648 | struct s_x3node **from; /* Previous link */ | ||
4649 | } x3node; | ||
4650 | |||
4651 | /* There is only one instance of the array, which is the following */ | ||
4652 | static struct s_x3 *x3a; | ||
4653 | |||
4654 | /* Allocate a new associative array */ | ||
4655 | void State_init(){ | ||
4656 | if( x3a ) return; | ||
4657 | x3a = (struct s_x3*)malloc( sizeof(struct s_x3) ); | ||
4658 | if( x3a ){ | ||
4659 | x3a->size = 128; | ||
4660 | x3a->count = 0; | ||
4661 | x3a->tbl = (x3node*)malloc( | ||
4662 | (sizeof(x3node) + sizeof(x3node*))*128 ); | ||
4663 | if( x3a->tbl==0 ){ | ||
4664 | free(x3a); | ||
4665 | x3a = 0; | ||
4666 | }else{ | ||
4667 | int i; | ||
4668 | x3a->ht = (x3node**)&(x3a->tbl[128]); | ||
4669 | for(i=0; i<128; i++) x3a->ht[i] = 0; | ||
4670 | } | ||
4671 | } | ||
4672 | } | ||
4673 | /* Insert a new record into the array. Return TRUE if successful. | ||
4674 | ** Prior data with the same key is NOT overwritten */ | ||
4675 | int State_insert(struct state *data, struct config *key) | ||
4676 | { | ||
4677 | x3node *np; | ||
4678 | int h; | ||
4679 | int ph; | ||
4680 | |||
4681 | if( x3a==0 ) return 0; | ||
4682 | ph = statehash(key); | ||
4683 | h = ph & (x3a->size-1); | ||
4684 | np = x3a->ht[h]; | ||
4685 | while( np ){ | ||
4686 | if( statecmp(np->key,key)==0 ){ | ||
4687 | /* An existing entry with the same key is found. */ | ||
4688 | /* Fail because overwrite is not allows. */ | ||
4689 | return 0; | ||
4690 | } | ||
4691 | np = np->next; | ||
4692 | } | ||
4693 | if( x3a->count>=x3a->size ){ | ||
4694 | /* Need to make the hash table bigger */ | ||
4695 | int i,size; | ||
4696 | struct s_x3 array; | ||
4697 | array.size = size = x3a->size*2; | ||
4698 | array.count = x3a->count; | ||
4699 | array.tbl = (x3node*)malloc( | ||
4700 | (sizeof(x3node) + sizeof(x3node*))*size ); | ||
4701 | if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ | ||
4702 | array.ht = (x3node**)&(array.tbl[size]); | ||
4703 | for(i=0; i<size; i++) array.ht[i] = 0; | ||
4704 | for(i=0; i<x3a->count; i++){ | ||
4705 | x3node *oldnp, *newnp; | ||
4706 | oldnp = &(x3a->tbl[i]); | ||
4707 | h = statehash(oldnp->key) & (size-1); | ||
4708 | newnp = &(array.tbl[i]); | ||
4709 | if( array.ht[h] ) array.ht[h]->from = &(newnp->next); | ||
4710 | newnp->next = array.ht[h]; | ||
4711 | newnp->key = oldnp->key; | ||
4712 | newnp->data = oldnp->data; | ||
4713 | newnp->from = &(array.ht[h]); | ||
4714 | array.ht[h] = newnp; | ||
4715 | } | ||
4716 | free(x3a->tbl); | ||
4717 | *x3a = array; | ||
4718 | } | ||
4719 | /* Insert the new data */ | ||
4720 | h = ph & (x3a->size-1); | ||
4721 | np = &(x3a->tbl[x3a->count++]); | ||
4722 | np->key = key; | ||
4723 | np->data = data; | ||
4724 | if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next); | ||
4725 | np->next = x3a->ht[h]; | ||
4726 | x3a->ht[h] = np; | ||
4727 | np->from = &(x3a->ht[h]); | ||
4728 | return 1; | ||
4729 | } | ||
4730 | |||
4731 | /* Return a pointer to data assigned to the given key. Return NULL | ||
4732 | ** if no such key. */ | ||
4733 | struct state *State_find(struct config *key) | ||
4734 | { | ||
4735 | int h; | ||
4736 | x3node *np; | ||
4737 | |||
4738 | if( x3a==0 ) return 0; | ||
4739 | h = statehash(key) & (x3a->size-1); | ||
4740 | np = x3a->ht[h]; | ||
4741 | while( np ){ | ||
4742 | if( statecmp(np->key,key)==0 ) break; | ||
4743 | np = np->next; | ||
4744 | } | ||
4745 | return np ? np->data : 0; | ||
4746 | } | ||
4747 | |||
4748 | /* Return an array of pointers to all data in the table. | ||
4749 | ** The array is obtained from malloc. Return NULL if memory allocation | ||
4750 | ** problems, or if the array is empty. */ | ||
4751 | struct state **State_arrayof() | ||
4752 | { | ||
4753 | struct state **array; | ||
4754 | int i,size; | ||
4755 | if( x3a==0 ) return 0; | ||
4756 | size = x3a->count; | ||
4757 | array = (struct state **)malloc( sizeof(struct state *)*size ); | ||
4758 | if( array ){ | ||
4759 | for(i=0; i<size; i++) array[i] = x3a->tbl[i].data; | ||
4760 | } | ||
4761 | return array; | ||
4762 | } | ||
4763 | |||
4764 | /* Hash a configuration */ | ||
4765 | PRIVATE int confighash(struct config *a) | ||
4766 | { | ||
4767 | int h=0; | ||
4768 | h = h*571 + a->rp->index*37 + a->dot; | ||
4769 | return h; | ||
4770 | } | ||
4771 | |||
4772 | /* There is one instance of the following structure for each | ||
4773 | ** associative array of type "x4". | ||
4774 | */ | ||
4775 | struct s_x4 { | ||
4776 | int size; /* The number of available slots. */ | ||
4777 | /* Must be a power of 2 greater than or */ | ||
4778 | /* equal to 1 */ | ||
4779 | int count; /* Number of currently slots filled */ | ||
4780 | struct s_x4node *tbl; /* The data stored here */ | ||
4781 | struct s_x4node **ht; /* Hash table for lookups */ | ||
4782 | }; | ||
4783 | |||
4784 | /* There is one instance of this structure for every data element | ||
4785 | ** in an associative array of type "x4". | ||
4786 | */ | ||
4787 | typedef struct s_x4node { | ||
4788 | struct config *data; /* The data */ | ||
4789 | struct s_x4node *next; /* Next entry with the same hash */ | ||
4790 | struct s_x4node **from; /* Previous link */ | ||
4791 | } x4node; | ||
4792 | |||
4793 | /* There is only one instance of the array, which is the following */ | ||
4794 | static struct s_x4 *x4a; | ||
4795 | |||
4796 | /* Allocate a new associative array */ | ||
4797 | void Configtable_init(){ | ||
4798 | if( x4a ) return; | ||
4799 | x4a = (struct s_x4*)malloc( sizeof(struct s_x4) ); | ||
4800 | if( x4a ){ | ||
4801 | x4a->size = 64; | ||
4802 | x4a->count = 0; | ||
4803 | x4a->tbl = (x4node*)malloc( | ||
4804 | (sizeof(x4node) + sizeof(x4node*))*64 ); | ||
4805 | if( x4a->tbl==0 ){ | ||
4806 | free(x4a); | ||
4807 | x4a = 0; | ||
4808 | }else{ | ||
4809 | int i; | ||
4810 | x4a->ht = (x4node**)&(x4a->tbl[64]); | ||
4811 | for(i=0; i<64; i++) x4a->ht[i] = 0; | ||
4812 | } | ||
4813 | } | ||
4814 | } | ||
4815 | /* Insert a new record into the array. Return TRUE if successful. | ||
4816 | ** Prior data with the same key is NOT overwritten */ | ||
4817 | int Configtable_insert(struct config *data) | ||
4818 | { | ||
4819 | x4node *np; | ||
4820 | int h; | ||
4821 | int ph; | ||
4822 | |||
4823 | if( x4a==0 ) return 0; | ||
4824 | ph = confighash(data); | ||
4825 | h = ph & (x4a->size-1); | ||
4826 | np = x4a->ht[h]; | ||
4827 | while( np ){ | ||
4828 | if( Configcmp((const char *) np->data,(const char *) data)==0 ){ | ||
4829 | /* An existing entry with the same key is found. */ | ||
4830 | /* Fail because overwrite is not allows. */ | ||
4831 | return 0; | ||
4832 | } | ||
4833 | np = np->next; | ||
4834 | } | ||
4835 | if( x4a->count>=x4a->size ){ | ||
4836 | /* Need to make the hash table bigger */ | ||
4837 | int i,size; | ||
4838 | struct s_x4 array; | ||
4839 | array.size = size = x4a->size*2; | ||
4840 | array.count = x4a->count; | ||
4841 | array.tbl = (x4node*)malloc( | ||
4842 | (sizeof(x4node) + sizeof(x4node*))*size ); | ||
4843 | if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ | ||
4844 | array.ht = (x4node**)&(array.tbl[size]); | ||
4845 | for(i=0; i<size; i++) array.ht[i] = 0; | ||
4846 | for(i=0; i<x4a->count; i++){ | ||
4847 | x4node *oldnp, *newnp; | ||
4848 | oldnp = &(x4a->tbl[i]); | ||
4849 | h = confighash(oldnp->data) & (size-1); | ||
4850 | newnp = &(array.tbl[i]); | ||
4851 | if( array.ht[h] ) array.ht[h]->from = &(newnp->next); | ||
4852 | newnp->next = array.ht[h]; | ||
4853 | newnp->data = oldnp->data; | ||
4854 | newnp->from = &(array.ht[h]); | ||
4855 | array.ht[h] = newnp; | ||
4856 | } | ||
4857 | free(x4a->tbl); | ||
4858 | *x4a = array; | ||
4859 | } | ||
4860 | /* Insert the new data */ | ||
4861 | h = ph & (x4a->size-1); | ||
4862 | np = &(x4a->tbl[x4a->count++]); | ||
4863 | np->data = data; | ||
4864 | if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next); | ||
4865 | np->next = x4a->ht[h]; | ||
4866 | x4a->ht[h] = np; | ||
4867 | np->from = &(x4a->ht[h]); | ||
4868 | return 1; | ||
4869 | } | ||
4870 | |||
4871 | /* Return a pointer to data assigned to the given key. Return NULL | ||
4872 | ** if no such key. */ | ||
4873 | struct config *Configtable_find(struct config *key) | ||
4874 | { | ||
4875 | int h; | ||
4876 | x4node *np; | ||
4877 | |||
4878 | if( x4a==0 ) return 0; | ||
4879 | h = confighash(key) & (x4a->size-1); | ||
4880 | np = x4a->ht[h]; | ||
4881 | while( np ){ | ||
4882 | if( Configcmp((const char *) np->data,(const char *) key)==0 ) break; | ||
4883 | np = np->next; | ||
4884 | } | ||
4885 | return np ? np->data : 0; | ||
4886 | } | ||
4887 | |||
4888 | /* Remove all data from the table. Pass each data to the function "f" | ||
4889 | ** as it is removed. ("f" may be null to avoid this step.) */ | ||
4890 | void Configtable_clear(int(*f)(struct config *)) | ||
4891 | { | ||
4892 | int i; | ||
4893 | if( x4a==0 || x4a->count==0 ) return; | ||
4894 | if( f ) for(i=0; i<x4a->count; i++) (*f)(x4a->tbl[i].data); | ||
4895 | for(i=0; i<x4a->size; i++) x4a->ht[i] = 0; | ||
4896 | x4a->count = 0; | ||
4897 | return; | ||
4898 | } | ||
diff --git a/LuaSL/src/lempar.c b/LuaSL/src/lempar.c new file mode 100644 index 0000000..fe56d2d --- /dev/null +++ b/LuaSL/src/lempar.c | |||
@@ -0,0 +1,850 @@ | |||
1 | /* Driver template for the LEMON parser generator. | ||
2 | ** The author disclaims copyright to this source code. | ||
3 | */ | ||
4 | /* First off, code is included that follows the "include" declaration | ||
5 | ** in the input grammar file. */ | ||
6 | #include <stdio.h> | ||
7 | %% | ||
8 | /* Next is all token values, in a form suitable for use by makeheaders. | ||
9 | ** This section will be null unless lemon is run with the -m switch. | ||
10 | */ | ||
11 | /* | ||
12 | ** These constants (all generated automatically by the parser generator) | ||
13 | ** specify the various kinds of tokens (terminals) that the parser | ||
14 | ** understands. | ||
15 | ** | ||
16 | ** Each symbol here is a terminal symbol in the grammar. | ||
17 | */ | ||
18 | %% | ||
19 | /* Make sure the INTERFACE macro is defined. | ||
20 | */ | ||
21 | #ifndef INTERFACE | ||
22 | # define INTERFACE 1 | ||
23 | #endif | ||
24 | /* The next thing included is series of defines which control | ||
25 | ** various aspects of the generated parser. | ||
26 | ** YYCODETYPE is the data type used for storing terminal | ||
27 | ** and nonterminal numbers. "unsigned char" is | ||
28 | ** used if there are fewer than 250 terminals | ||
29 | ** and nonterminals. "int" is used otherwise. | ||
30 | ** YYNOCODE is a number of type YYCODETYPE which corresponds | ||
31 | ** to no legal terminal or nonterminal number. This | ||
32 | ** number is used to fill in empty slots of the hash | ||
33 | ** table. | ||
34 | ** YYFALLBACK If defined, this indicates that one or more tokens | ||
35 | ** have fall-back values which should be used if the | ||
36 | ** original value of the token will not parse. | ||
37 | ** YYACTIONTYPE is the data type used for storing terminal | ||
38 | ** and nonterminal numbers. "unsigned char" is | ||
39 | ** used if there are fewer than 250 rules and | ||
40 | ** states combined. "int" is used otherwise. | ||
41 | ** ParseTOKENTYPE is the data type used for minor tokens given | ||
42 | ** directly to the parser from the tokenizer. | ||
43 | ** YYMINORTYPE is the data type used for all minor tokens. | ||
44 | ** This is typically a union of many types, one of | ||
45 | ** which is ParseTOKENTYPE. The entry in the union | ||
46 | ** for base tokens is called "yy0". | ||
47 | ** YYSTACKDEPTH is the maximum depth of the parser's stack. If | ||
48 | ** zero the stack is dynamically sized using realloc() | ||
49 | ** ParseARG_SDECL A static variable declaration for the %extra_argument | ||
50 | ** ParseARG_PDECL A parameter declaration for the %extra_argument | ||
51 | ** ParseARG_STORE Code to store %extra_argument into yypParser | ||
52 | ** ParseARG_FETCH Code to extract %extra_argument from yypParser | ||
53 | ** YYNSTATE the combined number of states. | ||
54 | ** YYNRULE the number of rules in the grammar | ||
55 | ** YYERRORSYMBOL is the code number of the error symbol. If not | ||
56 | ** defined, then do no error processing. | ||
57 | */ | ||
58 | %% | ||
59 | #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) | ||
60 | #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) | ||
61 | #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) | ||
62 | |||
63 | /* The yyzerominor constant is used to initialize instances of | ||
64 | ** YYMINORTYPE objects to zero. */ | ||
65 | static const YYMINORTYPE yyzerominor = { 0 }; | ||
66 | |||
67 | /* Define the yytestcase() macro to be a no-op if is not already defined | ||
68 | ** otherwise. | ||
69 | ** | ||
70 | ** Applications can choose to define yytestcase() in the %include section | ||
71 | ** to a macro that can assist in verifying code coverage. For production | ||
72 | ** code the yytestcase() macro should be turned off. But it is useful | ||
73 | ** for testing. | ||
74 | */ | ||
75 | #ifndef yytestcase | ||
76 | # define yytestcase(X) | ||
77 | #endif | ||
78 | |||
79 | |||
80 | /* Next are the tables used to determine what action to take based on the | ||
81 | ** current state and lookahead token. These tables are used to implement | ||
82 | ** functions that take a state number and lookahead value and return an | ||
83 | ** action integer. | ||
84 | ** | ||
85 | ** Suppose the action integer is N. Then the action is determined as | ||
86 | ** follows | ||
87 | ** | ||
88 | ** 0 <= N < YYNSTATE Shift N. That is, push the lookahead | ||
89 | ** token onto the stack and goto state N. | ||
90 | ** | ||
91 | ** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. | ||
92 | ** | ||
93 | ** N == YYNSTATE+YYNRULE A syntax error has occurred. | ||
94 | ** | ||
95 | ** N == YYNSTATE+YYNRULE+1 The parser accepts its input. | ||
96 | ** | ||
97 | ** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused | ||
98 | ** slots in the yy_action[] table. | ||
99 | ** | ||
100 | ** The action table is constructed as a single large table named yy_action[]. | ||
101 | ** Given state S and lookahead X, the action is computed as | ||
102 | ** | ||
103 | ** yy_action[ yy_shift_ofst[S] + X ] | ||
104 | ** | ||
105 | ** If the index value yy_shift_ofst[S]+X is out of range or if the value | ||
106 | ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] | ||
107 | ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table | ||
108 | ** and that yy_default[S] should be used instead. | ||
109 | ** | ||
110 | ** The formula above is for computing the action when the lookahead is | ||
111 | ** a terminal symbol. If the lookahead is a non-terminal (as occurs after | ||
112 | ** a reduce action) then the yy_reduce_ofst[] array is used in place of | ||
113 | ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of | ||
114 | ** YY_SHIFT_USE_DFLT. | ||
115 | ** | ||
116 | ** The following are the tables generated in this section: | ||
117 | ** | ||
118 | ** yy_action[] A single table containing all actions. | ||
119 | ** yy_lookahead[] A table containing the lookahead for each entry in | ||
120 | ** yy_action. Used to detect hash collisions. | ||
121 | ** yy_shift_ofst[] For each state, the offset into yy_action for | ||
122 | ** shifting terminals. | ||
123 | ** yy_reduce_ofst[] For each state, the offset into yy_action for | ||
124 | ** shifting non-terminals after a reduce. | ||
125 | ** yy_default[] Default action for each state. | ||
126 | */ | ||
127 | %% | ||
128 | |||
129 | /* The next table maps tokens into fallback tokens. If a construct | ||
130 | ** like the following: | ||
131 | ** | ||
132 | ** %fallback ID X Y Z. | ||
133 | ** | ||
134 | ** appears in the grammar, then ID becomes a fallback token for X, Y, | ||
135 | ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser | ||
136 | ** but it does not parse, the type of the token is changed to ID and | ||
137 | ** the parse is retried before an error is thrown. | ||
138 | */ | ||
139 | #ifdef YYFALLBACK | ||
140 | static const YYCODETYPE yyFallback[] = { | ||
141 | %% | ||
142 | }; | ||
143 | #endif /* YYFALLBACK */ | ||
144 | |||
145 | /* The following structure represents a single element of the | ||
146 | ** parser's stack. Information stored includes: | ||
147 | ** | ||
148 | ** + The state number for the parser at this level of the stack. | ||
149 | ** | ||
150 | ** + The value of the token stored at this level of the stack. | ||
151 | ** (In other words, the "major" token.) | ||
152 | ** | ||
153 | ** + The semantic value stored at this level of the stack. This is | ||
154 | ** the information used by the action routines in the grammar. | ||
155 | ** It is sometimes called the "minor" token. | ||
156 | */ | ||
157 | struct yyStackEntry { | ||
158 | YYACTIONTYPE stateno; /* The state-number */ | ||
159 | YYCODETYPE major; /* The major token value. This is the code | ||
160 | ** number for the token at this stack level */ | ||
161 | YYMINORTYPE minor; /* The user-supplied minor token value. This | ||
162 | ** is the value of the token */ | ||
163 | }; | ||
164 | typedef struct yyStackEntry yyStackEntry; | ||
165 | |||
166 | /* The state of the parser is completely contained in an instance of | ||
167 | ** the following structure */ | ||
168 | struct yyParser { | ||
169 | int yyidx; /* Index of top element in stack */ | ||
170 | #ifdef YYTRACKMAXSTACKDEPTH | ||
171 | int yyidxMax; /* Maximum value of yyidx */ | ||
172 | #endif | ||
173 | int yyerrcnt; /* Shifts left before out of the error */ | ||
174 | ParseARG_SDECL /* A place to hold %extra_argument */ | ||
175 | #if YYSTACKDEPTH<=0 | ||
176 | int yystksz; /* Current side of the stack */ | ||
177 | yyStackEntry *yystack; /* The parser's stack */ | ||
178 | #else | ||
179 | yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ | ||
180 | #endif | ||
181 | }; | ||
182 | typedef struct yyParser yyParser; | ||
183 | |||
184 | #ifndef NDEBUG | ||
185 | #include <stdio.h> | ||
186 | static FILE *yyTraceFILE = 0; | ||
187 | static char *yyTracePrompt = 0; | ||
188 | #endif /* NDEBUG */ | ||
189 | |||
190 | #ifndef NDEBUG | ||
191 | /* | ||
192 | ** Turn parser tracing on by giving a stream to which to write the trace | ||
193 | ** and a prompt to preface each trace message. Tracing is turned off | ||
194 | ** by making either argument NULL | ||
195 | ** | ||
196 | ** Inputs: | ||
197 | ** <ul> | ||
198 | ** <li> A FILE* to which trace output should be written. | ||
199 | ** If NULL, then tracing is turned off. | ||
200 | ** <li> A prefix string written at the beginning of every | ||
201 | ** line of trace output. If NULL, then tracing is | ||
202 | ** turned off. | ||
203 | ** </ul> | ||
204 | ** | ||
205 | ** Outputs: | ||
206 | ** None. | ||
207 | */ | ||
208 | void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ | ||
209 | yyTraceFILE = TraceFILE; | ||
210 | yyTracePrompt = zTracePrompt; | ||
211 | if( yyTraceFILE==0 ) yyTracePrompt = 0; | ||
212 | else if( yyTracePrompt==0 ) yyTraceFILE = 0; | ||
213 | } | ||
214 | #endif /* NDEBUG */ | ||
215 | |||
216 | #ifndef NDEBUG | ||
217 | /* For tracing shifts, the names of all terminals and nonterminals | ||
218 | ** are required. The following table supplies these names */ | ||
219 | static const char *const yyTokenName[] = { | ||
220 | %% | ||
221 | }; | ||
222 | #endif /* NDEBUG */ | ||
223 | |||
224 | #ifndef NDEBUG | ||
225 | /* For tracing reduce actions, the names of all rules are required. | ||
226 | */ | ||
227 | static const char *const yyRuleName[] = { | ||
228 | %% | ||
229 | }; | ||
230 | #endif /* NDEBUG */ | ||
231 | |||
232 | |||
233 | #if YYSTACKDEPTH<=0 | ||
234 | /* | ||
235 | ** Try to increase the size of the parser stack. | ||
236 | */ | ||
237 | static void yyGrowStack(yyParser *p){ | ||
238 | int newSize; | ||
239 | yyStackEntry *pNew; | ||
240 | |||
241 | newSize = p->yystksz*2 + 100; | ||
242 | pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); | ||
243 | if( pNew ){ | ||
244 | p->yystack = pNew; | ||
245 | p->yystksz = newSize; | ||
246 | #ifndef NDEBUG | ||
247 | if( yyTraceFILE ){ | ||
248 | fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", | ||
249 | yyTracePrompt, p->yystksz); | ||
250 | } | ||
251 | #endif | ||
252 | } | ||
253 | } | ||
254 | #endif | ||
255 | |||
256 | /* | ||
257 | ** This function allocates a new parser. | ||
258 | ** The only argument is a pointer to a function which works like | ||
259 | ** malloc. | ||
260 | ** | ||
261 | ** Inputs: | ||
262 | ** A pointer to the function used to allocate memory. | ||
263 | ** | ||
264 | ** Outputs: | ||
265 | ** A pointer to a parser. This pointer is used in subsequent calls | ||
266 | ** to Parse and ParseFree. | ||
267 | */ | ||
268 | void *ParseAlloc(void *(*mallocProc)(size_t)){ | ||
269 | yyParser *pParser; | ||
270 | pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); | ||
271 | if( pParser ){ | ||
272 | pParser->yyidx = -1; | ||
273 | #ifdef YYTRACKMAXSTACKDEPTH | ||
274 | pParser->yyidxMax = 0; | ||
275 | #endif | ||
276 | #if YYSTACKDEPTH<=0 | ||
277 | pParser->yystack = NULL; | ||
278 | pParser->yystksz = 0; | ||
279 | yyGrowStack(pParser); | ||
280 | #endif | ||
281 | } | ||
282 | return pParser; | ||
283 | } | ||
284 | |||
285 | /* The following function deletes the value associated with a | ||
286 | ** symbol. The symbol can be either a terminal or nonterminal. | ||
287 | ** "yymajor" is the symbol code, and "yypminor" is a pointer to | ||
288 | ** the value. | ||
289 | */ | ||
290 | static void yy_destructor( | ||
291 | yyParser *yypParser, /* The parser */ | ||
292 | YYCODETYPE yymajor, /* Type code for object to destroy */ | ||
293 | YYMINORTYPE *yypminor /* The object to be destroyed */ | ||
294 | ){ | ||
295 | ParseARG_FETCH; | ||
296 | switch( yymajor ){ | ||
297 | /* Here is inserted the actions which take place when a | ||
298 | ** terminal or non-terminal is destroyed. This can happen | ||
299 | ** when the symbol is popped from the stack during a | ||
300 | ** reduce or during error processing or when a parser is | ||
301 | ** being destroyed before it is finished parsing. | ||
302 | ** | ||
303 | ** Note: during a reduce, the only symbols destroyed are those | ||
304 | ** which appear on the RHS of the rule, but which are not used | ||
305 | ** inside the C code. | ||
306 | */ | ||
307 | %% | ||
308 | default: break; /* If no destructor action specified: do nothing */ | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | ** Pop the parser's stack once. | ||
314 | ** | ||
315 | ** If there is a destructor routine associated with the token which | ||
316 | ** is popped from the stack, then call it. | ||
317 | ** | ||
318 | ** Return the major token number for the symbol popped. | ||
319 | */ | ||
320 | static int yy_pop_parser_stack(yyParser *pParser){ | ||
321 | YYCODETYPE yymajor; | ||
322 | yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; | ||
323 | |||
324 | if( pParser->yyidx<0 ) return 0; | ||
325 | #ifndef NDEBUG | ||
326 | if( yyTraceFILE && pParser->yyidx>=0 ){ | ||
327 | fprintf(yyTraceFILE,"%sPopping %s\n", | ||
328 | yyTracePrompt, | ||
329 | yyTokenName[yytos->major]); | ||
330 | } | ||
331 | #endif | ||
332 | yymajor = yytos->major; | ||
333 | yy_destructor(pParser, yymajor, &yytos->minor); | ||
334 | pParser->yyidx--; | ||
335 | return yymajor; | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | ** Deallocate and destroy a parser. Destructors are all called for | ||
340 | ** all stack elements before shutting the parser down. | ||
341 | ** | ||
342 | ** Inputs: | ||
343 | ** <ul> | ||
344 | ** <li> A pointer to the parser. This should be a pointer | ||
345 | ** obtained from ParseAlloc. | ||
346 | ** <li> A pointer to a function used to reclaim memory obtained | ||
347 | ** from malloc. | ||
348 | ** </ul> | ||
349 | */ | ||
350 | void ParseFree( | ||
351 | void *p, /* The parser to be deleted */ | ||
352 | void (*freeProc)(void*) /* Function used to reclaim memory */ | ||
353 | ){ | ||
354 | yyParser *pParser = (yyParser*)p; | ||
355 | if( pParser==0 ) return; | ||
356 | while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); | ||
357 | #if YYSTACKDEPTH<=0 | ||
358 | free(pParser->yystack); | ||
359 | #endif | ||
360 | (*freeProc)((void*)pParser); | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | ** Return the peak depth of the stack for a parser. | ||
365 | */ | ||
366 | #ifdef YYTRACKMAXSTACKDEPTH | ||
367 | int ParseStackPeak(void *p){ | ||
368 | yyParser *pParser = (yyParser*)p; | ||
369 | return pParser->yyidxMax; | ||
370 | } | ||
371 | #endif | ||
372 | |||
373 | /* | ||
374 | ** Find the appropriate action for a parser given the terminal | ||
375 | ** look-ahead token iLookAhead. | ||
376 | ** | ||
377 | ** If the look-ahead token is YYNOCODE, then check to see if the action is | ||
378 | ** independent of the look-ahead. If it is, return the action, otherwise | ||
379 | ** return YY_NO_ACTION. | ||
380 | */ | ||
381 | static int yy_find_shift_action( | ||
382 | yyParser *pParser, /* The parser */ | ||
383 | YYCODETYPE iLookAhead /* The look-ahead token */ | ||
384 | ){ | ||
385 | int i; | ||
386 | int stateno = pParser->yystack[pParser->yyidx].stateno; | ||
387 | |||
388 | if( stateno>YY_SHIFT_COUNT | ||
389 | || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ | ||
390 | return yy_default[stateno]; | ||
391 | } | ||
392 | assert( iLookAhead!=YYNOCODE ); | ||
393 | i += iLookAhead; | ||
394 | if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ | ||
395 | if( iLookAhead>0 ){ | ||
396 | #ifdef YYFALLBACK | ||
397 | YYCODETYPE iFallback; /* Fallback token */ | ||
398 | if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) | ||
399 | && (iFallback = yyFallback[iLookAhead])!=0 ){ | ||
400 | #ifndef NDEBUG | ||
401 | if( yyTraceFILE ){ | ||
402 | fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", | ||
403 | yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); | ||
404 | } | ||
405 | #endif | ||
406 | return yy_find_shift_action(pParser, iFallback); | ||
407 | } | ||
408 | #endif | ||
409 | #ifdef YYWILDCARD | ||
410 | { | ||
411 | int j = i - iLookAhead + YYWILDCARD; | ||
412 | if( | ||
413 | #if YY_SHIFT_MIN+YYWILDCARD<0 | ||
414 | j>=0 && | ||
415 | #endif | ||
416 | #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT | ||
417 | j<YY_ACTTAB_COUNT && | ||
418 | #endif | ||
419 | yy_lookahead[j]==YYWILDCARD | ||
420 | ){ | ||
421 | #ifndef NDEBUG | ||
422 | if( yyTraceFILE ){ | ||
423 | fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", | ||
424 | yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); | ||
425 | } | ||
426 | #endif /* NDEBUG */ | ||
427 | return yy_action[j]; | ||
428 | } | ||
429 | } | ||
430 | #endif /* YYWILDCARD */ | ||
431 | } | ||
432 | return yy_default[stateno]; | ||
433 | }else{ | ||
434 | return yy_action[i]; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | /* | ||
439 | ** Find the appropriate action for a parser given the non-terminal | ||
440 | ** look-ahead token iLookAhead. | ||
441 | ** | ||
442 | ** If the look-ahead token is YYNOCODE, then check to see if the action is | ||
443 | ** independent of the look-ahead. If it is, return the action, otherwise | ||
444 | ** return YY_NO_ACTION. | ||
445 | */ | ||
446 | static int yy_find_reduce_action( | ||
447 | int stateno, /* Current state number */ | ||
448 | YYCODETYPE iLookAhead /* The look-ahead token */ | ||
449 | ){ | ||
450 | int i; | ||
451 | #ifdef YYERRORSYMBOL | ||
452 | if( stateno>YY_REDUCE_COUNT ){ | ||
453 | return yy_default[stateno]; | ||
454 | } | ||
455 | #else | ||
456 | assert( stateno<=YY_REDUCE_COUNT ); | ||
457 | #endif | ||
458 | i = yy_reduce_ofst[stateno]; | ||
459 | assert( i!=YY_REDUCE_USE_DFLT ); | ||
460 | assert( iLookAhead!=YYNOCODE ); | ||
461 | i += iLookAhead; | ||
462 | #ifdef YYERRORSYMBOL | ||
463 | if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ | ||
464 | return yy_default[stateno]; | ||
465 | } | ||
466 | #else | ||
467 | assert( i>=0 && i<YY_ACTTAB_COUNT ); | ||
468 | assert( yy_lookahead[i]==iLookAhead ); | ||
469 | #endif | ||
470 | return yy_action[i]; | ||
471 | } | ||
472 | |||
473 | /* | ||
474 | ** The following routine is called if the stack overflows. | ||
475 | */ | ||
476 | static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ | ||
477 | ParseARG_FETCH; | ||
478 | yypParser->yyidx--; | ||
479 | #ifndef NDEBUG | ||
480 | if( yyTraceFILE ){ | ||
481 | fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); | ||
482 | } | ||
483 | #endif | ||
484 | while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); | ||
485 | /* Here code is inserted which will execute if the parser | ||
486 | ** stack every overflows */ | ||
487 | %% | ||
488 | ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ | ||
489 | } | ||
490 | |||
491 | /* | ||
492 | ** Perform a shift action. | ||
493 | */ | ||
494 | static void yy_shift( | ||
495 | yyParser *yypParser, /* The parser to be shifted */ | ||
496 | int yyNewState, /* The new state to shift in */ | ||
497 | int yyMajor, /* The major token to shift in */ | ||
498 | YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ | ||
499 | ){ | ||
500 | yyStackEntry *yytos; | ||
501 | yypParser->yyidx++; | ||
502 | #ifdef YYTRACKMAXSTACKDEPTH | ||
503 | if( yypParser->yyidx>yypParser->yyidxMax ){ | ||
504 | yypParser->yyidxMax = yypParser->yyidx; | ||
505 | } | ||
506 | #endif | ||
507 | #if YYSTACKDEPTH>0 | ||
508 | if( yypParser->yyidx>=YYSTACKDEPTH ){ | ||
509 | yyStackOverflow(yypParser, yypMinor); | ||
510 | return; | ||
511 | } | ||
512 | #else | ||
513 | if( yypParser->yyidx>=yypParser->yystksz ){ | ||
514 | yyGrowStack(yypParser); | ||
515 | if( yypParser->yyidx>=yypParser->yystksz ){ | ||
516 | yyStackOverflow(yypParser, yypMinor); | ||
517 | return; | ||
518 | } | ||
519 | } | ||
520 | #endif | ||
521 | yytos = &yypParser->yystack[yypParser->yyidx]; | ||
522 | yytos->stateno = (YYACTIONTYPE)yyNewState; | ||
523 | yytos->major = (YYCODETYPE)yyMajor; | ||
524 | yytos->minor = *yypMinor; | ||
525 | #ifndef NDEBUG | ||
526 | if( yyTraceFILE && yypParser->yyidx>0 ){ | ||
527 | int i; | ||
528 | fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); | ||
529 | fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); | ||
530 | for(i=1; i<=yypParser->yyidx; i++) | ||
531 | fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); | ||
532 | fprintf(yyTraceFILE,"\n"); | ||
533 | } | ||
534 | #endif | ||
535 | } | ||
536 | |||
537 | /* The following table contains information about every rule that | ||
538 | ** is used during the reduce. | ||
539 | */ | ||
540 | static const struct { | ||
541 | YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ | ||
542 | unsigned char nrhs; /* Number of right-hand side symbols in the rule */ | ||
543 | } yyRuleInfo[] = { | ||
544 | %% | ||
545 | }; | ||
546 | |||
547 | static void yy_accept(yyParser*); /* Forward Declaration */ | ||
548 | |||
549 | /* | ||
550 | ** Perform a reduce action and the shift that must immediately | ||
551 | ** follow the reduce. | ||
552 | */ | ||
553 | static void yy_reduce( | ||
554 | yyParser *yypParser, /* The parser */ | ||
555 | int yyruleno /* Number of the rule by which to reduce */ | ||
556 | ){ | ||
557 | int yygoto; /* The next state */ | ||
558 | int yyact; /* The next action */ | ||
559 | YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ | ||
560 | yyStackEntry *yymsp; /* The top of the parser's stack */ | ||
561 | int yysize; /* Amount to pop the stack */ | ||
562 | ParseARG_FETCH; | ||
563 | yymsp = &yypParser->yystack[yypParser->yyidx]; | ||
564 | #ifndef NDEBUG | ||
565 | if( yyTraceFILE && yyruleno>=0 | ||
566 | && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ | ||
567 | fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, | ||
568 | yyRuleName[yyruleno]); | ||
569 | } | ||
570 | #endif /* NDEBUG */ | ||
571 | |||
572 | /* Silence complaints from purify about yygotominor being uninitialized | ||
573 | ** in some cases when it is copied into the stack after the following | ||
574 | ** switch. yygotominor is uninitialized when a rule reduces that does | ||
575 | ** not set the value of its left-hand side nonterminal. Leaving the | ||
576 | ** value of the nonterminal uninitialized is utterly harmless as long | ||
577 | ** as the value is never used. So really the only thing this code | ||
578 | ** accomplishes is to quieten purify. | ||
579 | ** | ||
580 | ** 2007-01-16: The wireshark project (www.wireshark.org) reports that | ||
581 | ** without this code, their parser segfaults. I'm not sure what there | ||
582 | ** parser is doing to make this happen. This is the second bug report | ||
583 | ** from wireshark this week. Clearly they are stressing Lemon in ways | ||
584 | ** that it has not been previously stressed... (SQLite ticket #2172) | ||
585 | */ | ||
586 | /*memset(&yygotominor, 0, sizeof(yygotominor));*/ | ||
587 | yygotominor = yyzerominor; | ||
588 | |||
589 | |||
590 | switch( yyruleno ){ | ||
591 | /* Beginning here are the reduction cases. A typical example | ||
592 | ** follows: | ||
593 | ** case 0: | ||
594 | ** #line <lineno> <grammarfile> | ||
595 | ** { ... } // User supplied code | ||
596 | ** #line <lineno> <thisfile> | ||
597 | ** break; | ||
598 | */ | ||
599 | %% | ||
600 | }; | ||
601 | yygoto = yyRuleInfo[yyruleno].lhs; | ||
602 | yysize = yyRuleInfo[yyruleno].nrhs; | ||
603 | yypParser->yyidx -= yysize; | ||
604 | yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); | ||
605 | if( yyact < YYNSTATE ){ | ||
606 | #ifdef NDEBUG | ||
607 | /* If we are not debugging and the reduce action popped at least | ||
608 | ** one element off the stack, then we can push the new element back | ||
609 | ** onto the stack here, and skip the stack overflow test in yy_shift(). | ||
610 | ** That gives a significant speed improvement. */ | ||
611 | if( yysize ){ | ||
612 | yypParser->yyidx++; | ||
613 | yymsp -= yysize-1; | ||
614 | yymsp->stateno = (YYACTIONTYPE)yyact; | ||
615 | yymsp->major = (YYCODETYPE)yygoto; | ||
616 | yymsp->minor = yygotominor; | ||
617 | }else | ||
618 | #endif | ||
619 | { | ||
620 | yy_shift(yypParser,yyact,yygoto,&yygotominor); | ||
621 | } | ||
622 | }else{ | ||
623 | assert( yyact == YYNSTATE + YYNRULE + 1 ); | ||
624 | yy_accept(yypParser); | ||
625 | } | ||
626 | } | ||
627 | |||
628 | /* | ||
629 | ** The following code executes when the parse fails | ||
630 | */ | ||
631 | #ifndef YYNOERRORRECOVERY | ||
632 | static void yy_parse_failed( | ||
633 | yyParser *yypParser /* The parser */ | ||
634 | ){ | ||
635 | ParseARG_FETCH; | ||
636 | #ifndef NDEBUG | ||
637 | if( yyTraceFILE ){ | ||
638 | fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); | ||
639 | } | ||
640 | #endif | ||
641 | while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); | ||
642 | /* Here code is inserted which will be executed whenever the | ||
643 | ** parser fails */ | ||
644 | %% | ||
645 | ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ | ||
646 | } | ||
647 | #endif /* YYNOERRORRECOVERY */ | ||
648 | |||
649 | /* | ||
650 | ** The following code executes when a syntax error first occurs. | ||
651 | */ | ||
652 | static void yy_syntax_error( | ||
653 | yyParser *yypParser, /* The parser */ | ||
654 | int yymajor, /* The major type of the error token */ | ||
655 | YYMINORTYPE yyminor /* The minor type of the error token */ | ||
656 | ){ | ||
657 | ParseARG_FETCH; | ||
658 | #define TOKEN (yyminor.yy0) | ||
659 | %% | ||
660 | ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ | ||
661 | } | ||
662 | |||
663 | /* | ||
664 | ** The following is executed when the parser accepts | ||
665 | */ | ||
666 | static void yy_accept( | ||
667 | yyParser *yypParser /* The parser */ | ||
668 | ){ | ||
669 | ParseARG_FETCH; | ||
670 | #ifndef NDEBUG | ||
671 | if( yyTraceFILE ){ | ||
672 | fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); | ||
673 | } | ||
674 | #endif | ||
675 | while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); | ||
676 | /* Here code is inserted which will be executed whenever the | ||
677 | ** parser accepts */ | ||
678 | %% | ||
679 | ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ | ||
680 | } | ||
681 | |||
682 | /* The main parser program. | ||
683 | ** The first argument is a pointer to a structure obtained from | ||
684 | ** "ParseAlloc" which describes the current state of the parser. | ||
685 | ** The second argument is the major token number. The third is | ||
686 | ** the minor token. The fourth optional argument is whatever the | ||
687 | ** user wants (and specified in the grammar) and is available for | ||
688 | ** use by the action routines. | ||
689 | ** | ||
690 | ** Inputs: | ||
691 | ** <ul> | ||
692 | ** <li> A pointer to the parser (an opaque structure.) | ||
693 | ** <li> The major token number. | ||
694 | ** <li> The minor token number. | ||
695 | ** <li> An option argument of a grammar-specified type. | ||
696 | ** </ul> | ||
697 | ** | ||
698 | ** Outputs: | ||
699 | ** None. | ||
700 | */ | ||
701 | void Parse( | ||
702 | void *yyp, /* The parser */ | ||
703 | int yymajor, /* The major token code number */ | ||
704 | ParseTOKENTYPE yyminor /* The value for the token */ | ||
705 | ParseARG_PDECL /* Optional %extra_argument parameter */ | ||
706 | ){ | ||
707 | YYMINORTYPE yyminorunion; | ||
708 | int yyact; /* The parser action. */ | ||
709 | int yyendofinput; /* True if we are at the end of input */ | ||
710 | #ifdef YYERRORSYMBOL | ||
711 | int yyerrorhit = 0; /* True if yymajor has invoked an error */ | ||
712 | #endif | ||
713 | yyParser *yypParser; /* The parser */ | ||
714 | |||
715 | /* (re)initialize the parser, if necessary */ | ||
716 | yypParser = (yyParser*)yyp; | ||
717 | if( yypParser->yyidx<0 ){ | ||
718 | #if YYSTACKDEPTH<=0 | ||
719 | if( yypParser->yystksz <=0 ){ | ||
720 | /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ | ||
721 | yyminorunion = yyzerominor; | ||
722 | yyStackOverflow(yypParser, &yyminorunion); | ||
723 | return; | ||
724 | } | ||
725 | #endif | ||
726 | yypParser->yyidx = 0; | ||
727 | yypParser->yyerrcnt = -1; | ||
728 | yypParser->yystack[0].stateno = 0; | ||
729 | yypParser->yystack[0].major = 0; | ||
730 | } | ||
731 | yyminorunion.yy0 = yyminor; | ||
732 | yyendofinput = (yymajor==0); | ||
733 | ParseARG_STORE; | ||
734 | |||
735 | #ifndef NDEBUG | ||
736 | if( yyTraceFILE ){ | ||
737 | fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); | ||
738 | } | ||
739 | #endif | ||
740 | |||
741 | do{ | ||
742 | yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); | ||
743 | if( yyact<YYNSTATE ){ | ||
744 | assert( !yyendofinput ); /* Impossible to shift the $ token */ | ||
745 | yy_shift(yypParser,yyact,yymajor,&yyminorunion); | ||
746 | yypParser->yyerrcnt--; | ||
747 | yymajor = YYNOCODE; | ||
748 | }else if( yyact < YYNSTATE + YYNRULE ){ | ||
749 | yy_reduce(yypParser,yyact-YYNSTATE); | ||
750 | }else{ | ||
751 | assert( yyact == YY_ERROR_ACTION ); | ||
752 | #ifdef YYERRORSYMBOL | ||
753 | int yymx; | ||
754 | #endif | ||
755 | #ifndef NDEBUG | ||
756 | if( yyTraceFILE ){ | ||
757 | fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); | ||
758 | } | ||
759 | #endif | ||
760 | #ifdef YYERRORSYMBOL | ||
761 | /* A syntax error has occurred. | ||
762 | ** The response to an error depends upon whether or not the | ||
763 | ** grammar defines an error token "ERROR". | ||
764 | ** | ||
765 | ** This is what we do if the grammar does define ERROR: | ||
766 | ** | ||
767 | ** * Call the %syntax_error function. | ||
768 | ** | ||
769 | ** * Begin popping the stack until we enter a state where | ||
770 | ** it is legal to shift the error symbol, then shift | ||
771 | ** the error symbol. | ||
772 | ** | ||
773 | ** * Set the error count to three. | ||
774 | ** | ||
775 | ** * Begin accepting and shifting new tokens. No new error | ||
776 | ** processing will occur until three tokens have been | ||
777 | ** shifted successfully. | ||
778 | ** | ||
779 | */ | ||
780 | if( yypParser->yyerrcnt<0 ){ | ||
781 | yy_syntax_error(yypParser,yymajor,yyminorunion); | ||
782 | } | ||
783 | yymx = yypParser->yystack[yypParser->yyidx].major; | ||
784 | if( yymx==YYERRORSYMBOL || yyerrorhit ){ | ||
785 | #ifndef NDEBUG | ||
786 | if( yyTraceFILE ){ | ||
787 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", | ||
788 | yyTracePrompt,yyTokenName[yymajor]); | ||
789 | } | ||
790 | #endif | ||
791 | yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); | ||
792 | yymajor = YYNOCODE; | ||
793 | }else{ | ||
794 | while( | ||
795 | yypParser->yyidx >= 0 && | ||
796 | yymx != YYERRORSYMBOL && | ||
797 | (yyact = yy_find_reduce_action( | ||
798 | yypParser->yystack[yypParser->yyidx].stateno, | ||
799 | YYERRORSYMBOL)) >= YYNSTATE | ||
800 | ){ | ||
801 | yy_pop_parser_stack(yypParser); | ||
802 | } | ||
803 | if( yypParser->yyidx < 0 || yymajor==0 ){ | ||
804 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); | ||
805 | yy_parse_failed(yypParser); | ||
806 | yymajor = YYNOCODE; | ||
807 | }else if( yymx!=YYERRORSYMBOL ){ | ||
808 | YYMINORTYPE u2; | ||
809 | u2.YYERRSYMDT = 0; | ||
810 | yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); | ||
811 | } | ||
812 | } | ||
813 | yypParser->yyerrcnt = 3; | ||
814 | yyerrorhit = 1; | ||
815 | #elif defined(YYNOERRORRECOVERY) | ||
816 | /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to | ||
817 | ** do any kind of error recovery. Instead, simply invoke the syntax | ||
818 | ** error routine and continue going as if nothing had happened. | ||
819 | ** | ||
820 | ** Applications can set this macro (for example inside %include) if | ||
821 | ** they intend to abandon the parse upon the first syntax error seen. | ||
822 | */ | ||
823 | yy_syntax_error(yypParser,yymajor,yyminorunion); | ||
824 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); | ||
825 | yymajor = YYNOCODE; | ||
826 | |||
827 | #else /* YYERRORSYMBOL is not defined */ | ||
828 | /* This is what we do if the grammar does not define ERROR: | ||
829 | ** | ||
830 | ** * Report an error message, and throw away the input token. | ||
831 | ** | ||
832 | ** * If the input token is $, then fail the parse. | ||
833 | ** | ||
834 | ** As before, subsequent error messages are suppressed until | ||
835 | ** three input tokens have been successfully shifted. | ||
836 | */ | ||
837 | if( yypParser->yyerrcnt<=0 ){ | ||
838 | yy_syntax_error(yypParser,yymajor,yyminorunion); | ||
839 | } | ||
840 | yypParser->yyerrcnt = 3; | ||
841 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); | ||
842 | if( yyendofinput ){ | ||
843 | yy_parse_failed(yypParser); | ||
844 | } | ||
845 | yymajor = YYNOCODE; | ||
846 | #endif | ||
847 | } | ||
848 | }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); | ||
849 | return; | ||
850 | } | ||
diff --git a/LuaSL/test.lsl b/LuaSL/test.lsl index 40d98b3..022163a 100644 --- a/LuaSL/test.lsl +++ b/LuaSL/test.lsl | |||
@@ -1,3 +1,6 @@ | |||
1 | 4 + /* c0 */ 2 /* c1 */ * /* c2 */ 10 /* c3 */ + /* c4 */ | 1 | /* */ 4 /* c */ + /* c0 */ 2 /* c1 */ * /* c2 */ 10 /* c3 */ + /* c4 */ |
2 | 3 /* c5 */ * /* c6 */ (5 /* c7 */ + /* c8 */ 1); | 2 | 3 /* c5 */ * /* c6 */ ( /* c7 */ 5 /* c8 */ + /* c9 */ 1 /* cA */ ) /* cB */ ; /* cE */ |
3 | // Some more arithmetic - | ||
4 | 1+1; | ||
3 | 5 | ||
6 | // This is the end my friend. \ No newline at end of file | ||