blob: b634016e24e4813918dfaada3079964cde6df2e3 [file] [log] [blame]
The Android Open Source Project23580ca2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17%{
18#undef NDEBUG
19 #include <stdlib.h>
20 #include <string.h>
21 #include <assert.h>
22 #include <stdio.h>
23 #include "ast.h"
24 #include "lexer.h"
25 #include "commands.h"
26
27 void yyerror(const char *msg);
28 int yylex(void);
29
30#define STRING_COMPARISON(out, a1, sop, a2) \
31 do { \
32 out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \
33 if (out == NULL) { \
34 YYABORT; \
35 } \
36 out->type = AM_BVAL_STRING_COMPARISON; \
37 out->u.stringComparison.op = sop; \
38 out->u.stringComparison.arg1 = a1; \
39 out->u.stringComparison.arg2 = a2; \
40 } while (false)
41
42#define BOOLEAN_EXPRESSION(out, a1, bop, a2) \
43 do { \
44 out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \
45 if (out == NULL) { \
46 YYABORT; \
47 } \
48 out->type = AM_BVAL_EXPRESSION; \
49 out->u.expression.op = bop; \
50 out->u.expression.arg1 = a1; \
51 out->u.expression.arg2 = a2; \
52 } while (false)
53
54AmCommandList *gCommands = NULL;
55%}
56
57%start lines
58
59%union {
60 char *literalString;
61 AmFunctionArgumentBuilder *functionArgumentBuilder;
62 AmFunctionArguments *functionArguments;
63 AmFunctionCall *functionCall;
64 AmStringValue *stringValue;
65 AmBooleanValue *booleanValue;
66 AmWordListBuilder *wordListBuilder;
67 AmCommandArguments *commandArguments;
68 AmCommand *command;
69 AmCommandList *commandList;
70 }
71
72%token TOK_AND TOK_OR TOK_EQ TOK_NE TOK_GE TOK_LE TOK_EOF TOK_EOL TOK_ERROR
73%token <literalString> TOK_STRING TOK_IDENTIFIER TOK_WORD
74
75%type <commandList> lines
76%type <command> command line
77%type <functionArgumentBuilder> function_arguments
78%type <functionArguments> function_arguments_or_empty
79%type <functionCall> function_call
80%type <literalString> function_name
81%type <stringValue> string_value
82%type <booleanValue> boolean_expression
83%type <wordListBuilder> word_list
84%type <commandArguments> arguments
85
86/* Operator precedence, weakest to strongest.
87 * Same as C/Java precedence.
88 */
89
90%left TOK_OR
91%left TOK_AND
92%left TOK_EQ TOK_NE
93%left '<' '>' TOK_LE TOK_GE
94%right '!'
95
96%%
97
98lines : /* empty */
99 {
100 $$ = (AmCommandList *)malloc(sizeof(AmCommandList));
101 if ($$ == NULL) {
102 YYABORT;
103 }
104gCommands = $$;
105 $$->arraySize = 64;
106 $$->commandCount = 0;
107 $$->commands = (AmCommand **)malloc(
108 sizeof(AmCommand *) * $$->arraySize);
109 if ($$->commands == NULL) {
110 YYABORT;
111 }
112 }
113 | lines line
114 {
115 if ($2 != NULL) {
116 if ($1->commandCount >= $1->arraySize) {
117 AmCommand **newArray;
118 newArray = (AmCommand **)realloc($$->commands,
119 sizeof(AmCommand *) * $$->arraySize * 2);
120 if (newArray == NULL) {
121 YYABORT;
122 }
123 $$->commands = newArray;
124 $$->arraySize *= 2;
125 }
126 $1->commands[$1->commandCount++] = $2;
127 }
128 }
129 ;
130
131line : line_ending
132 {
133 $$ = NULL; /* ignore blank lines */
134 }
135 | command arguments line_ending
136 {
137 $$ = $1;
138 $$->args = $2;
139 setLexerArgumentType(AM_UNKNOWN_ARGS);
140 }
141 ;
142
143command : TOK_IDENTIFIER
144 {
145 Command *cmd = findCommand($1);
146 if (cmd == NULL) {
147 fprintf(stderr, "Unknown command \"%s\"\n", $1);
148 YYABORT;
149 }
150 $$ = (AmCommand *)malloc(sizeof(AmCommand));
151 if ($$ == NULL) {
152 YYABORT;
153 }
154 $$->line = getLexerLineNumber();
155 $$->name = strdup($1);
156 if ($$->name == NULL) {
157 YYABORT;
158 }
159 $$->args = NULL;
160 CommandArgumentType argType = getCommandArgumentType(cmd);
161 if (argType == CMD_ARGS_BOOLEAN) {
162 setLexerArgumentType(AM_BOOLEAN_ARGS);
163 } else {
164 setLexerArgumentType(AM_WORD_ARGS);
165 }
166 $$->cmd = cmd;
167 }
168 ;
169
170line_ending :
171 TOK_EOL
172 | TOK_EOF
173 ;
174
175arguments : boolean_expression
176 {
177 $$ = (AmCommandArguments *)malloc(
178 sizeof(AmCommandArguments));
179 if ($$ == NULL) {
180 YYABORT;
181 }
182 $$->booleanArgs = true;
183 $$->u.b = $1;
184 }
185 | word_list
186 {
187 /* Convert the builder list into an array.
188 * Do it in reverse order; the words were pushed
189 * onto the list in LIFO order.
190 */
191 AmWordList *w = (AmWordList *)malloc(sizeof(AmWordList));
192 if (w == NULL) {
193 YYABORT;
194 }
195 if ($1 != NULL) {
196 AmWordListBuilder *words = $1;
197
198 w->argc = words->wordCount;
199 w->argv = (const char **)malloc(w->argc *
200 sizeof(char *));
201 if (w->argv == NULL) {
202 YYABORT;
203 }
204 int i;
205 for (i = w->argc; words != NULL && i > 0; --i) {
206 AmWordListBuilder *f = words;
207 w->argv[i-1] = words->word;
208 words = words->next;
209 free(f);
210 }
211 assert(i == 0);
212 assert(words == NULL);
213 } else {
214 w->argc = 0;
215 w->argv = NULL;
216 }
217 $$ = (AmCommandArguments *)malloc(
218 sizeof(AmCommandArguments));
219 if ($$ == NULL) {
220 YYABORT;
221 }
222 $$->booleanArgs = false;
223 $$->u.w = w;
224 }
225 ;
226
227word_list : /* empty */
228 { $$ = NULL; }
229 | word_list TOK_WORD
230 {
231 if ($1 == NULL) {
232 $$ = (AmWordListBuilder *)malloc(
233 sizeof(AmWordListBuilder));
234 if ($$ == NULL) {
235 YYABORT;
236 }
237 $$->next = NULL;
238 $$->wordCount = 1;
239 } else {
240 $$ = (AmWordListBuilder *)malloc(
241 sizeof(AmWordListBuilder));
242 if ($$ == NULL) {
243 YYABORT;
244 }
245 $$->next = $1;
246 $$->wordCount = $$->next->wordCount + 1;
247 }
248 $$->word = strdup($2);
249 if ($$->word == NULL) {
250 YYABORT;
251 }
252 }
253 ;
254
255boolean_expression :
256 '!' boolean_expression
257 {
258 $$ = (AmBooleanValue *)malloc(sizeof(AmBooleanValue));
259 if ($$ == NULL) {
260 YYABORT;
261 }
262 $$->type = AM_BVAL_EXPRESSION;
263 $$->u.expression.op = AM_BOP_NOT;
264 $$->u.expression.arg1 = $2;
265 $$->u.expression.arg2 = NULL;
266 }
267 /* TODO: if both expressions are literals, evaluate now */
268 | boolean_expression TOK_AND boolean_expression
269 { BOOLEAN_EXPRESSION($$, $1, AM_BOP_AND, $3); }
270 | boolean_expression TOK_OR boolean_expression
271 { BOOLEAN_EXPRESSION($$, $1, AM_BOP_OR, $3); }
272 | boolean_expression TOK_EQ boolean_expression
273 { BOOLEAN_EXPRESSION($$, $1, AM_BOP_EQ, $3); }
274 | boolean_expression TOK_NE boolean_expression
275 { BOOLEAN_EXPRESSION($$, $1, AM_BOP_NE, $3); }
276 | '(' boolean_expression ')'
277 { $$ = $2; }
278 /* TODO: if both strings are literals, evaluate now */
279 | string_value '<' string_value
280 { STRING_COMPARISON($$, $1, AM_SOP_LT, $3); }
281 | string_value '>' string_value
282 { STRING_COMPARISON($$, $1, AM_SOP_GT, $3); }
283 | string_value TOK_EQ string_value
284 { STRING_COMPARISON($$, $1, AM_SOP_EQ, $3); }
285 | string_value TOK_NE string_value
286 { STRING_COMPARISON($$, $1, AM_SOP_NE, $3); }
287 | string_value TOK_LE string_value
288 { STRING_COMPARISON($$, $1, AM_SOP_LE, $3); }
289 | string_value TOK_GE string_value
290 { STRING_COMPARISON($$, $1, AM_SOP_GE, $3); }
291 ;
292
293string_value :
294 TOK_IDENTIFIER
295 {
296 $$ = (AmStringValue *)malloc(sizeof(AmStringValue));
297 if ($$ == NULL) {
298 YYABORT;
299 }
300 $$->type = AM_SVAL_LITERAL;
301 $$->u.literal = strdup($1);
302 if ($$->u.literal == NULL) {
303 YYABORT;
304 }
305 }
306 | TOK_STRING
307 {
308 $$ = (AmStringValue *)malloc(sizeof(AmStringValue));
309 if ($$ == NULL) {
310 YYABORT;
311 }
312 $$->type = AM_SVAL_LITERAL;
313 $$->u.literal = strdup($1);
314 if ($$->u.literal == NULL) {
315 YYABORT;
316 }
317 }
318 | function_call
319 {
320 $$ = (AmStringValue *)malloc(sizeof(AmStringValue));
321 if ($$ == NULL) {
322 YYABORT;
323 }
324 $$->type = AM_SVAL_FUNCTION;
325 $$->u.function = $1;
326 }
327 ;
328
329 /* We can't just say
330 * TOK_IDENTIFIER '(' function_arguments_or_empty ')'
331 * because parsing function_arguments_or_empty will clobber
332 * the underlying string that yylval.literalString points to.
333 */
334function_call :
335 function_name '(' function_arguments_or_empty ')'
336 {
337 Function *fn = findFunction($1);
338 if (fn == NULL) {
339 fprintf(stderr, "Unknown function \"%s\"\n", $1);
340 YYABORT;
341 }
342 $$ = (AmFunctionCall *)malloc(sizeof(AmFunctionCall));
343 if ($$ == NULL) {
344 YYABORT;
345 }
346 $$->name = $1;
347 if ($$->name == NULL) {
348 YYABORT;
349 }
350 $$->fn = fn;
351 $$->args = $3;
352 }
353 ;
354
355function_name :
356 TOK_IDENTIFIER
357 {
358 $$ = strdup($1);
359 }
360 ;
361
362function_arguments_or_empty :
363 /* empty */
364 {
365 $$ = (AmFunctionArguments *)malloc(
366 sizeof(AmFunctionArguments));
367 if ($$ == NULL) {
368 YYABORT;
369 }
370 $$->argc = 0;
371 $$->argv = NULL;
372 }
373 | function_arguments
374 {
375 AmFunctionArgumentBuilder *args = $1;
376 assert(args != NULL);
377
378 /* Convert the builder list into an array.
379 * Do it in reverse order; the args were pushed
380 * onto the list in LIFO order.
381 */
382 $$ = (AmFunctionArguments *)malloc(
383 sizeof(AmFunctionArguments));
384 if ($$ == NULL) {
385 YYABORT;
386 }
387 $$->argc = args->argCount;
388 $$->argv = (AmStringValue *)malloc(
389 $$->argc * sizeof(AmStringValue));
390 if ($$->argv == NULL) {
391 YYABORT;
392 }
393 int i;
394 for (i = $$->argc; args != NULL && i > 0; --i) {
395 AmFunctionArgumentBuilder *f = args;
396 $$->argv[i-1] = *args->arg;
397 args = args->next;
398 free(f->arg);
399 free(f);
400 }
401 assert(i == 0);
402 assert(args == NULL);
403 }
404 ;
405
406function_arguments :
407 string_value
408 {
409 $$ = (AmFunctionArgumentBuilder *)malloc(
410 sizeof(AmFunctionArgumentBuilder));
411 if ($$ == NULL) {
412 YYABORT;
413 }
414 $$->next = NULL;
415 $$->argCount = 1;
416 $$->arg = $1;
417 }
418 | function_arguments ',' string_value
419 {
420 $$ = (AmFunctionArgumentBuilder *)malloc(
421 sizeof(AmFunctionArgumentBuilder));
422 if ($$ == NULL) {
423 YYABORT;
424 }
425 $$->next = $1;
426 $$->argCount = $$->next->argCount + 1;
427 $$->arg = $3;
428 }
429 ;
430 /* xxx this whole tool needs to be hardened */