1616
1717PgBenchExpr *expr_parse_result;
1818
19+ static PgBenchExprList *make_elist (PgBenchExpr *exp, PgBenchExprList *list);
1920static PgBenchExpr *make_integer_constant (int64 ival);
2021static PgBenchExpr *make_variable (char *varname);
21- static PgBenchExpr *make_op (char operator , PgBenchExpr *lexpr,
22+ static PgBenchExpr *make_op (const char * operator , PgBenchExpr *lexpr,
2223 PgBenchExpr *rexpr);
24+ static int find_func (const char *fname);
25+ static PgBenchExpr *make_func (const int fnumber, PgBenchExprList *args);
2326
2427%}
2528
@@ -31,13 +34,15 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
3134 int64 ival;
3235 char *str;
3336 PgBenchExpr *expr;
37+ PgBenchExprList *elist;
3438}
3539
40+ %type <elist> elist
3641%type <expr> expr
37- %type <ival> INTEGER
38- %type <str> VARIABLE
42+ %type <ival> INTEGER function
43+ %type <str> VARIABLE FUNCTION
3944
40- %token INTEGER VARIABLE
45+ %token INTEGER VARIABLE FUNCTION
4146%token CHAR_ERROR /* never used, will raise a syntax error */
4247
4348/* Precedence: lowest to highest */
@@ -49,16 +54,25 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
4954
5055result : expr { expr_parse_result = $1 ; }
5156
57+ elist : { $$ = NULL ; }
58+ | expr { $$ = make_elist($1 , NULL ); }
59+ | elist ' ,' expr { $$ = make_elist($3 , $1 ); }
60+ ;
61+
5262expr : ' (' expr ' )' { $$ = $2 ; }
5363 | ' +' 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 ); }
6070 | INTEGER { $$ = make_integer_constant($1 ); }
6171 | VARIABLE { $$ = make_variable($1 ); }
72+ | function ' (' elist ' )' { $$ = make_func($1 , $3 ); }
73+ ;
74+
75+ function : FUNCTION { $$ = find_func($1 ); pg_free($1 ); }
6276 ;
6377
6478%%
@@ -84,14 +98,131 @@ make_variable(char *varname)
8498}
8599
86100static 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)
88202{
89203 PgBenchExpr *expr = pg_malloc (sizeof (PgBenchExpr));
90204
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+
95226 return expr;
96227}
97228
0 commit comments