A few more changes to edify:
  - fix write_raw_image(); my last change neglected to close the write
    context, so the written image was corrupt.
  - each expression tracks the span of the source code from which it
    was compiled, so that assert()'s error message can include the
    source of the expression that failed.
  - the 'cookie' argument to each Function is replaced with a State
    object, which contains the cookie, the source script (for use with
    the above spans), and the current error message (replacing the
    global variables that were used for this purpose).
  - in the recovery image, a new command "ui_print" can be sent back
    through the command pipe to cause text to appear on the screen.
    Add a new ui_print() function to print things from scripts.
    Rename existing "print" function to "stdout".
		
	
		
			
				
	
	
		
			131 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| %{
 | |
| /*
 | |
|  * Copyright (C) 2009 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.
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "expr.h"
 | |
| #include "yydefs.h"
 | |
| #include "parser.h"
 | |
| 
 | |
| extern int gLine;
 | |
| extern int gColumn;
 | |
| 
 | |
| void yyerror(Expr** root, int* error_count, const char* s);
 | |
| int yyparse(Expr** root, int* error_count);
 | |
| 
 | |
| %}
 | |
| 
 | |
| %locations
 | |
| 
 | |
| %union {
 | |
|     char* str;
 | |
|     Expr* expr;
 | |
|     struct {
 | |
|         int argc;
 | |
|         Expr** argv;
 | |
|     } args;
 | |
| }
 | |
| 
 | |
| %token AND OR SUBSTR SUPERSTR EQ NE IF THEN ELSE ENDIF
 | |
| %token <str> STRING BAD
 | |
| %type <expr> expr
 | |
| %type <args> arglist
 | |
| 
 | |
| %parse-param {Expr** root}
 | |
| %parse-param {int* error_count}
 | |
| %error-verbose
 | |
| 
 | |
| /* declarations in increasing order of precedence */
 | |
| %left ';'
 | |
| %left ','
 | |
| %left OR
 | |
| %left AND
 | |
| %left EQ NE
 | |
| %left '+'
 | |
| %right '!'
 | |
| 
 | |
| %%
 | |
| 
 | |
| input:  expr           { *root = $1; }
 | |
| ;
 | |
| 
 | |
| expr:  STRING {
 | |
|     $$ = malloc(sizeof(Expr));
 | |
|     $$->fn = Literal;
 | |
|     $$->name = $1;
 | |
|     $$->argc = 0;
 | |
|     $$->argv = NULL;
 | |
|     $$->start = @$.start;
 | |
|     $$->end = @$.end;
 | |
| }
 | |
| |  '(' expr ')'                      { $$ = $2; $$->start=@$.start; $$->end=@$.end; }
 | |
| |  expr ';'                          { $$ = $1; $$->start=@1.start; $$->end=@1.end; }
 | |
| |  expr ';' expr                     { $$ = Build(SequenceFn, @$, 2, $1, $3); }
 | |
| |  error ';' expr                    { $$ = $3; $$->start=@$.start; $$->end=@$.end; }
 | |
| |  expr '+' expr                     { $$ = Build(ConcatFn, @$, 2, $1, $3); }
 | |
| |  expr EQ expr                      { $$ = Build(EqualityFn, @$, 2, $1, $3); }
 | |
| |  expr NE expr                      { $$ = Build(InequalityFn, @$, 2, $1, $3); }
 | |
| |  expr AND expr                     { $$ = Build(LogicalAndFn, @$, 2, $1, $3); }
 | |
| |  expr OR expr                      { $$ = Build(LogicalOrFn, @$, 2, $1, $3); }
 | |
| |  '!' expr                          { $$ = Build(LogicalNotFn, @$, 1, $2); }
 | |
| |  IF expr THEN expr ENDIF           { $$ = Build(IfElseFn, @$, 2, $2, $4); }
 | |
| |  IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); }
 | |
| | STRING '(' arglist ')' {
 | |
|     $$ = malloc(sizeof(Expr));
 | |
|     $$->fn = FindFunction($1);
 | |
|     if ($$->fn == NULL) {
 | |
|         char buffer[256];
 | |
|         snprintf(buffer, sizeof(buffer), "unknown function \"%s\"", $1);
 | |
|         yyerror(root, error_count, buffer);
 | |
|         YYERROR;
 | |
|     }
 | |
|     $$->name = $1;
 | |
|     $$->argc = $3.argc;
 | |
|     $$->argv = $3.argv;
 | |
|     $$->start = @$.start;
 | |
|     $$->end = @$.end;
 | |
| }
 | |
| ;
 | |
| 
 | |
| arglist:    /* empty */ {
 | |
|     $$.argc = 0;
 | |
|     $$.argv = NULL;
 | |
| }
 | |
| | expr {
 | |
|     $$.argc = 1;
 | |
|     $$.argv = malloc(sizeof(Expr*));
 | |
|     $$.argv[0] = $1;
 | |
| }
 | |
| | arglist ',' expr {
 | |
|     $$.argc = $1.argc + 1;
 | |
|     $$.argv = realloc($$.argv, $$.argc * sizeof(Expr*));
 | |
|     $$.argv[$$.argc-1] = $3;
 | |
| }
 | |
| ;
 | |
| 
 | |
| %%
 | |
| 
 | |
| void yyerror(Expr** root, int* error_count, const char* s) {
 | |
|   if (strlen(s) == 0) {
 | |
|     s = "syntax error";
 | |
|   }
 | |
|   printf("line %d col %d: %s\n", gLine, gColumn, s);
 | |
|   ++*error_count;
 | |
| }
 |