Initial commit to Gerrit
[profile/ivi/orc.git] / orc / orcparse.c
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include <orc/orc.h>
7 #include <orc/orcparse.h>
8
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 /**
14  * SECTION:orcparse
15  * @title: Parser
16  * @short_description: Parse Orc source code
17  */
18
19
20 typedef struct _OrcParser OrcParser;
21 struct _OrcParser {
22   const char *code;
23   int code_length;
24
25   const char *p;
26
27   int line_number;
28   char *line;
29   int creg_index;
30
31   OrcOpcodeSet *opcode_set;
32   OrcProgram *program;
33   OrcProgram *error_program;
34
35   OrcProgram **programs;
36   int n_programs;
37   int n_programs_alloc;
38
39   char *log;
40   int log_size;
41   int log_alloc;
42 };
43
44 static void orc_parse_get_line (OrcParser *parser);
45 static OrcStaticOpcode * get_opcode (OrcParser *parser, const char *opcode);
46 static void orc_parse_log (OrcParser *parser, const char *format, ...);
47 static int opcode_n_args (OrcStaticOpcode *opcode);
48 static void orc_parse_sanity_check (OrcParser *parser, OrcProgram *program);
49
50
51 int
52 orc_parse (const char *code, OrcProgram ***programs)
53 {
54   return orc_parse_full (code, programs, NULL);
55 }
56
57 int
58 orc_parse_full (const char *code, OrcProgram ***programs, char **log)
59 {
60   OrcParser _parser;
61   OrcParser *parser = &_parser;
62   char *init_function = NULL;
63
64   memset (parser, 0, sizeof(*parser));
65
66   parser->code = code;
67   parser->code_length = strlen (code);
68   parser->line_number = 0;
69   parser->p = code;
70   parser->opcode_set = orc_opcode_set_get ("sys");
71   parser->log = malloc(100);
72   parser->log_alloc = 100;
73   parser->log_size = 0;
74
75   while (parser->p[0] != 0) {
76     char *p;
77     char *end;
78     char *token[10];
79     int n_tokens;
80
81     orc_parse_get_line (parser);
82
83     p = parser->line;
84     end = p + strlen (p);
85     //printf("%d: %s\n", parser->line_number, parser->line);
86
87     while (p[0] == ' ' || p[0] == '\t') p++;
88
89     if (p[0] == 0) {
90       continue;
91     }
92
93     if (p[0] == '#') {
94       //printf("comment: %s\n", p+1);
95       continue;
96     }
97
98     n_tokens = 0;
99
100     while (p < end) {
101       if (p[0] == ' ' || p[0] == '\t' || p[0] == ',') p++;
102       if (p[0] == 0 || p[0] == '#') break;
103
104       token[n_tokens] = p;
105       while (p[0] != 0 && p[0] != ' ' && p[0] != '\t' && p[0] != ',') p++;
106       n_tokens++;
107
108       p[0] = 0;
109       p++;
110     }
111
112     if (n_tokens == 0) {
113       continue;
114     }
115
116     {
117       int i;
118       for(i=0;i<n_tokens;i++){
119         //printf("'%s' ", token[i]);
120       }
121       //printf("\n");
122     }
123
124     if (token[0][0] == '.') {
125       if (strcmp (token[0], ".function") == 0) {
126         if (parser->program) {
127           orc_parse_sanity_check (parser, parser->program);
128         }
129         parser->program = orc_program_new ();
130         orc_program_set_name (parser->program, token[1]);
131         if (parser->n_programs == parser->n_programs_alloc) {
132           parser->n_programs_alloc += 32;
133           parser->programs = realloc (parser->programs,
134               sizeof(OrcProgram *)*parser->n_programs_alloc);
135         }
136         parser->programs[parser->n_programs] = parser->program;
137         parser->n_programs++;
138         parser->creg_index = 1;
139       } else if (strcmp (token[0], ".init") == 0) {
140         if (init_function) free (init_function);
141         if (n_tokens < 2) {
142           orc_parse_log (parser, "error: line %d: .init without function name\n",
143               parser->line_number);
144         } else {
145           init_function = strdup (token[1]);
146         }
147       } else if (strcmp (token[0], ".flags") == 0) {
148         int i;
149         for(i=1;i<n_tokens;i++){
150           if (!strcmp (token[i], "2d")) {
151             orc_program_set_2d (parser->program);
152           }
153         }
154       } else if (strcmp (token[0], ".n") == 0) {
155         int size = strtol (token[1], NULL, 0);
156         orc_program_set_constant_n (parser->program, size);
157       } else if (strcmp (token[0], ".m") == 0) {
158         int size = strtol (token[1], NULL, 0);
159         orc_program_set_constant_m (parser->program, size);
160       } else if (strcmp (token[0], ".source") == 0) {
161         int size = strtol (token[1], NULL, 0);
162         int var;
163         var = orc_program_add_source (parser->program, size, token[2]);
164         if (n_tokens > 3) {
165           orc_program_set_type_name (parser->program, var, token[3]);
166         }
167       } else if (strcmp (token[0], ".dest") == 0) {
168         int size = strtol (token[1], NULL, 0);
169         int var;
170         var = orc_program_add_destination (parser->program, size, token[2]);
171         if (n_tokens > 3) {
172           orc_program_set_type_name (parser->program, var, token[3]);
173         }
174       } else if (strcmp (token[0], ".accumulator") == 0) {
175         int size = strtol (token[1], NULL, 0);
176         int var;
177         var = orc_program_add_accumulator (parser->program, size, token[2]);
178         if (n_tokens > 3) {
179           orc_program_set_type_name (parser->program, var, token[3]);
180         }
181       } else if (strcmp (token[0], ".temp") == 0) {
182         int size = strtol (token[1], NULL, 0);
183         orc_program_add_temporary (parser->program, size, token[2]);
184       } else if (strcmp (token[0], ".param") == 0) {
185         int size = strtol (token[1], NULL, 0);
186         orc_program_add_parameter (parser->program, size, token[2]);
187       } else if (strcmp (token[0], ".longparam") == 0) {
188         int size = strtol (token[1], NULL, 0);
189         orc_program_add_parameter_int64 (parser->program, size, token[2]);
190       } else if (strcmp (token[0], ".const") == 0) {
191         int size = strtol (token[1], NULL, 0);
192
193         orc_program_add_constant_str (parser->program, size, token[3], token[2]);
194       } else if (strcmp (token[0], ".floatparam") == 0) {
195         int size = strtol (token[1], NULL, 0);
196         orc_program_add_parameter_float (parser->program, size, token[2]);
197       } else if (strcmp (token[0], ".doubleparam") == 0) {
198         int size = strtol (token[1], NULL, 0);
199         orc_program_add_parameter_double (parser->program, size, token[2]);
200       } else {
201         orc_parse_log (parser, "error: line %d: unknown directive: %s\n",
202             parser->line_number, token[0]);
203       }
204     } else {
205       OrcStaticOpcode *o;
206       unsigned int flags = 0;
207       int offset = 0;
208
209       if (strcmp (token[0], "x4") == 0) {
210         flags |= ORC_INSTRUCTION_FLAG_X4;
211         offset = 1;
212       } else if (strcmp (token[0], "x2") == 0) {
213         flags |= ORC_INSTRUCTION_FLAG_X2;
214         offset = 1;
215       }
216
217       o = get_opcode (parser, token[offset]);
218
219       if (o) {
220         int n_args = opcode_n_args (o);
221         int i;
222
223         if (n_tokens != 1 + offset + n_args) {
224           orc_parse_log (parser, "error: line %d: too %s arguments for %s (expected %d)\n",
225               parser->line_number, (n_tokens < 1+offset+n_args) ? "few" : "many",
226               token[offset], n_args);
227         }
228
229         for(i=offset+1;i<n_tokens;i++){
230           char *end;
231           double d;
232           d = strtod (token[i], &end);
233           if (end != token[i]) {
234             orc_program_add_constant_str (parser->program, 0, token[i],
235                 token[i]);
236           }
237         }
238
239         if (n_tokens - offset == 5) {
240           orc_program_append_str_2 (parser->program, token[offset], flags,
241               token[offset+1], token[offset+2], token[offset+3], token[offset+4]);
242         } else if (n_tokens - offset == 4) {
243           orc_program_append_str_2 (parser->program, token[offset], flags,
244               token[offset+1], token[offset+2], token[offset+3], NULL);
245         } else {
246           orc_program_append_str_2 (parser->program, token[offset], flags,
247               token[offset+1], token[offset+2], NULL, NULL);
248         }
249       } else {
250         orc_parse_log (parser, "error: line %d: unknown opcode: %s\n",
251             parser->line_number,
252             token[offset]);
253       }
254     }
255   }
256
257   if (parser->program) {
258     orc_parse_sanity_check (parser, parser->program);
259   }
260
261   if (parser->line) free (parser->line);
262
263   if (log) {
264     *log = parser->log;
265   } else {
266     free (parser->log);
267   }
268   if (parser->programs[0]) {
269     parser->programs[0]->init_function = init_function;
270   }
271   *programs = parser->programs;
272   return parser->n_programs;
273 }
274
275 static OrcStaticOpcode *
276 get_opcode (OrcParser *parser, const char *opcode)
277 {
278   int i;
279
280   for(i=0;i<parser->opcode_set->n_opcodes;i++){
281     if (strcmp (opcode, parser->opcode_set->opcodes[i].name) == 0) {
282       return parser->opcode_set->opcodes + i;
283     }
284   }
285
286   return NULL;
287 }
288
289 static int
290 opcode_n_args (OrcStaticOpcode *opcode)
291 {
292   int i;
293   int n = 0;
294   for(i=0;i<ORC_STATIC_OPCODE_N_DEST;i++){
295     if (opcode->dest_size[i] != 0) n++;
296   }
297   for(i=0;i<ORC_STATIC_OPCODE_N_SRC;i++){
298     if (opcode->src_size[i] != 0) n++;
299   }
300   return n;
301 }
302
303 static void
304 orc_parse_log_valist (OrcParser *parser, const char *format, va_list args)
305 {
306   char s[100];
307   int len;
308   
309   if (parser->error_program != parser->program) {
310     sprintf(s, "In function %s:\n", parser->program->name);
311     len = strlen(s);
312
313     if (parser->log_size + len + 1 >= parser->log_alloc) {
314       parser->log_alloc += 100;
315       parser->log = realloc (parser->log, parser->log_alloc);
316     }
317
318     strcpy (parser->log + parser->log_size, s);
319     parser->log_size += len;
320     parser->error_program = parser->program;
321   }
322
323   vsprintf(s, format, args);
324   len = strlen(s);
325
326   if (parser->log_size + len + 1 >= parser->log_alloc) {
327     parser->log_alloc += 100;
328     parser->log = realloc (parser->log, parser->log_alloc);
329   }
330
331   strcpy (parser->log + parser->log_size, s);
332   parser->log_size += len;
333 }
334
335 static void
336 orc_parse_log (OrcParser *parser, const char *format, ...)
337 {
338   va_list var_args;
339
340   va_start (var_args, format);
341   orc_parse_log_valist (parser, format, var_args);
342   va_end (var_args);
343 }
344
345 static void
346 orc_parse_get_line (OrcParser *parser)
347 {
348   const char *end;
349   int n;
350
351   if (parser->line) {
352     free (parser->line);
353     parser->line = NULL;
354   }
355
356   end = strchr (parser->p, '\n');
357   if (end == NULL) {
358     end = parser->code + parser->code_length;
359   }
360
361   n = end - parser->p;
362   parser->line = malloc (n + 1);
363   memcpy (parser->line, parser->p, n);
364   parser->line[n] = 0;
365
366   parser->p = end;
367   if (parser->p[0] == '\n') {
368     parser->p++;
369   }
370   parser->line_number++;
371 }
372
373
374 static void
375 orc_parse_sanity_check (OrcParser *parser, OrcProgram *program)
376 {
377   int i;
378   int j;
379
380   for(i=0;i<=ORC_VAR_T15;i++) {
381     if (program->vars[i].size == 0) continue;
382     for(j=i+1;j<=ORC_VAR_T15;j++) {
383       if (program->vars[j].size == 0) continue;
384
385       if (strcmp (program->vars[i].name, program->vars[j].name) == 0) {
386         orc_parse_log (parser, "error: duplicate variable name: %s\n",
387             program->vars[i].name);
388       }
389     }
390   }
391
392   for(i=0;i<program->n_insns;i++){
393     OrcInstruction *insn = program->insns + i;
394     OrcStaticOpcode *opcode = insn->opcode;
395
396     for(j=0;j<ORC_STATIC_OPCODE_N_DEST;j++){
397       if (opcode->dest_size[j] == 0) continue;
398       if (program->vars[insn->dest_args[j]].used &&
399           program->vars[insn->dest_args[j]].vartype == ORC_VAR_TYPE_DEST) {
400         orc_parse_log (parser, "error: destination \"%s\" written multiple times\n",
401             program->vars[insn->dest_args[j]].name);
402       }
403       program->vars[insn->dest_args[j]].used = TRUE;
404     }
405
406     for(j=0;j<ORC_STATIC_OPCODE_N_SRC;j++){
407       if (opcode->src_size[j] == 0) continue;
408       if (program->vars[insn->src_args[j]].used &&
409           program->vars[insn->src_args[j]].vartype == ORC_VAR_TYPE_SRC) {
410         orc_parse_log (parser, "error: source \"%s\" read multiple times\n",
411             program->vars[insn->src_args[j]].name);
412       }
413       if (!program->vars[insn->src_args[j]].used &&
414           program->vars[insn->src_args[j]].vartype == ORC_VAR_TYPE_TEMP) {
415         orc_parse_log (parser, "error: variable \"%s\" used before being written\n",
416             program->vars[insn->src_args[j]].name);
417       }
418     }
419
420   }
421
422 }
423
424 const char *
425 orc_parse_get_init_function (OrcProgram *program)
426 {
427   return program->init_function;
428 }
429