16
16
17
17
PgBenchExpr *expr_parse_result;
18
18
19
+ static PgBenchExprList *make_elist (PgBenchExpr *exp, PgBenchExprList *list);
19
20
static PgBenchExpr *make_integer_constant (int64 ival);
20
21
static PgBenchExpr *make_variable (char *varname);
21
- static PgBenchExpr *make_op (char operator , PgBenchExpr *lexpr,
22
+ static PgBenchExpr *make_op (const char * operator , PgBenchExpr *lexpr,
22
23
PgBenchExpr *rexpr);
24
+ static int find_func (const char *fname);
25
+ static PgBenchExpr *make_func (const int fnumber, PgBenchExprList *args);
23
26
24
27
%}
25
28
@@ -31,13 +34,15 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
31
34
int64 ival;
32
35
char *str;
33
36
PgBenchExpr *expr;
37
+ PgBenchExprList *elist;
34
38
}
35
39
40
+ %type <elist> elist
36
41
%type <expr> expr
37
- %type <ival> INTEGER
38
- %type <str> VARIABLE
42
+ %type <ival> INTEGER function
43
+ %type <str> VARIABLE FUNCTION
39
44
40
- %token INTEGER VARIABLE
45
+ %token INTEGER VARIABLE FUNCTION
41
46
%token CHAR_ERROR /* never used, will raise a syntax error */
42
47
43
48
/* Precedence: lowest to highest */
@@ -49,16 +54,25 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
49
54
50
55
result : expr { expr_parse_result = $1 ; }
51
56
57
+ elist : { $$ = NULL ; }
58
+ | expr { $$ = make_elist($1 , NULL ); }
59
+ | elist ' ,' expr { $$ = make_elist($3 , $1 ); }
60
+ ;
61
+
52
62
expr : ' (' expr ' )' { $$ = $2 ; }
53
63
| ' +' expr %prec UMINUS { $$ = $2 ; }
54
- | ' -' expr %prec UMINUS { $$ = make_op(' - ' , make_integer_constant(0 ), $2 ); }
55
- | expr ' +' expr { $$ = make_op(' + ' , $1 , $3 ); }
56
- | expr ' -' expr { $$ = make_op(' - ' , $1 , $3 ); }
57
- | expr ' *' expr { $$ = make_op(' * ' , $1 , $3 ); }
58
- | expr ' /' expr { $$ = make_op(' / ' , $1 , $3 ); }
59
- | expr ' %' expr { $$ = make_op(' % ' , $1 , $3 ); }
64
+ | ' -' expr %prec UMINUS { $$ = make_op(" - " , make_integer_constant(0 ), $2 ); }
65
+ | expr ' +' expr { $$ = make_op(" + " , $1 , $3 ); }
66
+ | expr ' -' expr { $$ = make_op(" - " , $1 , $3 ); }
67
+ | expr ' *' expr { $$ = make_op(" * " , $1 , $3 ); }
68
+ | expr ' /' expr { $$ = make_op(" / " , $1 , $3 ); }
69
+ | expr ' %' expr { $$ = make_op(" % " , $1 , $3 ); }
60
70
| INTEGER { $$ = make_integer_constant($1 ); }
61
71
| VARIABLE { $$ = make_variable($1 ); }
72
+ | function ' (' elist ' )' { $$ = make_func($1 , $3 ); }
73
+ ;
74
+
75
+ function : FUNCTION { $$ = find_func($1 ); pg_free($1 ); }
62
76
;
63
77
64
78
%%
@@ -84,14 +98,131 @@ make_variable(char *varname)
84
98
}
85
99
86
100
static PgBenchExpr *
87
- make_op (char operator , PgBenchExpr *lexpr, PgBenchExpr *rexpr)
101
+ make_op (const char *operator , PgBenchExpr *lexpr, PgBenchExpr *rexpr)
102
+ {
103
+ return make_func (find_func (operator ),
104
+ make_elist (rexpr, make_elist (lexpr, NULL )));
105
+ }
106
+
107
+ /*
108
+ * List of available functions:
109
+ * - fname: function name
110
+ * - nargs: number of arguments
111
+ * -1 is a special value for min & max meaning #args >= 1
112
+ * - tag: function identifier from PgBenchFunction enum
113
+ */
114
+ static struct
115
+ {
116
+ char * fname;
117
+ int nargs;
118
+ PgBenchFunction tag;
119
+ } PGBENCH_FUNCTIONS[] = {
120
+ /* parsed as operators, executed as functions */
121
+ { " +" , 2 , PGBENCH_ADD },
122
+ { " -" , 2 , PGBENCH_SUB },
123
+ { " *" , 2 , PGBENCH_MUL },
124
+ { " /" , 2 , PGBENCH_DIV },
125
+ { " %" , 2 , PGBENCH_MOD },
126
+ /* actual functions */
127
+ { " abs" , 1 , PGBENCH_ABS },
128
+ { " min" , -1 , PGBENCH_MIN },
129
+ { " max" , -1 , PGBENCH_MAX },
130
+ { " debug" , 1 , PGBENCH_DEBUG },
131
+ /* keep as last array element */
132
+ { NULL , 0 , 0 }
133
+ };
134
+
135
+ /*
136
+ * Find a function from its name
137
+ *
138
+ * return the index of the function from the PGBENCH_FUNCTIONS array
139
+ * or fail if the function is unknown.
140
+ */
141
+ static int
142
+ find_func (const char * fname)
143
+ {
144
+ int i = 0 ;
145
+
146
+ while (PGBENCH_FUNCTIONS[i].fname )
147
+ {
148
+ if (pg_strcasecmp (fname, PGBENCH_FUNCTIONS[i].fname ) == 0 )
149
+ return i;
150
+ i++;
151
+ }
152
+
153
+ expr_yyerror_more (" unexpected function name" , fname);
154
+
155
+ /* not reached */
156
+ return -1 ;
157
+ }
158
+
159
+ /* Expression linked list builder */
160
+ static PgBenchExprList *
161
+ make_elist (PgBenchExpr *expr, PgBenchExprList *list)
162
+ {
163
+ PgBenchExprLink * cons;
164
+
165
+ if (list == NULL )
166
+ {
167
+ list = pg_malloc (sizeof (PgBenchExprList));
168
+ list->head = NULL ;
169
+ list->tail = NULL ;
170
+ }
171
+
172
+ cons = pg_malloc (sizeof (PgBenchExprLink));
173
+ cons->expr = expr;
174
+ cons->next = NULL ;
175
+
176
+ if (list->head == NULL )
177
+ list->head = cons;
178
+ else
179
+ list->tail ->next = cons;
180
+
181
+ list->tail = cons;
182
+
183
+ return list;
184
+ }
185
+
186
+ /* Return the length of an expression list */
187
+ static int
188
+ elist_length (PgBenchExprList *list)
189
+ {
190
+ PgBenchExprLink *link = list != NULL ? list->head : NULL ;
191
+ int len = 0 ;
192
+
193
+ for (; link != NULL ; link = link ->next )
194
+ len++;
195
+
196
+ return len;
197
+ }
198
+
199
+ /* Build function call expression */
200
+ static PgBenchExpr *
201
+ make_func (const int fnumber, PgBenchExprList *args)
88
202
{
89
203
PgBenchExpr *expr = pg_malloc (sizeof (PgBenchExpr));
90
204
91
- expr->etype = ENODE_OPERATOR;
92
- expr->u .operator .operator = operator ;
93
- expr->u .operator .lexpr = lexpr;
94
- expr->u .operator .rexpr = rexpr;
205
+ Assert (fnumber >= 0 );
206
+
207
+ if (PGBENCH_FUNCTIONS[fnumber].nargs >= 0 &&
208
+ PGBENCH_FUNCTIONS[fnumber].nargs != elist_length (args))
209
+ expr_yyerror_more (" unexpected number of arguments" ,
210
+ PGBENCH_FUNCTIONS[fnumber].fname );
211
+
212
+ /* check at least one arg for min & max */
213
+ if (PGBENCH_FUNCTIONS[fnumber].nargs == -1 &&
214
+ elist_length (args) == 0 )
215
+ expr_yyerror_more (" at least one argument expected" ,
216
+ PGBENCH_FUNCTIONS[fnumber].fname );
217
+
218
+ expr->etype = ENODE_FUNCTION;
219
+ expr->u .function .function = PGBENCH_FUNCTIONS[fnumber].tag ;
220
+
221
+ /* only the link is used, the head/tail is not useful anymore */
222
+ expr->u .function .args = args != NULL ? args->head : NULL ;
223
+ if (args)
224
+ pg_free (args);
225
+
95
226
return expr;
96
227
}
97
228
0 commit comments