431 lines
15 KiB
Plaintext
431 lines
15 KiB
Plaintext
/*
|
|
* 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 */
|