summaryrefslogtreecommitdiff
path: root/utils/imxtools/dbparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/imxtools/dbparser.c')
-rw-r--r--utils/imxtools/dbparser.c849
1 files changed, 849 insertions, 0 deletions
diff --git a/utils/imxtools/dbparser.c b/utils/imxtools/dbparser.c
new file mode 100644
index 0000000000..b2027e5ad7
--- /dev/null
+++ b/utils/imxtools/dbparser.c
@@ -0,0 +1,849 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define _POSIX_C_SOURCE 200809L /* for strdup */
23#include <stdio.h>
24#include <ctype.h>
25#include <stdint.h>
26#include <string.h>
27#include "dbparser.h"
28#include "misc.h"
29
30enum lexem_type_t
31{
32 LEX_IDENTIFIER,
33 LEX_LPAREN,
34 LEX_RPAREN,
35 LEX_NUMBER,
36 LEX_STRING, /* double-quoted string */
37 LEX_EQUAL,
38 LEX_SEMICOLON,
39 LEX_LBRACE,
40 LEX_RBRACE,
41 LEX_RANGLE,
42 LEX_OR,
43 LEX_LSHIFT,
44 LEX_COLON,
45 LEX_LE,
46 LEX_EOF
47};
48
49struct lexem_t
50{
51 enum lexem_type_t type;
52 /* if str is not NULL, it must be a malloc'd pointer */
53 char *str;
54 uint32_t num;
55 int line;
56 const char *file;
57};
58
59struct context_t
60{
61 const char *file;
62 char *begin;
63 char *end;
64 char *ptr;
65 int line;
66};
67
68#define parse_error(ctx, ...) \
69 do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \
70 fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
71
72static void advance(struct context_t *ctx, int nr_chars)
73{
74 while(nr_chars--)
75 {
76 if(*(ctx->ptr++) == '\n')
77 ctx->line++;
78 }
79}
80
81static inline bool eof(struct context_t *ctx)
82{
83 return ctx->ptr == ctx->end;
84}
85
86static inline bool next_valid(struct context_t *ctx, int nr)
87{
88 return ctx->ptr + nr < ctx->end;
89}
90
91static inline char cur_char(struct context_t *ctx)
92{
93 return *ctx->ptr;
94}
95
96static inline char next_char(struct context_t *ctx, int nr)
97{
98 return ctx->ptr[nr];
99}
100
101static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx)
102{
103 lex->file = ctx->file;
104 lex->line = ctx->line;
105}
106
107static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c))
108{
109 while(!eof(ctx))
110 {
111 if(cur_char(ctx) == '"')
112 break;
113 else if(cur_char(ctx) == '\\')
114 {
115 advance(ctx, 1);
116 if(eof(ctx))
117 parse_error(ctx, "Unfinished string\n");
118 if(cur_char(ctx) == '\\') emit_fn(user, '\\');
119 else if(cur_char(ctx) == '\'') emit_fn(user, '\'');
120 else if(cur_char(ctx) == '\"') emit_fn(user, '\"');
121 else parse_error(ctx, "Unknown escape sequence \\%c\n", cur_char(ctx));
122 advance(ctx, 1);
123 }
124 else
125 {
126 emit_fn(user, cur_char(ctx));
127 advance(ctx, 1);
128 }
129 }
130 if(eof(ctx) || cur_char(ctx) != '"')
131 parse_error(ctx, "Unfinished string\n");
132 advance(ctx, 1);
133}
134
135static void __parse_string_emit(void *user, char c)
136{
137 char **pstr = (char **)user;
138 *(*pstr)++ = c;
139}
140
141static void __parse_string_count(void *user, char c)
142{
143 (void) c;
144 (*(int *)user)++;
145}
146
147static void parse_string(struct context_t *ctx, struct lexem_t *lexem)
148{
149 locate_lexem(lexem, ctx);
150 /* skip " */
151 advance(ctx, 1);
152 /* compute length */
153 struct context_t cpy_ctx = *ctx;
154 int length = 0;
155 __parse_string(&cpy_ctx, (void *)&length, __parse_string_count);
156 /* parse again */
157 lexem->type = LEX_STRING;
158 lexem->str = xmalloc(length + 1);
159 lexem->str[length] = 0;
160 char *pstr = lexem->str;
161 __parse_string(ctx, (void *)&pstr, __parse_string_emit);
162}
163
164static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem)
165{
166 locate_lexem(lexem, ctx);
167 /* skip ' */
168 advance(ctx, 1);
169 /* we expect n<=4 character and then ' */
170 int len = 0;
171 uint32_t value = 0;
172 while(!eof(ctx))
173 {
174 if(cur_char(ctx) != '\'')
175 {
176 value = value << 8 | cur_char(ctx);
177 len++;
178 advance(ctx, 1);
179 }
180 else
181 break;
182 }
183 if(eof(ctx) || cur_char(ctx) != '\'')
184 parse_error(ctx, "Unterminated ascii number literal\n");
185 if(len == 0 || len > 4)
186 parse_error(ctx, "Invalid ascii number literal length: only 1 to 4 characters allowed\n");
187 /* skip ' */
188 advance(ctx, 1);
189 lexem->type = LEX_NUMBER;
190 lexem->num = value;
191}
192
193static void parse_number(struct context_t *ctx, struct lexem_t *lexem)
194{
195 locate_lexem(lexem, ctx);
196 /* check base */
197 int base = 10;
198 if(cur_char(ctx) == '0' && next_valid(ctx, 1) && next_char(ctx, 1) == 'x')
199 {
200 advance(ctx, 2);
201 base = 16;
202 }
203
204 lexem->type = LEX_NUMBER;
205 lexem->num = 0;
206 while(!eof(ctx) && isxdigit(cur_char(ctx)))
207 {
208 if(base == 10 && !isdigit(cur_char(ctx)))
209 break;
210 byte v;
211 if(convxdigit(cur_char(ctx), &v))
212 break;
213 lexem->num = base * lexem->num + v;
214 advance(ctx, 1);
215 }
216}
217
218static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem)
219{
220 locate_lexem(lexem, ctx);
221 /* remember position */
222 char *old = ctx->ptr;
223 while(!eof(ctx) && (isalnum(cur_char(ctx)) || cur_char(ctx) == '_'))
224 advance(ctx, 1);
225 lexem->type = LEX_IDENTIFIER;
226 int len = ctx->ptr - old;
227 lexem->str = xmalloc(len + 1);
228 lexem->str[len] = 0;
229 memcpy(lexem->str, old, len);
230}
231
232static void next_lexem(struct context_t *ctx, struct lexem_t *lexem)
233{
234 #define ret_simple(t, adv) \
235 do {locate_lexem(lexem, ctx); \
236 lexem->type = t; \
237 advance(ctx, adv); \
238 return;} while(0)
239 while(!eof(ctx))
240 {
241 char c = cur_char(ctx);
242 /* skip whitespace */
243 if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
244 {
245 advance(ctx, 1);
246 continue;
247 }
248 /* skip C++ style comments */
249 if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/')
250 {
251 while(!eof(ctx) && cur_char(ctx) != '\n')
252 advance(ctx, 1);
253 continue;
254 }
255 /* skip C-style comments */
256 if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*')
257 {
258 advance(ctx, 2);
259 while(true)
260 {
261 if(!next_valid(ctx, 1))
262 parse_error(ctx, "Unterminated comment");
263 if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/')
264 {
265 advance(ctx, 2);
266 break;
267 }
268 advance(ctx, 1);
269 }
270 continue;
271 }
272 break;
273 }
274 if(eof(ctx)) ret_simple(LEX_EOF, 0);
275 char c = cur_char(ctx);
276 bool nv = next_valid(ctx, 1);
277 char nc = nv ? next_char(ctx, 1) : 0;
278 if(c == '(') ret_simple(LEX_LPAREN, 1);
279 if(c == ')') ret_simple(LEX_RPAREN, 1);
280 if(c == '{') ret_simple(LEX_LBRACE, 1);
281 if(c == '}') ret_simple(LEX_RBRACE, 1);
282 if(c == '>') ret_simple(LEX_RANGLE, 1);
283 if(c == '=') ret_simple(LEX_EQUAL, 1);
284 if(c == ';') ret_simple(LEX_SEMICOLON, 1);
285 if(c == ',') ret_simple(LEX_COLON, 1);
286 if(c == '|') ret_simple(LEX_OR, 1);
287 if(c == '<' && nv && nc == '<') ret_simple(LEX_LSHIFT, 2);
288 if(c == '<' && nv && nc == '=') ret_simple(LEX_LE, 2);
289 if(c == '"') return parse_string(ctx, lexem);
290 if(c == '\'') return parse_ascii_number(ctx, lexem);
291 if(isdigit(c)) return parse_number(ctx, lexem);
292 if(isalpha(c) || c == '_') return parse_identifier(ctx, lexem);
293 parse_error(ctx, "Unexpected character '%c'\n", c);
294 #undef ret_simple
295}
296
297#if 0
298static void log_lexem(struct lexem_t *lexem)
299{
300 switch(lexem->type)
301 {
302 case LEX_EOF: printf("<eof>"); break;
303 case LEX_EQUAL: printf("="); break;
304 case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break;
305 case LEX_LPAREN: printf("("); break;
306 case LEX_RPAREN: printf(")"); break;
307 case LEX_LBRACE: printf("{"); break;
308 case LEX_RBRACE: printf("}"); break;
309 case LEX_SEMICOLON: printf(";"); break;
310 case LEX_NUMBER: printf("num(%d)", lexem->num); break;
311 case LEX_STRING: printf("str(%s)", lexem->str); break;
312 case LEX_OR: printf("|"); break;
313 case LEX_LSHIFT: printf("<<"); break;
314 default: printf("<unk>");
315 }
316}
317#endif
318
319struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id)
320{
321 struct cmd_source_t *src = cmd_file->source_list;
322 while(src)
323 {
324 if(strcmp(src->identifier, id) == 0)
325 return src;
326 src = src->next;
327 }
328 return NULL;
329}
330
331struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name)
332{
333 while(opt)
334 {
335 if(strcmp(opt->name, name) == 0)
336 return opt;
337 opt = opt->next;
338 }
339 return NULL;
340}
341
342#define INVALID_SB_SUBVERSION 0xffff
343
344static uint16_t parse_sb_subversion(char *str)
345{
346 int len = strlen(str);
347 uint16_t n = 0;
348 if(len == 0 || len > 4)
349 return INVALID_SB_SUBVERSION;
350 for(int i = 0; i < len; i++)
351 {
352 if(!isdigit(str[i]))
353 return INVALID_SB_SUBVERSION;
354 n = n << 4 | (str[i] - '0');
355 }
356 return n;
357}
358
359bool db_parse_sb_version(struct sb_version_t *ver, char *str)
360{
361 int len = strlen(str);
362 int cnt = 0;
363 int pos[2];
364
365 for(int i = 0; i < len; i++)
366 {
367 if(str[i] != '.')
368 continue;
369 if(cnt == 2)
370 return false;
371 pos[cnt++] = i + 1;
372 str[i] = 0;
373 }
374 if(cnt != 2)
375 return false;
376 ver->major = parse_sb_subversion(str);
377 ver->minor = parse_sb_subversion(str + pos[0]);
378 ver->revision = parse_sb_subversion(str + pos[1]);
379 return ver->major != INVALID_SB_SUBVERSION &&
380 ver->minor != INVALID_SB_SUBVERSION &&
381 ver->revision != INVALID_SB_SUBVERSION;
382}
383
384#undef parse_error
385#define parse_error(lexem, ...) \
386 do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \
387 fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
388
389struct lex_ctx_t
390{
391 struct context_t ctx;
392 struct lexem_t lexem;
393};
394
395/* When lexems hold strings (like identifier), it might be useful to steal
396 * the pointer and don't clean the lexem but in other case, one don't want
397 * to keep the pointer to the string and just want to release the memory.
398 * Thus clean_lexem should be true except when one keeps a pointer */
399static inline void next(struct lex_ctx_t *ctx, bool clean_lexem)
400{
401 if(clean_lexem)
402 free(ctx->lexem.str);
403 memset(&ctx->lexem, 0, sizeof(struct lexem_t));
404 next_lexem(&ctx->ctx, &ctx->lexem);
405}
406
407static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
408{
409 uint32_t ret = 0;
410 if(ctx->lexem.type == LEX_NUMBER)
411 ret = ctx->lexem.num;
412 else if(ctx->lexem.type == LEX_IDENTIFIER)
413 {
414 struct cmd_option_t *c = db_find_option_by_id(const_list, ctx->lexem.str);
415 if(c == NULL)
416 parse_error(ctx->lexem, "Undefined reference to constant '%s'\n", ctx->lexem.str);
417 if(c->is_string)
418 parse_error(ctx->lexem, "Internal error: constant '%s' is not an integer\n", ctx->lexem.str);
419 ret = c->val;
420 }
421 else
422 parse_error(ctx->lexem, "Number or constant identifier expected\n");
423 next(ctx, true);
424 return ret;
425}
426
427static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
428{
429 uint32_t v = parse_term_expr(ctx, const_list);
430 while(ctx->lexem.type == LEX_LSHIFT)
431 {
432 next(ctx, true);
433 v <<= parse_term_expr(ctx, const_list);
434 }
435 return v;
436}
437
438static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
439{
440 uint32_t v = parse_shift_expr(ctx, const_list);
441 while(ctx->lexem.type == LEX_OR)
442 {
443 next(ctx, true);
444 v |= parse_shift_expr(ctx, const_list);
445 }
446 return v;
447}
448
449static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
450{
451 return parse_or_expr(ctx, const_list);
452}
453
454#define NR_INITIAL_CONSTANTS 4
455static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"};
456static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0};
457
458struct cmd_file_t *db_parse_file(const char *file)
459{
460 size_t size;
461 FILE *f = fopen(file, "r");
462 if(f == NULL)
463 bugp("Cannot open file '%s'", file);
464 fseek(f, 0, SEEK_END);
465 size = ftell(f);
466 fseek(f, 0, SEEK_SET);
467 char *buf = xmalloc(size);
468 if(fread(buf, size, 1, f) != 1)
469 bugp("Cannot read file '%s'", file);
470 fclose(f);
471
472 if(g_debug)
473 printf("Parsing db file '%s'\n", file);
474 struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t));
475 memset(cmd_file, 0, sizeof(struct cmd_file_t));
476
477 /* add initial constants */
478 for(int i = 0; i < NR_INITIAL_CONSTANTS; i++)
479 {
480 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
481 memset(opt, 0, sizeof(struct cmd_option_t));
482 opt->name = strdup(init_const_name[i]);
483 opt->is_string = false;
484 opt->val = init_const_value[i];
485 opt->next = cmd_file->constant_list;
486 cmd_file->constant_list = opt;
487 }
488
489 struct lex_ctx_t lctx;
490 lctx.ctx.file = file;
491 lctx.ctx.line = 1;
492 lctx.ctx.begin = buf;
493 lctx.ctx.ptr = buf;
494 lctx.ctx.end = buf + size;
495 #define next(clean_lexem) next(&lctx, clean_lexem)
496 #define lexem lctx.lexem
497 /* init lexer */
498 next(false); /* don't clean init lexem because it doesn't exist */
499 /* constants ? */
500 if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
501 {
502 next(true);
503 if(lexem.type != LEX_LBRACE)
504 parse_error(lexem, "'{' expected after 'constants'\n");
505
506 while(true)
507 {
508 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
509 memset(opt, 0, sizeof(struct cmd_option_t));
510 next(true);
511 if(lexem.type == LEX_RBRACE)
512 break;
513 if(lexem.type != LEX_IDENTIFIER)
514 parse_error(lexem, "Identifier expected in constants\n");
515 opt->name = lexem.str;
516 next(false); /* lexem string is kept as option name */
517 if(lexem.type != LEX_EQUAL)
518 parse_error(lexem, "'=' expected after identifier\n");
519 next(true);
520 opt->is_string = false;
521 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
522 opt->next = cmd_file->constant_list;
523 cmd_file->constant_list = opt;
524 if(lexem.type != LEX_SEMICOLON)
525 parse_error(lexem, "';' expected after string\n");
526 }
527 next(true);
528 }
529 /* options ? */
530 if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
531 {
532 next(true);
533 if(lexem.type != LEX_LBRACE)
534 parse_error(lexem, "'{' expected after 'options'\n");
535
536 while(true)
537 {
538 next(true);
539 if(lexem.type == LEX_RBRACE)
540 break;
541 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
542 memset(opt, 0, sizeof(struct cmd_option_t));
543 if(lexem.type != LEX_IDENTIFIER)
544 parse_error(lexem, "Identifier expected in options\n");
545 opt->name = lexem.str;
546 next(false); /* lexem string is kept as option name */
547 if(lexem.type != LEX_EQUAL)
548 parse_error(lexem, "'=' expected after identifier\n");
549 next(true);
550 if(lexem.type == LEX_STRING)
551 {
552 opt->is_string = true;
553 opt->str = lexem.str;
554 next(false); /* lexem string is kept as option name */
555 }
556 else
557 {
558 opt->is_string = false;
559 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
560 }
561 opt->next = cmd_file->opt_list;
562 cmd_file->opt_list = opt;
563 if(lexem.type != LEX_SEMICOLON)
564 parse_error(lexem, "';' expected after string\n");
565 }
566 next(true);
567 }
568 /* sources */
569 if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
570 parse_error(lexem, "'sources' expected\n");
571 next(true);
572 if(lexem.type != LEX_LBRACE)
573 parse_error(lexem, "'{' expected after 'sources'\n");
574
575 while(true)
576 {
577 next(true);
578 if(lexem.type == LEX_RBRACE)
579 break;
580 struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
581 memset(src, 0, sizeof(struct cmd_source_t));
582 if(lexem.type != LEX_IDENTIFIER)
583 parse_error(lexem, "identifier expected in sources\n");
584 src->identifier = lexem.str;
585 next(false); /* lexem string is kept as source name */
586 if(lexem.type != LEX_EQUAL)
587 parse_error(lexem, "'=' expected after identifier\n");
588 next(true);
589 if(lexem.type == LEX_STRING)
590 {
591 src->is_extern = false;
592 src->filename = lexem.str;
593 next(false); /* lexem string is kept as file name */
594 }
595 else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
596 {
597 src->is_extern = true;
598 src->filename = strdup("<extern>"); /* duplicate because it will be free'd */
599 next(true);
600 if(lexem.type != LEX_LPAREN)
601 parse_error(lexem, "'(' expected after 'extern'\n");
602 next(true);
603 src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
604 if(lexem.type != LEX_RPAREN)
605 parse_error(lexem, "')' expected\n");
606 next(true);
607 }
608 else
609 parse_error(lexem, "String or 'extern' expected after '='\n");
610 if(lexem.type != LEX_SEMICOLON)
611 parse_error(lexem, "';' expected\n");
612 if(db_find_source_by_id(cmd_file, src->identifier) != NULL)
613 parse_error(lexem, "Duplicate source identifier\n");
614 /* type filled later */
615 src->type = CMD_SRC_UNK;
616 src->next = cmd_file->source_list;
617 cmd_file->source_list = src;
618 }
619
620 /* sections */
621 struct cmd_section_t *end_sec = NULL;
622 while(true)
623 {
624 next(true);
625 if(lexem.type == LEX_EOF)
626 break;
627 struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
628 struct cmd_inst_t *end_list = NULL;
629 memset(sec, 0, sizeof(struct cmd_section_t));
630 if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
631 parse_error(lexem, "'section' expected\n");
632 next(true);
633 if(lexem.type != LEX_LPAREN)
634 parse_error(lexem, "'(' expected after 'section'\n");
635 next(true);
636 /* can be any number */
637 sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
638 /* options ? */
639 if(lexem.type == LEX_SEMICOLON)
640 {
641 do
642 {
643 next(true);
644 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
645 memset(opt, 0, sizeof(struct cmd_option_t));
646 if(lexem.type != LEX_IDENTIFIER)
647 parse_error(lexem, "Identifier expected for section option\n");
648 opt->name = lexem.str;
649 next(false); /* lexem string is kept as option name */
650 if(lexem.type != LEX_EQUAL)
651 parse_error(lexem, "'=' expected after option identifier\n");
652 next(true);
653 if(lexem.type == LEX_STRING)
654 {
655 opt->is_string = true;
656 opt->str = lexem.str;
657 next(false); /* lexem string is kept as option string */
658 }
659 else
660 {
661 opt->is_string = false;
662 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
663 }
664 opt->next = sec->opt_list;
665 sec->opt_list = opt;
666 }while(lexem.type == LEX_COLON);
667 }
668 if(lexem.type != LEX_RPAREN)
669 parse_error(lexem, "')' expected after section identifier\n");
670 next(true);
671 if(lexem.type == LEX_LBRACE)
672 {
673 sec->is_data = false;
674 /* commands */
675 while(true)
676 {
677 next(true);
678 if(lexem.type == LEX_RBRACE)
679 break;
680 struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
681 memset(inst, 0, sizeof(struct cmd_inst_t));
682 if(lexem.type != LEX_IDENTIFIER)
683 parse_error(lexem, "Instruction expected in section\n");
684 if(strcmp(lexem.str, "load") == 0)
685 inst->type = CMD_LOAD;
686 else if(strcmp(lexem.str, "call") == 0)
687 inst->type = CMD_CALL;
688 else if(strcmp(lexem.str, "jump") == 0)
689 inst->type = CMD_JUMP;
690 else if(strcmp(lexem.str, "mode") == 0)
691 inst->type = CMD_MODE;
692 else
693 parse_error(lexem, "Instruction expected in section\n");
694 next(true);
695
696 if(inst->type == CMD_LOAD)
697 {
698 if(lexem.type != LEX_IDENTIFIER)
699 parse_error(lexem, "Identifier expected after instruction\n");
700 inst->identifier = lexem.str;
701 if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
702 parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
703 next(false); /* lexem string kept as identifier */
704 if(lexem.type == LEX_RANGLE)
705 {
706 // load at
707 inst->type = CMD_LOAD_AT;
708 next(true);
709 inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
710 }
711 if(lexem.type != LEX_SEMICOLON)
712 parse_error(lexem, "';' expected after command\n");
713 }
714 else if(inst->type == CMD_CALL || inst->type == CMD_JUMP)
715 {
716 if(lexem.type == LEX_IDENTIFIER)
717 {
718 inst->identifier = lexem.str;
719 if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
720 parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
721 next(false); /* lexem string kept as identifier */
722 }
723 else
724 {
725 inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT;
726 inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
727 }
728
729 if(lexem.type == LEX_LPAREN)
730 {
731 next(true);
732 inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
733 if(lexem.type != LEX_RPAREN)
734 parse_error(lexem, "Expected closing brace\n");
735 next(true);
736 }
737 if(lexem.type != LEX_SEMICOLON)
738 parse_error(lexem, "';' expected after command\n");
739 }
740 else if(inst->type == CMD_MODE)
741 {
742 inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
743 if(lexem.type != LEX_SEMICOLON)
744 parse_error(lexem, "Expected ';' after command\n");
745 }
746 else
747 parse_error(lexem, "Internal error");
748 if(end_list == NULL)
749 {
750 sec->inst_list = inst;
751 end_list = inst;
752 }
753 else
754 {
755 end_list->next = inst;
756 end_list = inst;
757 }
758 }
759 }
760 else if(lexem.type == LEX_LE)
761 {
762 sec->is_data = true;
763 next(true);
764 if(lexem.type != LEX_IDENTIFIER)
765 parse_error(lexem, "Identifier expected after '<='\n");
766 sec->source_id = lexem.str;
767 next(false); /* lexem string is kept as source id */
768 if(lexem.type != LEX_SEMICOLON)
769 parse_error(lexem, "';' expected after identifier\n");
770 }
771 else
772 parse_error(lexem, "'{' or '<=' expected after section directive\n");
773
774 if(end_sec == NULL)
775 {
776 cmd_file->section_list = sec;
777 end_sec = sec;
778 }
779 else
780 {
781 end_sec->next = sec;
782 end_sec = sec;
783 }
784 }
785 #undef lexem
786 #undef next
787
788 free(buf);
789 return cmd_file;
790}
791
792void db_generate_default_sb_version(struct sb_version_t *ver)
793{
794 ver->major = ver->minor = ver->revision = 0x999;
795}
796
797void db_free_option_list(struct cmd_option_t *opt_list)
798{
799 while(opt_list)
800 {
801 struct cmd_option_t *next = opt_list->next;
802 fflush(stdout);
803 free(opt_list->name);
804 free(opt_list->str);
805 free(opt_list);
806 opt_list = next;
807 }
808}
809
810void db_free(struct cmd_file_t *file)
811{
812 db_free_option_list(file->opt_list);
813 db_free_option_list(file->constant_list);
814 struct cmd_source_t *src = file->source_list;
815 while(src)
816 {
817 struct cmd_source_t *next = src->next;
818 free(src->identifier);
819 fflush(stdout);
820 free(src->filename);
821 if(src->loaded)
822 {
823 if(src->type == CMD_SRC_BIN)
824 free(src->bin.data);
825 if(src->type == CMD_SRC_ELF)
826 elf_release(&src->elf);
827 }
828 free(src);
829 src = next;
830 }
831 struct cmd_section_t *sec = file->section_list;
832 while(sec)
833 {
834 struct cmd_section_t *next = sec->next;
835 db_free_option_list(sec->opt_list);
836 free(sec->source_id);
837 struct cmd_inst_t *inst = sec->inst_list;
838 while(inst)
839 {
840 struct cmd_inst_t *next = inst->next;
841 free(inst->identifier);
842 free(inst);
843 inst = next;
844 }
845 free(sec);
846 sec = next;
847 }
848 free(file);
849}