1507
|
1 %{
|
|
2 #define yymaxdepth pn_script_parser_maxdepth
|
|
3 #define yyparse pn_script_parser_parse
|
|
4 #define yylex pn_script_parser_lex
|
|
5 #define yyerror pn_script_parser_error
|
|
6 #define yylval pn_script_parser_lval
|
|
7 #define yychar pn_script_parser_char
|
|
8 #define yydebug pn_script_parser_debug
|
|
9 #define yypact pn_script_parser_pact
|
|
10 #define yyr1 pn_script_parser_r1
|
|
11 #define yyr2 pn_script_parser_r2
|
|
12 #define yydef pn_script_parser_def
|
|
13 #define yychk pn_script_parser_chk
|
|
14 #define yypgo pn_script_parser_pgo
|
|
15 #define yyact pn_script_parser_act
|
|
16 #define yyexca pn_script_parser_exca
|
|
17 #define yyerrflag pn_script_parser_errflag
|
|
18 #define ynerrs pn_script_parser_nerrs
|
|
19 #define yyps pn_script_parser_ps
|
|
20 #define yypv pn_script_parser_pv
|
|
21 #define yys pn_script_parser_s
|
|
22 #define yy_yys pn_script_parser_yys
|
|
23 #define yystate pn_script_parser_state
|
|
24 #define yytmp pn_script_parser_tmp
|
|
25 #define yyv pn_script_parser_v
|
|
26 #define yy_yyv pn_script_parser_yyv
|
|
27 #define yyval pn_script_parser_val
|
|
28 #define yylloc pn_script_parser_lloc
|
|
29 #define yyreds pn_script_parser_reds
|
|
30 #define yytoks pn_script_parser_toks
|
|
31 #define yylhs pn_script_parser_yylhs
|
|
32 #define yylen pn_script_parser_yylen
|
|
33 #define yydefred pn_script_parser_yydefred
|
|
34 #define yydgoto pn_script_parser_yydgoto
|
|
35 #define yysindex pn_script_parser_yysindex
|
|
36 #define yyrindex pn_script_parser_yyrindex
|
|
37 #define yygindex pn_script_parser_yygindex
|
|
38 #define yytable pn_script_parser_yytable
|
|
39 #define yycheck pn_script_parser_yycheck
|
|
40 #define yyname pn_script_parser_yyname
|
|
41 #define yyrule pn_script_parser_yyrule
|
|
42
|
|
43 #include <ctype.h>
|
|
44 #include <stdlib.h>
|
|
45 #include <glib.h>
|
|
46 #include <pn/pnscript.h>
|
|
47
|
|
48 /* define this to dump the parser output to stdout */
|
|
49 /* #define PN_PRINT_OPS 1 */
|
|
50
|
|
51 int yyerror (char *s);
|
|
52 int yylex (void);
|
|
53
|
|
54 static gboolean parse_failed;
|
|
55
|
|
56 /* Are we on the size-determining pass? */
|
|
57 static gboolean size_pass;
|
|
58
|
|
59 /* Used during the size pass to determine the size of the constant table */
|
|
60 static GArray *temp_constant_table = NULL;
|
|
61
|
|
62 /* The code size */
|
|
63 static guint code_size;
|
|
64
|
|
65 /* The current code byte */
|
|
66 static guint *code_ptr;
|
|
67
|
|
68 /* Input variables used during parsing */
|
|
69 static PnScript *parse_script;
|
|
70 static const gchar *parse_string;
|
|
71 %}
|
|
72
|
|
73 %union {
|
|
74 gdouble *constant;
|
|
75 PnVariable *variable;
|
|
76 }
|
|
77
|
|
78 %token <constant> CONSTANT
|
|
79 %token <variable> VARIABLE
|
|
80 /* Functions */
|
|
81 %token ABS_FUNC
|
|
82 %token MAX_FUNC
|
|
83 %token MIN_FUNC
|
|
84 %token SIN_FUNC
|
|
85 %token COS_FUNC
|
|
86 %token TAN_FUNC
|
|
87 %token ASIN_FUNC
|
|
88 %token ACOS_FUNC
|
|
89 %token ATAN_FUNC
|
|
90
|
|
91
|
|
92 %right '='
|
|
93 %left '-' '+'
|
|
94 %left '*' '/'
|
|
95 %left NEG
|
|
96 %right '^'
|
|
97
|
|
98 %%
|
|
99
|
|
100 script
|
|
101 : /* empty */
|
|
102 | script statement
|
|
103 ;
|
|
104
|
|
105 statement
|
|
106 : equation ';'
|
|
107 {
|
|
108 if (size_pass)
|
|
109 code_size += sizeof (guint);
|
|
110 else
|
|
111 {
|
|
112 *code_ptr++ = PN_OP_POP;
|
|
113
|
|
114 #ifdef PN_PRINT_OPS
|
|
115 g_print ("POP\n");
|
|
116 #endif /* PN_PRINT_OPS */
|
|
117 }
|
|
118 }
|
|
119 ;
|
|
120
|
|
121 equation
|
|
122 : VARIABLE '=' expression
|
|
123 {
|
|
124 if (size_pass)
|
|
125 code_size += sizeof (guint) + sizeof (gdouble *);
|
|
126 else
|
|
127 {
|
|
128 *code_ptr++ = PN_OP_SET;
|
|
129 *code_ptr++ = (guint) $1;
|
|
130
|
|
131 #ifdef PN_PRINT_OPS
|
|
132 g_print ("SET %s\n", $1->name);
|
|
133 #endif /* PN_PRINT_OPS */
|
|
134 }
|
|
135 }
|
|
136
|
|
137 expression
|
|
138 : CONSTANT
|
|
139 {
|
|
140 if (size_pass)
|
|
141 code_size += sizeof (guint) + sizeof (gdouble *);
|
|
142 else
|
|
143 {
|
|
144 *code_ptr++ = PN_OP_PUSHC;
|
|
145 *code_ptr++ = GPOINTER_TO_UINT ($1);
|
|
146
|
|
147 #ifdef PN_PRINT_OPS
|
|
148 g_print ("PUSHC %f\n", *$1);
|
|
149 #endif /* PN_PRINT_OPS */
|
|
150 }
|
|
151 }
|
|
152 | VARIABLE
|
|
153 {
|
|
154 if (size_pass)
|
|
155 code_size += sizeof (guint) + sizeof (gdouble *);
|
|
156 else
|
|
157 {
|
|
158 *code_ptr++ = PN_OP_PUSHV;
|
|
159 *code_ptr++ = (guint) $1;
|
|
160
|
|
161 #ifdef PN_PRINT_OPS
|
|
162 g_print ("PUSHV %s\n", $1->name);
|
|
163 #endif /* PN_PRINT_OPS */
|
|
164 }
|
|
165 }
|
|
166 | equation
|
|
167 | ABS_FUNC '(' expression ')'
|
|
168 {
|
|
169 if (size_pass)
|
|
170 code_size += sizeof (guint);
|
|
171 else
|
|
172 {
|
|
173 *code_ptr++ = PN_OP_ABS;
|
|
174 #ifdef PN_PRINT_OPS
|
|
175 g_print ("ABS\n");
|
|
176 #endif /* PN_PRINT_OPS */
|
|
177 }
|
|
178 }
|
|
179 | MAX_FUNC '(' expression ',' expression ')'
|
|
180 {
|
|
181 if (size_pass)
|
|
182 code_size += sizeof (guint);
|
|
183 else
|
|
184 {
|
|
185 *code_ptr++ = PN_OP_MAX;
|
|
186 #ifdef PN_PRINT_OPS
|
|
187 g_print ("MAX\n");
|
|
188 #endif /* PN_PRINT_OPS */
|
|
189 }
|
|
190 }
|
|
191 | MIN_FUNC '(' expression ',' expression ')'
|
|
192 {
|
|
193 if (size_pass)
|
|
194 code_size += sizeof (guint);
|
|
195 else
|
|
196 {
|
|
197 *code_ptr++ = PN_OP_MIN;
|
|
198
|
|
199 #ifdef PN_PRINT_OPS
|
|
200 g_print ("MIN\n");
|
|
201 #endif /* PN_PRINT_OPS */
|
|
202 }
|
|
203
|
|
204 }
|
|
205 | SIN_FUNC '(' expression ')'
|
|
206 {
|
|
207 if (size_pass)
|
|
208 code_size += sizeof (guint);
|
|
209 else
|
|
210 {
|
|
211 *code_ptr++ = PN_OP_SIN;
|
|
212
|
|
213 #ifdef PN_PRINT_OPS
|
|
214 g_print ("SIN\n");
|
|
215 #endif /* PN_PRINT_OPS */
|
|
216 }
|
|
217
|
|
218 }
|
|
219 | COS_FUNC '(' expression ')'
|
|
220 {
|
|
221 if (size_pass)
|
|
222 code_size += sizeof (guint);
|
|
223 else
|
|
224 {
|
|
225 *code_ptr++ = PN_OP_COS;
|
|
226
|
|
227 #ifdef PN_PRINT_OPS
|
|
228 g_print ("COS\n");
|
|
229 #endif /* PN_PRINT_OPS */
|
|
230 }
|
|
231
|
|
232 }
|
|
233 | TAN_FUNC '(' expression ')'
|
|
234 {
|
|
235 if (size_pass)
|
|
236 code_size += sizeof (guint);
|
|
237 else
|
|
238 {
|
|
239 *code_ptr++ = PN_OP_TAN;
|
|
240
|
|
241 #ifdef PN_PRINT_OPS
|
|
242 g_print ("TAN\n");
|
|
243 #endif /* PN_PRINT_OPS */
|
|
244 }
|
|
245
|
|
246 }
|
|
247 | ASIN_FUNC '(' expression ')'
|
|
248 {
|
|
249 if (size_pass)
|
|
250 code_size += sizeof (guint);
|
|
251 else
|
|
252 {
|
|
253 *code_ptr++ = PN_OP_ASIN;
|
|
254
|
|
255 #ifdef PN_PRINT_OPS
|
|
256 g_print ("ASIN\n");
|
|
257 #endif /* PN_PRINT_OPS */
|
|
258 }
|
|
259
|
|
260 }
|
|
261 | ACOS_FUNC '(' expression ')'
|
|
262 {
|
|
263 if (size_pass)
|
|
264 code_size += sizeof (guint);
|
|
265 else
|
|
266 {
|
|
267 *code_ptr++ = PN_OP_ACOS;
|
|
268
|
|
269 #ifdef PN_PRINT_OPS
|
|
270 g_print ("ACOS\n");
|
|
271 #endif /* PN_PRINT_OPS */
|
|
272 }
|
|
273
|
|
274 }
|
|
275 | ATAN_FUNC '(' expression ')'
|
|
276 {
|
|
277 if (size_pass)
|
|
278 code_size += sizeof (guint);
|
|
279 else
|
|
280 {
|
|
281 *code_ptr++ = PN_OP_ATAN;
|
|
282
|
|
283 #ifdef PN_PRINT_OPS
|
|
284 g_print ("ATAN\n");
|
|
285 #endif /* PN_PRINT_OPS */
|
|
286 }
|
|
287
|
|
288 }
|
|
289 | expression '+' expression
|
|
290 {
|
|
291 if (size_pass)
|
|
292 code_size += sizeof (guint);
|
|
293 else
|
|
294 {
|
|
295 *code_ptr++ = PN_OP_ADD;
|
|
296
|
|
297 #ifdef PN_PRINT_OPS
|
|
298 g_print ("ADD\n");
|
|
299 #endif /* PN_PRINT_OPS */
|
|
300 }
|
|
301 }
|
|
302 | expression '-' expression
|
|
303 {
|
|
304 if (size_pass)
|
|
305 code_size += sizeof (guint);
|
|
306 else
|
|
307 {
|
|
308 *code_ptr++ = PN_OP_SUB;
|
|
309 #ifdef PN_PRINT_OPS
|
|
310 g_print ("SUB\n");
|
|
311 #endif /* PN_PRINT_OPS */
|
|
312 }
|
|
313 }
|
|
314 | expression '*' expression
|
|
315 {
|
|
316 if (size_pass)
|
|
317 code_size += sizeof (guint);
|
|
318 else
|
|
319 {
|
|
320 *code_ptr++ = PN_OP_MUL;
|
|
321
|
|
322 #ifdef PN_PRINT_OPS
|
|
323 g_print ("MUL\n");
|
|
324 #endif /* PN_PRINT_OPS */
|
|
325 }
|
|
326 }
|
|
327 | expression '/' expression
|
|
328 {
|
|
329 if (size_pass)
|
|
330 code_size += sizeof (guint);
|
|
331 else
|
|
332 {
|
|
333 *code_ptr++ = PN_OP_DIV;
|
|
334
|
|
335 #ifdef PN_PRINT_OPS
|
|
336 g_print ("DIV\n");
|
|
337 #endif /* PN_PRINT_OPS */
|
|
338 }
|
|
339 }
|
|
340 | '-' expression %prec NEG
|
|
341 {
|
|
342 if (size_pass)
|
|
343 code_size += sizeof (guint);
|
|
344 else
|
|
345 {
|
|
346 *code_ptr++ = PN_OP_NEG;
|
|
347
|
|
348 #ifdef PN_PRINT_OPS
|
|
349 g_print ("NEG\n");
|
|
350 #endif /* PN_PRINT_OPS */
|
|
351 }
|
|
352 }
|
|
353 | expression '^' expression
|
|
354 {
|
|
355 if (size_pass)
|
|
356 code_size += sizeof (guint);
|
|
357 else
|
|
358 {
|
|
359 *code_ptr++ = PN_OP_POW;
|
|
360
|
|
361 #ifdef PN_PRINT_OPS
|
|
362 g_print ("POW\n");
|
|
363 #endif /* PN_PRINT_OPS */
|
|
364 }
|
|
365 }
|
|
366 | '(' expression ')'
|
|
367 ;
|
|
368
|
|
369 %%
|
|
370
|
|
371 static gdouble
|
|
372 get_named_constant_value (const gchar *name)
|
|
373 {
|
|
374 if (g_strcasecmp (name, "pi") == 0)
|
|
375 return G_PI;
|
|
376
|
|
377 /* This is a failure, so don't make a "zero" :) */
|
|
378 return 0.0;
|
|
379 }
|
|
380
|
|
381 static guint
|
|
382 get_function_token_type (const gchar *name)
|
|
383 {
|
|
384 if (g_strcasecmp (name, "abs") == 0)
|
|
385 return ABS_FUNC;
|
|
386 if (g_strcasecmp (name, "max") == 0)
|
|
387 return MAX_FUNC;
|
|
388 if (g_strcasecmp (name, "min") == 0)
|
|
389 return MIN_FUNC;
|
|
390 if (g_strcasecmp (name, "sin") == 0)
|
|
391 return SIN_FUNC;
|
|
392 if (g_strcasecmp (name, "cos") == 0)
|
|
393 return COS_FUNC;
|
|
394 if (g_strcasecmp (name, "tan") == 0)
|
|
395 return TAN_FUNC;
|
|
396 if (g_strcasecmp (name, "asin") == 0)
|
|
397 return ASIN_FUNC;
|
|
398 if (g_strcasecmp (name, "acos") == 0)
|
|
399 return ACOS_FUNC;
|
|
400 if (g_strcasecmp (name, "atan") == 0)
|
|
401 return ATAN_FUNC;
|
|
402
|
|
403 return 0;
|
|
404 }
|
|
405
|
|
406 static gdouble*
|
|
407 get_constant_ptr (gdouble value)
|
|
408 {
|
|
409 guint i;
|
|
410
|
|
411 if (size_pass)
|
|
412 {
|
|
413 for (i=0; i<temp_constant_table->len; i++)
|
|
414 if (g_array_index (temp_constant_table, gdouble, i) == value)
|
|
415 return (gdouble *) TRUE;
|
|
416
|
|
417 /* Add a constant */
|
|
418 g_array_append_val (temp_constant_table, value);
|
|
419 return (gdouble *) TRUE;
|
|
420 }
|
|
421 else
|
|
422 {
|
|
423 for (i=0; i<temp_constant_table->len; i++)
|
|
424 if (parse_script->constant_table[i] == value)
|
|
425 return &parse_script->constant_table[i];
|
|
426
|
|
427 return NULL; /* This should never be reached */
|
|
428 }
|
|
429 }
|
|
430
|
|
431 int
|
|
432 yylex (void)
|
|
433 {
|
|
434 /* Skip whitespaces */
|
|
435 while (isspace (*parse_string)) parse_string++;
|
|
436
|
|
437 /* Handle the end of the string */
|
|
438 if (*parse_string == '\0')
|
|
439 return 0;
|
|
440
|
|
441 /* Handle unnamed (numeric) constants */
|
|
442 if (*parse_string == '.' || isdigit (*parse_string))
|
|
443 {
|
|
444 gdouble value;
|
|
445
|
|
446 value = strtod (parse_string, (char **) &parse_string);
|
|
447 yylval.constant = get_constant_ptr (value);
|
|
448
|
|
449 return CONSTANT;
|
|
450 }
|
|
451
|
|
452 /* Handle alphanumeric symbols */
|
|
453 if (isalpha (*parse_string))
|
|
454 {
|
|
455 const gchar *symbol_start = parse_string;
|
|
456 guint function_token;
|
|
457 gchar *symbol_name;
|
|
458
|
|
459 while (isalnum (*parse_string) || *parse_string == '_') parse_string++;
|
|
460
|
|
461 symbol_name = g_strndup (symbol_start, parse_string - symbol_start);
|
|
462
|
|
463 /* Handle a named constant (e.g. 'pi') */
|
|
464 if (get_named_constant_value (symbol_name))
|
|
465 {
|
|
466 yylval.constant = get_constant_ptr (get_named_constant_value (symbol_name));
|
|
467
|
|
468 g_free (symbol_name);
|
|
469
|
|
470 return CONSTANT;
|
|
471 }
|
|
472
|
|
473 /* Handle a function (e.g. 'max') */
|
|
474 if ((function_token = get_function_token_type (symbol_name)))
|
|
475 {
|
|
476 g_free (symbol_name);
|
|
477
|
|
478 return function_token;
|
|
479 }
|
|
480
|
|
481 /* Handle a variable */
|
|
482 if (! size_pass)
|
|
483 yylval.variable = pn_symbol_table_ref_variable_by_name (parse_script->symbol_table,
|
|
484 symbol_name);
|
|
485
|
|
486 g_free (symbol_name);
|
|
487
|
|
488 return VARIABLE;
|
|
489 }
|
|
490
|
|
491 /* Handle a single-character symbol (or invalid tokens) */
|
|
492 return *parse_string++;
|
|
493 }
|
|
494
|
|
495 int
|
|
496 yyerror (char *s)
|
|
497 {
|
|
498 parse_failed = TRUE;
|
|
499
|
|
500 return 0;
|
|
501 }
|
|
502
|
|
503 gboolean
|
|
504 pn_script_internal_parse_string (PnScript *script, const gchar *string)
|
|
505 {
|
|
506 guint i;
|
|
507
|
|
508 g_return_val_if_fail (script != NULL, FALSE);
|
|
509 g_return_val_if_fail (PN_IS_SCRIPT (script), FALSE);
|
|
510 g_return_val_if_fail (string != NULL, FALSE);
|
|
511
|
|
512 /* Make a new temp constant table if needed */
|
|
513 if (! temp_constant_table)
|
|
514 temp_constant_table = g_array_new (FALSE, FALSE, sizeof (gdouble));
|
|
515
|
|
516 parse_failed = FALSE;
|
|
517
|
|
518 parse_script = script;
|
|
519 parse_string = string;
|
|
520
|
|
521 /* First determine the code size */
|
|
522 size_pass = TRUE;
|
|
523 code_size = 0;
|
|
524 yyparse ();
|
|
525
|
|
526 if (parse_failed)
|
|
527 return FALSE;
|
|
528
|
|
529 if (code_size == 0)
|
|
530 return TRUE;
|
|
531
|
|
532 /* Now generate the real code */
|
|
533 size_pass = FALSE;
|
|
534 parse_string = string;
|
|
535 script->code = g_malloc (code_size);
|
|
536 script->constant_table = g_malloc (temp_constant_table->len * sizeof (gdouble));
|
|
537 for (i=0; i<temp_constant_table->len; i++)
|
|
538 script->constant_table[i] = g_array_index (temp_constant_table, gdouble, i);
|
|
539 code_ptr = script->code;
|
|
540 yyparse ();
|
|
541 g_array_set_size (temp_constant_table, 0);
|
|
542
|
|
543 /* Terminate the script, replacing the last POP with an END */
|
|
544 *(code_ptr-1) = PN_OP_END;
|
|
545
|
|
546 #ifdef PN_PRINT_OPS
|
|
547 g_print ("END\n");
|
|
548 #endif /* PN_PRINT_OPS */
|
|
549
|
|
550 return TRUE;
|
|
551 }
|