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 */
 |