Fix FS#12824 : Malfunctioning FFT plugin in Sansa Clip Zip
[maemo-rb.git] / utils / imxtools / sbtools / dbparser.c
blob89a63b376741e2e4bff4796fc004b04eed0c54e3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2011 Amaury Pouly
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
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"
30 enum lexem_type_t
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
49 struct lexem_t
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;
59 struct context_t
61 const char *file;
62 char *begin;
63 char *end;
64 char *ptr;
65 int line;
68 #define parse_error(ctx, ...) \
69 do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \
70 fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
72 static void advance(struct context_t *ctx, int nr_chars)
74 while(nr_chars--)
76 if(*(ctx->ptr++) == '\n')
77 ctx->line++;
81 static inline bool eof(struct context_t *ctx)
83 return ctx->ptr == ctx->end;
86 static inline bool next_valid(struct context_t *ctx, int nr)
88 return ctx->ptr + nr < ctx->end;
91 static inline char cur_char(struct context_t *ctx)
93 return *ctx->ptr;
96 static inline char next_char(struct context_t *ctx, int nr)
98 return ctx->ptr[nr];
101 static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx)
103 lex->file = ctx->file;
104 lex->line = ctx->line;
107 static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c))
109 while(!eof(ctx))
111 if(cur_char(ctx) == '"')
112 break;
113 else if(cur_char(ctx) == '\\')
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);
124 else
126 emit_fn(user, cur_char(ctx));
127 advance(ctx, 1);
130 if(eof(ctx) || cur_char(ctx) != '"')
131 parse_error(ctx, "Unfinished string\n");
132 advance(ctx, 1);
135 static void __parse_string_emit(void *user, char c)
137 char **pstr = (char **)user;
138 *(*pstr)++ = c;
141 static void __parse_string_count(void *user, char c)
143 (void) c;
144 (*(int *)user)++;
147 static void parse_string(struct context_t *ctx, struct lexem_t *lexem)
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);
164 static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem)
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))
174 if(cur_char(ctx) != '\'')
176 value = value << 8 | cur_char(ctx);
177 len++;
178 advance(ctx, 1);
180 else
181 break;
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;
193 static void parse_number(struct context_t *ctx, struct lexem_t *lexem)
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')
200 advance(ctx, 2);
201 base = 16;
204 lexem->type = LEX_NUMBER;
205 lexem->num = 0;
206 while(!eof(ctx) && isxdigit(cur_char(ctx)))
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);
218 static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem)
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);
232 static void next_lexem(struct context_t *ctx, struct lexem_t *lexem)
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))
241 char c = cur_char(ctx);
242 /* skip whitespace */
243 if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
245 advance(ctx, 1);
246 continue;
248 /* skip C++ style comments */
249 if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/')
251 while(!eof(ctx) && cur_char(ctx) != '\n')
252 advance(ctx, 1);
253 continue;
255 /* skip C-style comments */
256 if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*')
258 advance(ctx, 2);
259 while(true)
261 if(!next_valid(ctx, 1))
262 parse_error(ctx, "Unterminated comment");
263 if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/')
265 advance(ctx, 2);
266 break;
268 advance(ctx, 1);
270 continue;
272 break;
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
297 #if 0
298 static void log_lexem(struct lexem_t *lexem)
300 switch(lexem->type)
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>");
317 #endif
319 struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id)
321 struct cmd_source_t *src = cmd_file->source_list;
322 while(src)
324 if(strcmp(src->identifier, id) == 0)
325 return src;
326 src = src->next;
328 return NULL;
331 struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name)
333 while(opt)
335 if(strcmp(opt->name, name) == 0)
336 return opt;
337 opt = opt->next;
339 return NULL;
342 #define INVALID_SB_SUBVERSION 0xffff
344 static uint16_t parse_sb_subversion(char *str)
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++)
352 if(!isdigit(str[i]))
353 return INVALID_SB_SUBVERSION;
354 n = n << 4 | (str[i] - '0');
356 return n;
359 bool db_parse_sb_version(struct sb_version_t *ver, char *str)
361 int len = strlen(str);
362 int cnt = 0;
363 int pos[2];
365 for(int i = 0; i < len; i++)
367 if(str[i] != '.')
368 continue;
369 if(cnt == 2)
370 return false;
371 pos[cnt++] = i + 1;
372 str[i] = 0;
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;
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)
389 struct lex_ctx_t
391 struct context_t ctx;
392 struct lexem_t lexem;
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 */
399 static inline void next(struct lex_ctx_t *ctx, bool clean_lexem)
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);
407 static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
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)
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;
421 else
422 parse_error(ctx->lexem, "Number or constant identifier expected\n");
423 next(ctx, true);
424 return ret;
427 static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
429 uint32_t v = parse_term_expr(ctx, const_list);
430 while(ctx->lexem.type == LEX_LSHIFT)
432 next(ctx, true);
433 v <<= parse_term_expr(ctx, const_list);
435 return v;
438 static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
440 uint32_t v = parse_shift_expr(ctx, const_list);
441 while(ctx->lexem.type == LEX_OR)
443 next(ctx, true);
444 v |= parse_shift_expr(ctx, const_list);
446 return v;
449 static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
451 return parse_or_expr(ctx, const_list);
454 #define NR_INITIAL_CONSTANTS 4
455 static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"};
456 static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0};
458 struct cmd_file_t *db_parse_file(const char *file)
460 size_t size;
461 FILE *f = fopen(file, "r");
462 if(f == NULL)
464 if(g_debug)
465 perror("Cannot open db file");
466 return NULL;
468 fseek(f, 0, SEEK_END);
469 size = ftell(f);
470 fseek(f, 0, SEEK_SET);
471 char *buf = xmalloc(size);
472 if(fread(buf, size, 1, f) != 1)
474 if(g_debug)
475 perror("Cannot read db file");
476 return NULL;
478 fclose(f);
480 if(g_debug)
481 printf("Parsing db file '%s'\n", file);
482 struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t));
483 memset(cmd_file, 0, sizeof(struct cmd_file_t));
485 /* add initial constants */
486 for(int i = 0; i < NR_INITIAL_CONSTANTS; i++)
488 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
489 memset(opt, 0, sizeof(struct cmd_option_t));
490 opt->name = strdup(init_const_name[i]);
491 opt->is_string = false;
492 opt->val = init_const_value[i];
493 opt->next = cmd_file->constant_list;
494 cmd_file->constant_list = opt;
497 struct lex_ctx_t lctx;
498 lctx.ctx.file = file;
499 lctx.ctx.line = 1;
500 lctx.ctx.begin = buf;
501 lctx.ctx.ptr = buf;
502 lctx.ctx.end = buf + size;
503 #define next(clean_lexem) next(&lctx, clean_lexem)
504 #define lexem lctx.lexem
505 /* init lexer */
506 next(false); /* don't clean init lexem because it doesn't exist */
507 /* constants ? */
508 if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
510 next(true);
511 if(lexem.type != LEX_LBRACE)
512 parse_error(lexem, "'{' expected after 'constants'\n");
514 while(true)
516 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
517 memset(opt, 0, sizeof(struct cmd_option_t));
518 next(true);
519 if(lexem.type == LEX_RBRACE)
520 break;
521 if(lexem.type != LEX_IDENTIFIER)
522 parse_error(lexem, "Identifier expected in constants\n");
523 opt->name = lexem.str;
524 next(false); /* lexem string is kept as option name */
525 if(lexem.type != LEX_EQUAL)
526 parse_error(lexem, "'=' expected after identifier\n");
527 next(true);
528 opt->is_string = false;
529 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
530 opt->next = cmd_file->constant_list;
531 cmd_file->constant_list = opt;
532 if(lexem.type != LEX_SEMICOLON)
533 parse_error(lexem, "';' expected after string\n");
535 next(true);
537 /* options ? */
538 if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
540 next(true);
541 if(lexem.type != LEX_LBRACE)
542 parse_error(lexem, "'{' expected after 'options'\n");
544 while(true)
546 next(true);
547 if(lexem.type == LEX_RBRACE)
548 break;
549 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
550 memset(opt, 0, sizeof(struct cmd_option_t));
551 if(lexem.type != LEX_IDENTIFIER)
552 parse_error(lexem, "Identifier expected in options\n");
553 opt->name = lexem.str;
554 next(false); /* lexem string is kept as option name */
555 if(lexem.type != LEX_EQUAL)
556 parse_error(lexem, "'=' expected after identifier\n");
557 next(true);
558 if(lexem.type == LEX_STRING)
560 opt->is_string = true;
561 opt->str = lexem.str;
562 next(false); /* lexem string is kept as option name */
564 else
566 opt->is_string = false;
567 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
569 opt->next = cmd_file->opt_list;
570 cmd_file->opt_list = opt;
571 if(lexem.type != LEX_SEMICOLON)
572 parse_error(lexem, "';' expected after string\n");
574 next(true);
576 /* sources */
577 if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
578 parse_error(lexem, "'sources' expected\n");
579 next(true);
580 if(lexem.type != LEX_LBRACE)
581 parse_error(lexem, "'{' expected after 'sources'\n");
583 while(true)
585 next(true);
586 if(lexem.type == LEX_RBRACE)
587 break;
588 struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
589 memset(src, 0, sizeof(struct cmd_source_t));
590 if(lexem.type != LEX_IDENTIFIER)
591 parse_error(lexem, "identifier expected in sources\n");
592 src->identifier = lexem.str;
593 next(false); /* lexem string is kept as source name */
594 if(lexem.type != LEX_EQUAL)
595 parse_error(lexem, "'=' expected after identifier\n");
596 next(true);
597 if(lexem.type == LEX_STRING)
599 src->is_extern = false;
600 src->filename = lexem.str;
601 next(false); /* lexem string is kept as file name */
603 else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
605 src->is_extern = true;
606 src->filename = strdup("<extern>"); /* duplicate because it will be free'd */
607 next(true);
608 if(lexem.type != LEX_LPAREN)
609 parse_error(lexem, "'(' expected after 'extern'\n");
610 next(true);
611 src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
612 if(lexem.type != LEX_RPAREN)
613 parse_error(lexem, "')' expected\n");
614 next(true);
616 else
617 parse_error(lexem, "String or 'extern' expected after '='\n");
618 if(lexem.type != LEX_SEMICOLON)
619 parse_error(lexem, "';' expected\n");
620 if(db_find_source_by_id(cmd_file, src->identifier) != NULL)
621 parse_error(lexem, "Duplicate source identifier\n");
622 /* type filled later */
623 src->type = CMD_SRC_UNK;
624 src->next = cmd_file->source_list;
625 cmd_file->source_list = src;
628 /* sections */
629 struct cmd_section_t *end_sec = NULL;
630 while(true)
632 next(true);
633 if(lexem.type == LEX_EOF)
634 break;
635 struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
636 struct cmd_inst_t *end_list = NULL;
637 memset(sec, 0, sizeof(struct cmd_section_t));
638 if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
639 parse_error(lexem, "'section' expected\n");
640 next(true);
641 if(lexem.type != LEX_LPAREN)
642 parse_error(lexem, "'(' expected after 'section'\n");
643 next(true);
644 /* can be any number */
645 sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
646 /* options ? */
647 if(lexem.type == LEX_SEMICOLON)
651 next(true);
652 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
653 memset(opt, 0, sizeof(struct cmd_option_t));
654 if(lexem.type != LEX_IDENTIFIER)
655 parse_error(lexem, "Identifier expected for section option\n");
656 opt->name = lexem.str;
657 next(false); /* lexem string is kept as option name */
658 if(lexem.type != LEX_EQUAL)
659 parse_error(lexem, "'=' expected after option identifier\n");
660 next(true);
661 if(lexem.type == LEX_STRING)
663 opt->is_string = true;
664 opt->str = lexem.str;
665 next(false); /* lexem string is kept as option string */
667 else
669 opt->is_string = false;
670 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
672 opt->next = sec->opt_list;
673 sec->opt_list = opt;
674 }while(lexem.type == LEX_COLON);
676 if(lexem.type != LEX_RPAREN)
677 parse_error(lexem, "')' expected after section identifier\n");
678 next(true);
679 if(lexem.type == LEX_LBRACE)
681 sec->is_data = false;
682 /* commands */
683 while(true)
685 next(true);
686 if(lexem.type == LEX_RBRACE)
687 break;
688 struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
689 memset(inst, 0, sizeof(struct cmd_inst_t));
690 if(lexem.type != LEX_IDENTIFIER)
691 parse_error(lexem, "Instruction expected in section\n");
692 if(strcmp(lexem.str, "load") == 0)
693 inst->type = CMD_LOAD;
694 else if(strcmp(lexem.str, "call") == 0)
695 inst->type = CMD_CALL;
696 else if(strcmp(lexem.str, "jump") == 0)
697 inst->type = CMD_JUMP;
698 else if(strcmp(lexem.str, "mode") == 0)
699 inst->type = CMD_MODE;
700 else
701 parse_error(lexem, "Instruction expected in section\n");
702 next(true);
704 if(inst->type == CMD_LOAD)
706 if(lexem.type != LEX_IDENTIFIER)
707 parse_error(lexem, "Identifier expected after instruction\n");
708 inst->identifier = lexem.str;
709 if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
710 parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
711 next(false); /* lexem string kept as identifier */
712 if(lexem.type == LEX_RANGLE)
714 // load at
715 inst->type = CMD_LOAD_AT;
716 next(true);
717 inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
719 if(lexem.type != LEX_SEMICOLON)
720 parse_error(lexem, "';' expected after command\n");
722 else if(inst->type == CMD_CALL || inst->type == CMD_JUMP)
724 if(lexem.type == LEX_IDENTIFIER)
726 inst->identifier = lexem.str;
727 if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
728 parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
729 next(false); /* lexem string kept as identifier */
731 else
733 inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT;
734 inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
737 if(lexem.type == LEX_LPAREN)
739 next(true);
740 inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
741 if(lexem.type != LEX_RPAREN)
742 parse_error(lexem, "Expected closing brace\n");
743 next(true);
745 if(lexem.type != LEX_SEMICOLON)
746 parse_error(lexem, "';' expected after command\n");
748 else if(inst->type == CMD_MODE)
750 inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
751 if(lexem.type != LEX_SEMICOLON)
752 parse_error(lexem, "Expected ';' after command\n");
754 else
755 parse_error(lexem, "Internal error");
756 if(end_list == NULL)
758 sec->inst_list = inst;
759 end_list = inst;
761 else
763 end_list->next = inst;
764 end_list = inst;
768 else if(lexem.type == LEX_LE)
770 sec->is_data = true;
771 next(true);
772 if(lexem.type != LEX_IDENTIFIER)
773 parse_error(lexem, "Identifier expected after '<='\n");
774 sec->source_id = lexem.str;
775 next(false); /* lexem string is kept as source id */
776 if(lexem.type != LEX_SEMICOLON)
777 parse_error(lexem, "';' expected after identifier\n");
779 else
780 parse_error(lexem, "'{' or '<=' expected after section directive\n");
782 if(end_sec == NULL)
784 cmd_file->section_list = sec;
785 end_sec = sec;
787 else
789 end_sec->next = sec;
790 end_sec = sec;
793 #undef lexem
794 #undef next
796 free(buf);
797 return cmd_file;
800 void db_generate_default_sb_version(struct sb_version_t *ver)
802 ver->major = ver->minor = ver->revision = 0x999;
805 void db_free_option_list(struct cmd_option_t *opt_list)
807 while(opt_list)
809 struct cmd_option_t *next = opt_list->next;
810 fflush(stdout);
811 free(opt_list->name);
812 free(opt_list->str);
813 free(opt_list);
814 opt_list = next;
818 void db_free(struct cmd_file_t *file)
820 db_free_option_list(file->opt_list);
821 db_free_option_list(file->constant_list);
822 struct cmd_source_t *src = file->source_list;
823 while(src)
825 struct cmd_source_t *next = src->next;
826 free(src->identifier);
827 fflush(stdout);
828 free(src->filename);
829 if(src->loaded)
831 if(src->type == CMD_SRC_BIN)
832 free(src->bin.data);
833 if(src->type == CMD_SRC_ELF)
834 elf_release(&src->elf);
836 free(src);
837 src = next;
839 struct cmd_section_t *sec = file->section_list;
840 while(sec)
842 struct cmd_section_t *next = sec->next;
843 db_free_option_list(sec->opt_list);
844 free(sec->source_id);
845 struct cmd_inst_t *inst = sec->inst_list;
846 while(inst)
848 struct cmd_inst_t *next = inst->next;
849 free(inst->identifier);
850 free(inst);
851 inst = next;
853 free(sec);
854 sec = next;
856 free(file);