1 %{
2 /*
3  * Copyright (C) 2009 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include "expr.h"
23 #include "yydefs.h"
24 #include "parser.h"
25 
26 extern int gLine;
27 extern int gColumn;
28 
29 void yyerror(Expr** root, int* error_count, const char* s);
30 int yyparse(Expr** root, int* error_count);
31 
32 struct yy_buffer_state;
33 void yy_switch_to_buffer(struct yy_buffer_state* new_buffer);
34 struct yy_buffer_state* yy_scan_string(const char* yystr);
35 
36 %}
37 
38 %locations
39 
40 %union {
41     char* str;
42     Expr* expr;
43     struct {
44         int argc;
45         Expr** argv;
46     } args;
47 }
48 
49 %token AND OR SUBSTR SUPERSTR EQ NE IF THEN ELSE ENDIF
50 %token <str> STRING BAD
51 %type <expr> expr
52 %type <args> arglist
53 
54 %parse-param {Expr** root}
55 %parse-param {int* error_count}
56 %error-verbose
57 
58 /* declarations in increasing order of precedence */
59 %left ';'
60 %left ','
61 %left OR
62 %left AND
63 %left EQ NE
64 %left '+'
65 %right '!'
66 
67 %%
68 
69 input:  expr           { *root = $1; }
70 ;
71 
72 expr:  STRING {
73     $$ = malloc(sizeof(Expr));
74     $$->fn = Literal;
75     $$->name = $1;
76     $$->argc = 0;
77     $$->argv = NULL;
78     $$->start = @$.start;
79     $$->end = @$.end;
80 }
81 |  '(' expr ')'                      { $$ = $2; $$->start=@$.start; $$->end=@$.end; }
82 |  expr ';'                          { $$ = $1; $$->start=@1.start; $$->end=@1.end; }
83 |  expr ';' expr                     { $$ = Build(SequenceFn, @$, 2, $1, $3); }
84 |  error ';' expr                    { $$ = $3; $$->start=@$.start; $$->end=@$.end; }
85 |  expr '+' expr                     { $$ = Build(ConcatFn, @$, 2, $1, $3); }
86 |  expr EQ expr                      { $$ = Build(EqualityFn, @$, 2, $1, $3); }
87 |  expr NE expr                      { $$ = Build(InequalityFn, @$, 2, $1, $3); }
88 |  expr AND expr                     { $$ = Build(LogicalAndFn, @$, 2, $1, $3); }
89 |  expr OR expr                      { $$ = Build(LogicalOrFn, @$, 2, $1, $3); }
90 |  '!' expr                          { $$ = Build(LogicalNotFn, @$, 1, $2); }
91 |  IF expr THEN expr ENDIF           { $$ = Build(IfElseFn, @$, 2, $2, $4); }
92 |  IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); }
93 | STRING '(' arglist ')' {
94     $$ = malloc(sizeof(Expr));
95     $$->fn = FindFunction($1);
96     if ($$->fn == NULL) {
97         char buffer[256];
98         snprintf(buffer, sizeof(buffer), "unknown function \"%s\"", $1);
99         yyerror(root, error_count, buffer);
100         YYERROR;
101     }
102     $$->name = $1;
103     $$->argc = $3.argc;
104     $$->argv = $3.argv;
105     $$->start = @$.start;
106     $$->end = @$.end;
107 }
108 ;
109 
110 arglist:    /* empty */ {
111     $$.argc = 0;
112     $$.argv = NULL;
113 }
114 | expr {
115     $$.argc = 1;
116     $$.argv = malloc(sizeof(Expr*));
117     $$.argv[0] = $1;
118 }
119 | arglist ',' expr {
120     $$.argc = $1.argc + 1;
121     $$.argv = realloc($$.argv, $$.argc * sizeof(Expr*));
122     $$.argv[$$.argc-1] = $3;
123 }
124 ;
125 
126 %%
127 
128 void yyerror(Expr** root, int* error_count, const char* s) {
129   if (strlen(s) == 0) {
130     s = "syntax error";
131   }
132   printf("line %d col %d: %s\n", gLine, gColumn, s);
133   ++*error_count;
134 }
135 
parse_string(const char * str,Expr ** root,int * error_count)136 int parse_string(const char* str, Expr** root, int* error_count) {
137     yy_switch_to_buffer(yy_scan_string(str));
138     return yyparse(root, error_count);
139 }
140