diff options
Diffstat (limited to 'amend/parser_y.y')
-rw-r--r-- | amend/parser_y.y | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/amend/parser_y.y b/amend/parser_y.y new file mode 100644 index 000000000..b634016e2 --- /dev/null +++ b/amend/parser_y.y @@ -0,0 +1,430 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +%{ +#undef NDEBUG + #include <stdlib.h> + #include <string.h> + #include <assert.h> + #include <stdio.h> + #include "ast.h" + #include "lexer.h" + #include "commands.h" + + void yyerror(const char *msg); + int yylex(void); + +#define STRING_COMPARISON(out, a1, sop, a2) \ + do { \ + out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \ + if (out == NULL) { \ + YYABORT; \ + } \ + out->type = AM_BVAL_STRING_COMPARISON; \ + out->u.stringComparison.op = sop; \ + out->u.stringComparison.arg1 = a1; \ + out->u.stringComparison.arg2 = a2; \ + } while (false) + +#define BOOLEAN_EXPRESSION(out, a1, bop, a2) \ + do { \ + out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \ + if (out == NULL) { \ + YYABORT; \ + } \ + out->type = AM_BVAL_EXPRESSION; \ + out->u.expression.op = bop; \ + out->u.expression.arg1 = a1; \ + out->u.expression.arg2 = a2; \ + } while (false) + +AmCommandList *gCommands = NULL; +%} + +%start lines + +%union { + char *literalString; + AmFunctionArgumentBuilder *functionArgumentBuilder; + AmFunctionArguments *functionArguments; + AmFunctionCall *functionCall; + AmStringValue *stringValue; + AmBooleanValue *booleanValue; + AmWordListBuilder *wordListBuilder; + AmCommandArguments *commandArguments; + AmCommand *command; + AmCommandList *commandList; + } + +%token TOK_AND TOK_OR TOK_EQ TOK_NE TOK_GE TOK_LE TOK_EOF TOK_EOL TOK_ERROR +%token <literalString> TOK_STRING TOK_IDENTIFIER TOK_WORD + +%type <commandList> lines +%type <command> command line +%type <functionArgumentBuilder> function_arguments +%type <functionArguments> function_arguments_or_empty +%type <functionCall> function_call +%type <literalString> function_name +%type <stringValue> string_value +%type <booleanValue> boolean_expression +%type <wordListBuilder> word_list +%type <commandArguments> arguments + +/* Operator precedence, weakest to strongest. + * Same as C/Java precedence. + */ + +%left TOK_OR +%left TOK_AND +%left TOK_EQ TOK_NE +%left '<' '>' TOK_LE TOK_GE +%right '!' + +%% + +lines : /* empty */ + { + $$ = (AmCommandList *)malloc(sizeof(AmCommandList)); + if ($$ == NULL) { + YYABORT; + } +gCommands = $$; + $$->arraySize = 64; + $$->commandCount = 0; + $$->commands = (AmCommand **)malloc( + sizeof(AmCommand *) * $$->arraySize); + if ($$->commands == NULL) { + YYABORT; + } + } + | lines line + { + if ($2 != NULL) { + if ($1->commandCount >= $1->arraySize) { + AmCommand **newArray; + newArray = (AmCommand **)realloc($$->commands, + sizeof(AmCommand *) * $$->arraySize * 2); + if (newArray == NULL) { + YYABORT; + } + $$->commands = newArray; + $$->arraySize *= 2; + } + $1->commands[$1->commandCount++] = $2; + } + } + ; + +line : line_ending + { + $$ = NULL; /* ignore blank lines */ + } + | command arguments line_ending + { + $$ = $1; + $$->args = $2; + setLexerArgumentType(AM_UNKNOWN_ARGS); + } + ; + +command : TOK_IDENTIFIER + { + Command *cmd = findCommand($1); + if (cmd == NULL) { + fprintf(stderr, "Unknown command \"%s\"\n", $1); + YYABORT; + } + $$ = (AmCommand *)malloc(sizeof(AmCommand)); + if ($$ == NULL) { + YYABORT; + } + $$->line = getLexerLineNumber(); + $$->name = strdup($1); + if ($$->name == NULL) { + YYABORT; + } + $$->args = NULL; + CommandArgumentType argType = getCommandArgumentType(cmd); + if (argType == CMD_ARGS_BOOLEAN) { + setLexerArgumentType(AM_BOOLEAN_ARGS); + } else { + setLexerArgumentType(AM_WORD_ARGS); + } + $$->cmd = cmd; + } + ; + +line_ending : + TOK_EOL + | TOK_EOF + ; + +arguments : boolean_expression + { + $$ = (AmCommandArguments *)malloc( + sizeof(AmCommandArguments)); + if ($$ == NULL) { + YYABORT; + } + $$->booleanArgs = true; + $$->u.b = $1; + } + | word_list + { + /* Convert the builder list into an array. + * Do it in reverse order; the words were pushed + * onto the list in LIFO order. + */ + AmWordList *w = (AmWordList *)malloc(sizeof(AmWordList)); + if (w == NULL) { + YYABORT; + } + if ($1 != NULL) { + AmWordListBuilder *words = $1; + + w->argc = words->wordCount; + w->argv = (const char **)malloc(w->argc * + sizeof(char *)); + if (w->argv == NULL) { + YYABORT; + } + int i; + for (i = w->argc; words != NULL && i > 0; --i) { + AmWordListBuilder *f = words; + w->argv[i-1] = words->word; + words = words->next; + free(f); + } + assert(i == 0); + assert(words == NULL); + } else { + w->argc = 0; + w->argv = NULL; + } + $$ = (AmCommandArguments *)malloc( + sizeof(AmCommandArguments)); + if ($$ == NULL) { + YYABORT; + } + $$->booleanArgs = false; + $$->u.w = w; + } + ; + +word_list : /* empty */ + { $$ = NULL; } + | word_list TOK_WORD + { + if ($1 == NULL) { + $$ = (AmWordListBuilder *)malloc( + sizeof(AmWordListBuilder)); + if ($$ == NULL) { + YYABORT; + } + $$->next = NULL; + $$->wordCount = 1; + } else { + $$ = (AmWordListBuilder *)malloc( + sizeof(AmWordListBuilder)); + if ($$ == NULL) { + YYABORT; + } + $$->next = $1; + $$->wordCount = $$->next->wordCount + 1; + } + $$->word = strdup($2); + if ($$->word == NULL) { + YYABORT; + } + } + ; + +boolean_expression : + '!' boolean_expression + { + $$ = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); + if ($$ == NULL) { + YYABORT; + } + $$->type = AM_BVAL_EXPRESSION; + $$->u.expression.op = AM_BOP_NOT; + $$->u.expression.arg1 = $2; + $$->u.expression.arg2 = NULL; + } + /* TODO: if both expressions are literals, evaluate now */ + | boolean_expression TOK_AND boolean_expression + { BOOLEAN_EXPRESSION($$, $1, AM_BOP_AND, $3); } + | boolean_expression TOK_OR boolean_expression + { BOOLEAN_EXPRESSION($$, $1, AM_BOP_OR, $3); } + | boolean_expression TOK_EQ boolean_expression + { BOOLEAN_EXPRESSION($$, $1, AM_BOP_EQ, $3); } + | boolean_expression TOK_NE boolean_expression + { BOOLEAN_EXPRESSION($$, $1, AM_BOP_NE, $3); } + | '(' boolean_expression ')' + { $$ = $2; } + /* TODO: if both strings are literals, evaluate now */ + | string_value '<' string_value + { STRING_COMPARISON($$, $1, AM_SOP_LT, $3); } + | string_value '>' string_value + { STRING_COMPARISON($$, $1, AM_SOP_GT, $3); } + | string_value TOK_EQ string_value + { STRING_COMPARISON($$, $1, AM_SOP_EQ, $3); } + | string_value TOK_NE string_value + { STRING_COMPARISON($$, $1, AM_SOP_NE, $3); } + | string_value TOK_LE string_value + { STRING_COMPARISON($$, $1, AM_SOP_LE, $3); } + | string_value TOK_GE string_value + { STRING_COMPARISON($$, $1, AM_SOP_GE, $3); } + ; + +string_value : + TOK_IDENTIFIER + { + $$ = (AmStringValue *)malloc(sizeof(AmStringValue)); + if ($$ == NULL) { + YYABORT; + } + $$->type = AM_SVAL_LITERAL; + $$->u.literal = strdup($1); + if ($$->u.literal == NULL) { + YYABORT; + } + } + | TOK_STRING + { + $$ = (AmStringValue *)malloc(sizeof(AmStringValue)); + if ($$ == NULL) { + YYABORT; + } + $$->type = AM_SVAL_LITERAL; + $$->u.literal = strdup($1); + if ($$->u.literal == NULL) { + YYABORT; + } + } + | function_call + { + $$ = (AmStringValue *)malloc(sizeof(AmStringValue)); + if ($$ == NULL) { + YYABORT; + } + $$->type = AM_SVAL_FUNCTION; + $$->u.function = $1; + } + ; + + /* We can't just say + * TOK_IDENTIFIER '(' function_arguments_or_empty ')' + * because parsing function_arguments_or_empty will clobber + * the underlying string that yylval.literalString points to. + */ +function_call : + function_name '(' function_arguments_or_empty ')' + { + Function *fn = findFunction($1); + if (fn == NULL) { + fprintf(stderr, "Unknown function \"%s\"\n", $1); + YYABORT; + } + $$ = (AmFunctionCall *)malloc(sizeof(AmFunctionCall)); + if ($$ == NULL) { + YYABORT; + } + $$->name = $1; + if ($$->name == NULL) { + YYABORT; + } + $$->fn = fn; + $$->args = $3; + } + ; + +function_name : + TOK_IDENTIFIER + { + $$ = strdup($1); + } + ; + +function_arguments_or_empty : + /* empty */ + { + $$ = (AmFunctionArguments *)malloc( + sizeof(AmFunctionArguments)); + if ($$ == NULL) { + YYABORT; + } + $$->argc = 0; + $$->argv = NULL; + } + | function_arguments + { + AmFunctionArgumentBuilder *args = $1; + assert(args != NULL); + + /* Convert the builder list into an array. + * Do it in reverse order; the args were pushed + * onto the list in LIFO order. + */ + $$ = (AmFunctionArguments *)malloc( + sizeof(AmFunctionArguments)); + if ($$ == NULL) { + YYABORT; + } + $$->argc = args->argCount; + $$->argv = (AmStringValue *)malloc( + $$->argc * sizeof(AmStringValue)); + if ($$->argv == NULL) { + YYABORT; + } + int i; + for (i = $$->argc; args != NULL && i > 0; --i) { + AmFunctionArgumentBuilder *f = args; + $$->argv[i-1] = *args->arg; + args = args->next; + free(f->arg); + free(f); + } + assert(i == 0); + assert(args == NULL); + } + ; + +function_arguments : + string_value + { + $$ = (AmFunctionArgumentBuilder *)malloc( + sizeof(AmFunctionArgumentBuilder)); + if ($$ == NULL) { + YYABORT; + } + $$->next = NULL; + $$->argCount = 1; + $$->arg = $1; + } + | function_arguments ',' string_value + { + $$ = (AmFunctionArgumentBuilder *)malloc( + sizeof(AmFunctionArgumentBuilder)); + if ($$ == NULL) { + YYABORT; + } + $$->next = $1; + $$->argCount = $$->next->argCount + 1; + $$->arg = $3; + } + ; + /* xxx this whole tool needs to be hardened */ |