1 /*
2  * This file is part of the Yices SMT Solver.
3  * Copyright (C) 2017 SRI International.
4  *
5  * Yices is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Yices is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Yices.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /*
20  * Build tables for parsing and relatives
21  * - the input is a set of triples <state, token, value>
22  *   or <state, default, value>, and a global default value d
23  * - the set must be deterministic: no triples have the same
24  *   state and token.
25  *
26  * This defines a function f that maps states and tokens to values:
27  * - f(s, t) = v if <s, t, v> is a triple
28  * - f(s, t) = v0 if <s, default, v0> is a triple and there's no
29  *   triple of the form <s, t, _>
30  * - f(s, t) = global default otherwise.
31  *
32  * The code builds four tables default, table, val, and check
33  * that encode the function in a compact way.
34  * - for every state c,
35  *   default[c] = a default value for state c (or error)
36  *   base[c] = an index in array val and check
37  * - for an index i,
38  *   val[i] = a value
39  *   check[i] = a state
40  *
41  * The goal is to build the table so that f(s, t) is computed
42  * as follows:
43  * let i = base[s] + t;
44  * if check[i] = s then return val[i] else return default[s]
45  */
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdbool.h>
50 #include <string.h>
51 
52 
53 /*
54  * The specification file must define
55  * NSTATES, NTOKENS, DEFAULT_TOKEN, DEFAULT_VALUE, and triple
56  */
57 // #include "smt2_input_tables.h"
58 #include "yices_input_tables.h"
59 
60 /*
61  * Descriptor for each state
62  */
63 typedef struct edge_s {
64   int token;
65   char * val;
66 } edge_t;
67 
68 typedef struct {
69   char * def; // default value for that state
70   int nedges;  // number of edges known
71   int size;    // size of array edge
72   edge_t *edge;
73 } state_desc_t;
74 
75 static state_desc_t state[NSTATES];
76 
77 /*
78  * Initialization
79  */
init_state_descriptors(void)80 static void init_state_descriptors(void) {
81   int i;
82   edge_t *tmp;
83 
84   for (i=0; i<NSTATES; i++) {
85     state[i].def = DEFAULT_VALUE;
86     state[i].nedges = 0;
87     state[i].size = 2;
88     tmp = (edge_t *) malloc(20 * sizeof(edge_t));
89     if (tmp == NULL) {
90       fprintf(stderr, "Malloc failed; could not allocate descriptors\n");
91       abort();
92     }
93     state[i].edge = tmp;
94   }
95 }
96 
97 /*
98  * Add edge x, val to state i
99  */
add_edge(int i,int x,char * v)100 static void add_edge(int i, int x, char * v) {
101   state_desc_t *desc;
102   edge_t *e;
103   int j, n;
104 
105   desc = state + i;
106 
107   if (x == DEFAULT_TOKEN) {
108     if (strcmp(desc->def, DEFAULT_VALUE) == 0) {
109       desc->def = v;
110     } else {
111       fprintf(stderr, "Error: two default values for state %d\n", i);
112       abort();
113     }
114   } else {
115     e = desc->edge;
116     for (j=0; j<desc->nedges; j++) {
117       if (e[j].token == x) {
118 	fprintf(stderr, "Error: two values for (state %d, token %d)\n", i, x);
119 	abort();
120       }
121     }
122 
123     if (j >= desc->size) {
124       n = desc->size * 2;
125       e = (edge_t *) realloc(e, n * sizeof(edge_t));
126       if (e == NULL) {
127 	fprintf(stderr, "Realloc failed; could not allocate descriptors\n");
128 	abort();
129       }
130       desc->edge = e;
131       desc->size = n;
132     }
133 
134     e[j].token = x;
135     e[j].val = v;
136     desc->nedges ++;
137   }
138 }
139 
140 
141 /*
142  * Read all the triples
143  */
set_descriptors(triple_t * l)144 static void set_descriptors(triple_t *l) {
145   while (((int) l->source) >= 0) {
146     //    printf("Adding triple %d %d %s\n", l->source, l->token, l->value);
147     if (l->source >= NSTATES) {
148       fprintf(stderr, "Error: triple state = %d, number of states = %d\n", l->source, NSTATES);
149       abort();
150     }
151     add_edge(l->source, l->token, l->value);
152     l ++;
153   }
154 }
155 
156 /*
157  * Print the descriptors
158  */
print_descriptors(void)159 static void print_descriptors(void) {
160   int i, j, n;
161   edge_t *e;
162 
163   for (i=0; i<NSTATES; i++) {
164     printf("state %d\n", i);
165     n = state[i].nedges;
166     e = state[i].edge;
167     for (j=0; j<n; j++) {
168       printf("  token %d: %s\n", e[j].token, e[j].val);
169     }
170     printf("  default: %s\n", state[i].def);
171   }
172 }
173 
174 
175 /*
176  * Tables to construct
177  */
178 static char * defval[NSTATES];
179 static int base[NSTATES];
180 static int val_size;
181 static int *check;
182 static char * *val;
183 
184 
185 /*
186  * Allocate tables check and val, with initial size = 2*NTOKENS
187  * Set all defaults in deval
188  */
init_tables(void)189 static void init_tables(void) {
190   int i, n;
191 
192   for (i=0; i<NSTATES; i++) {
193     defval[i] = state[i].def;
194   }
195 
196   n = 2*NTOKENS;
197   val_size = n;
198   check = (int *) malloc(n * sizeof(int));
199   val = (char * *) malloc(n * sizeof(char *));
200   if (check == NULL || val == NULL) {
201     fprintf(stderr, "Malloc failed: could not allocate check or val table\n");
202     abort();
203   }
204 
205   for (i=0; i<n; i++) {
206     check[i] = NSTATES;
207     val[i] = DEFAULT_VALUE;
208   }
209 }
210 
211 /*
212  * Extend the tables: make then twice as large
213  */
extend_tables(void)214 static void extend_tables(void) {
215   int i, n;
216 
217   n = 2 * val_size;
218   check = (int *) realloc(check, n * sizeof(int));
219   val = (char * *) realloc(val, n * sizeof(char *));
220   if (check == NULL || val == NULL) {
221     fprintf(stderr, "Realloc failed: could not extend check or val table\n");
222     abort();
223   }
224 
225   for (i=val_size; i<n; i++) {
226     check[i] = NSTATES;
227     val[i] = DEFAULT_VALUE;
228   }
229 
230   val_size = n;
231 }
232 
233 /*
234  * Check whether setting base[i] = b causes a conflict
235  */
base_possible(state_t i,int b)236 static bool base_possible(state_t i, int b) {
237   state_desc_t *desc;
238   edge_t *e;
239   int j, n, k;
240 
241   desc = state + i;
242   e = desc->edge;
243   n = desc->nedges;
244 
245   for (j=0; j<n; j++) {
246     k = b + e[j].token;
247     if (check[k] != NSTATES) {
248       return false;
249     }
250   }
251   return true;
252 }
253 
254 /*
255  * Store data for state i at base b
256  */
build_state_base(state_t i,int b)257 static void build_state_base(state_t i, int b) {
258   state_desc_t *desc;
259   edge_t *e;
260   int j, n, k;
261 
262   desc = state + i;
263   e = desc->edge;
264   n = desc->nedges;
265 
266   base[i] = b;
267 
268   for (j=0; j<n; j++) {
269     k = b + e[j].token;
270     check[k] = i;
271     val[k] = e[j].val;
272   }
273 }
274 
275 
276 /*
277  * Store data for state i
278  */
find_base(state_t i)279 static void find_base(state_t i) {
280   int b;
281 
282   b=0;
283   while (! base_possible(i, b)) {
284     b ++;
285     if (b + NTOKENS > val_size) {
286       extend_tables();
287     }
288   }
289   build_state_base(i, b);
290 }
291 
292 
293 /*
294  * Build the full tables
295  */
build_tables(void)296 static void build_tables(void) {
297   state_t i;
298 
299   init_tables();
300   for (i=0; i<NSTATES; i++) {
301     find_base(i);
302   }
303 }
304 
305 
306 /*
307  * Print the tables
308  */
print_tables(void)309 static void print_tables(void) {
310   int i, maxbase, size;
311 
312   maxbase = base[0];
313   for (i=1; i<NSTATES; i++) {
314     if (base[i] > maxbase) {
315       maxbase = base[i];
316     }
317   }
318   size = maxbase + NTOKENS;
319 
320   printf("/*\n"
321 	 " * Tables generated by table_builder\n"
322 	 " * see utils/table_builder.c\n"
323 	 " */\n\n");
324 
325   printf("// Table sizes\n");
326   printf("#define NSTATES %d\n", NSTATES);
327   printf("#define BSIZE %d\n\n", size);
328 
329   printf("// Default values for each state\n");
330   printf("static value_t default_value[NSTATES] = {\n");
331   for (i=0; i<NSTATES; i++) {
332     printf("  %s,\n", defval[i]);
333   }
334   printf("};\n\n");
335 
336   printf("// Base values for each state\n");
337   printf("static int base[NSTATES] = {");
338   for (i=0; i<NSTATES; i++) {
339     if (i % 10 == 0) printf("\n  ");
340     printf("%4d,", base[i]);
341   }
342   printf("\n};\n\n");
343 
344   printf("// Check table\n");
345   printf("static int check[BSIZE] = {");
346   for (i=0; i<size; i++) {
347     if (i % 10 == 0) printf("\n  ");
348     printf("%4d,", check[i]);
349   }
350   printf("\n};\n\n");
351 
352   printf("// Value table\n");
353   printf("static value_t value[BSIZE] = {\n");
354   for (i=0; i<size; i++) {
355     printf("  %s,\n", val[i]);
356   }
357   printf("};\n\n");
358 }
359 
360 
361 /*
362  * Check the tables
363  */
get_val(state_t i,token_t t)364 static char *get_val(state_t i, token_t t) {
365   int k;
366 
367   k = base[i] + t;
368   if (check[k] == i) {
369     return val[k];
370   } else {
371     return defval[i];
372   }
373 }
374 
get_desc_val(state_t i,token_t t)375 static char *get_desc_val(state_t i, token_t t) {
376   state_desc_t *desc;
377   edge_t *e;
378   int j, n;
379 
380   desc = state + i;
381   e = desc->edge;
382   n = desc->nedges;
383 
384   for (j=0; j<n; j++) {
385     if (e[j].token == t) return e[j].val;
386   }
387 
388   return desc->def;
389 }
390 
check_tables(void)391 static void check_tables(void) {
392   int i, j, n;
393   char *v1, *v2;
394 
395   n = 0;
396   for (i=0; i<NSTATES; i++) {
397     for (j=0; j<NTOKENS; j++) {
398       v1 = get_val(i, j);
399       v2 = get_desc_val(i, j);
400       if (v1 != v2) {
401 	n ++;
402 	fprintf(stderr, "Error in tables\n");
403 	fprintf(stderr, "  get_val(%d, %d) = %s\n", i, j, v1);
404 	fprintf(stderr, "  get_desc_val(%d, %d) = %s\n", i, j, v2);
405       }
406     }
407   }
408   if (n == 0) {
409     fprintf(stderr, "Tables appear correct\n");
410   }
411 }
412 
main(void)413 int main(void) {
414   init_state_descriptors();
415   set_descriptors(triples);
416   print_descriptors();
417 
418   build_tables();
419   print_tables();
420   check_tables();
421   return 0;
422 }
423