librdesc
Loading...
Searching...
No Matches
interpreter.c
1#include "grammar.h"
2#include "interpreter.h"
3#include "functions.h"
4
5#include <assert.h>
6#include <math.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11
13#include <rdesc/rdesc.h>
14#include <rdesc/cst_macros.h>
15#include <rdesc/util.h>
16
17/* We only call this function with nonterminals, starting from <stmt>. */
18double pm_interpreter(struct rdesc *p,
19 struct rdesc_node *n)
20{
21 switch (rid(n)) {
22 case NT_STMT:
23 /* continue evaluation from first child (<expr>) */
24 return pm_interpreter(p, rchild(p, n, 0));
25
26 case NT_EXPR:
27 switch (ralt_idx(n)) {
28 case 0: /* <exponentiation_expr> "|" <pipe_expr>*/
29 /* flip <pipe_expr> to left-associative order */
30 rdesc_flip_left(p, n, 2);
31
32 /* Start pipe evaluation from left-to-right. */
33 return pm_interpret_pipe(p,
34 rchild(p, n, 2),
35 pm_interpreter(p, rchild(p, n, 0)));
36 default: /* <exponentiation_expr> */
37 return pm_interpreter(p, rchild(p, n, 0));
38 }
39
40 case NT_EXPONENTIATION_EXPR:
41 /* <num> <exponentiation_expr_rest> */
42 return pow(pm_extract_num(rchild(p, n, 0)),
43 pm_interpreter(p, rchild(p, n, 1)));
44
45 case NT_EXPONENTIATION_EXPR_REST:
46 switch (ralt_idx(n)) {
47 case 0: /* "^" <num> <exponentiation_expr_rest> */
48 return pow(pm_extract_num(rchild(p, n, 1)),
49 pm_interpreter(p, rchild(p, n, 2)));
50 default: /* E */
51 return 1;
52 }
53 }
54
55 return 0; // GCOVR_EXCL_LINE: Unreachable
56}
58
59
61double pm_extract_num(struct rdesc_node *num)
62{
63 char *seminfo;
64
65 /* seminfo stores a pointer to number, so it is a char **.
66 *
67 * Aside: We need to use memcpy to retrieve char * from char ** to not
68 * break strict-aliasing rule. */
69 memcpy(&seminfo, rseminfo(num), sizeof(char *));
70
71 double seminfo_num = atof(seminfo);
72
73 free(seminfo);
74
75 return seminfo_num;
76}
78
79
81/* Called for <pipe_expr>. */
82double pm_interpret_pipe(struct rdesc *p,
83 struct rdesc_node *pipe,
84 double lhs /* value at left-hand side of pipe */)
85{
86 switch (ralt_idx(pipe)) {
87 case 0: /* <pipe_expr> "|" <function_call> */
88 return pm_interpret_function(p, rchild(p, pipe, 2),
89 pm_interpret_pipe(p, rchild(p, pipe, 0), lhs));
90
91 default: /* <function_call> */
92 return pm_interpret_function(p, rchild(p, pipe, 0), lhs);
93 }
94}
96
97static void collect_function_args(struct rdesc *p,
98 struct rdesc_node *args,
99 size_t *argc, double **argv)
100{
101 size_t current_idx;
102
103 switch (rid(args)) {
104 case NT_FUNCTION_ARG_LS: /* <expr> <function_arg_ls_rest> */
105 current_idx = (*argc)++;
106
107 collect_function_args(p, rchild(p, args, 1), argc, argv);
108
109 break;
110
111 case NT_FUNCTION_ARG_LS_REST:
112 switch (ralt_idx(args)) {
113 case 0: /* "," <expr> <function_arg_ls_rest> */
114 current_idx = (*argc)++;
115
116 collect_function_args(p, rchild(p, args, 2), argc, argv);
117
118 break;
119
120 case 1: /* E */
121 assert(*argv = malloc(sizeof(double) * *argc));
122
123 return;
124 }
125 }
126
127 (*argv)[current_idx] =
128 pm_interpreter(p, rchild(p, args, rid(args) == NT_FUNCTION_ARG_LS ? 0 : 1));
129}
130
131double pm_interpret_function(struct rdesc *p,
132 struct rdesc_node *function,
133 double lhs)
134{
135 char *function_name;
136
137 /* child at index 0 is always function name (identifier) */
138 memcpy(&function_name, rseminfo(rchild(p, function, 0)), sizeof(char *));
139
140 size_t function_id;
141
142 for (function_id = 0; function_id < pm_function_count; function_id++) {
143 if (strcmp(function_name, pm_function_names[function_id]) == 0)
144 break;
145 }
146
147 size_t argc = 0;
148 double *argv = NULL;
149 double result;
150
151 if (ralt_idx(function) == 0) { /* ident "(" <function_arg_ls> ")" */
152 collect_function_args(p, rchild(p, function, 2), &argc, &argv);
153 } else { /* ident */ }
154
155 if (function_id == pm_function_count) {
156 fprintf(stderr, "Unknown function %s, ignoring\n", function_name);
157
158 result = lhs;
159 } else {
160 result = pm_functions[function_id](lhs, argc, argv);
161 }
162
163 if (argv)
164 free(argv);
165
166 free(function_name);
167
168 return result;
169}
#define rid(node)
Returns the 15-bit identifier for underlying token/nonterminal.
Definition cst_macros.h:77
#define rchild(p, nt_node, child_idx)
Returns child of the node by its index.
Definition cst_macros.h:115
#define ralt_idx(nt_node)
Returns index of the nonterminal alternative in production rule.
Definition cst_macros.h:84
#define rseminfo(tk_node)
Returns a reference to the token's seminfo field.
Definition cst_macros.h:99
Grammar data structures.
Recursive descent parser state.
Definition rdesc.h:40
void rdesc_flip_left(struct rdesc *parser, struct rdesc_node *parent, uint16_t child_index)
Rotates a right-recursive concrete syntax tree into a left-recursive form.