Mercurial > hg > index.cgi
diff lwasm/pass1.c @ 0:2c24602be78f
Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author | lost@l-w.ca |
---|---|
date | Wed, 19 Jan 2011 22:27:17 -0700 |
parents | |
children | 7317fbe024af |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/pass1.c Wed Jan 19 22:27:17 2011 -0700 @@ -0,0 +1,316 @@ +/* +pass1.c + +Copyright © 2010 William Astle + +This file is part of LWTOOLS. + +LWTOOLS is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> + +#include <lw_alloc.h> +#include <lw_string.h> + +#include "lwasm.h" +#include "instab.h" +#include "input.h" + +extern int expand_macro(asmstate_t *as, line_t *l, char **p, char *opc); +extern int expand_struct(asmstate_t *as, line_t *l, char **p, char *opc); + +/* +pass 1: parse the lines + +line format: + +[<symbol>] <opcode> <operand>[ <comment>] + +If <symbol> is followed by a :, whitespace may precede the symbol + +A line may optionally start with a number which must not be preceded by +white space and must be followed by a single whitespace character. After +that whitespace character, the line is parsed as if it had no line number. + +*/ +void do_pass1(asmstate_t *as) +{ + char *line; + line_t *cl; + char *p1; + int stspace; + char *tok, *sym; + int opnum; + int lc = 1; + for (;;) + { + sym = NULL; + line = input_readline(as); + if (!line) + break; + if (line[0] == 1 && line[1] == 1) + { + // special internal directive + // these DO NOT appear in the output anywhere + // they are generated by the parser to pass information + // forward + for (p1 = line + 2; *p1 && !isspace(*p1); p1++) + /* do nothing */ ; + *p1++ = '\0'; + if (!strcmp(line + 2, "SETCONTEXT")) + { + as -> context = strtol(p1, NULL, 10); + } + lw_free(line); + lc = 1; + continue; + } + debug_message(as, 75, "Read line: %s", line); + + cl = lw_alloc(sizeof(line_t)); + memset(cl, 0, sizeof(line_t)); + cl -> outputl = -1; + cl -> linespec = lw_strdup(input_curspec(as)); + cl -> prev = as -> line_tail; + cl -> insn = -1; + cl -> as = as; + cl -> inmod = as -> inmod; + cl -> csect = as -> csect; + cl -> pragmas = as -> pragmas; + cl -> context = as -> context; + cl -> ltext = lw_strdup(line); + cl -> soff = -1; + cl -> dshow = -1; + cl -> dsize = 0; + cl -> dptr = NULL; + cl -> isbrpt = 0; + as -> cl = cl; + if (!as -> line_tail) + { + as -> line_head = cl; + cl -> addr = lw_expr_build(lw_expr_type_int, 0); + } + else + { + lw_expr_t te; + + cl -> lineno = as -> line_tail -> lineno + 1; + as -> line_tail -> next = cl; + + // set the line address + te = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, cl -> prev); + cl -> addr = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, cl -> prev -> addr, te); + lw_expr_destroy(te); + lwasm_reduce_expr(as, cl -> addr); +// lw_expr_simplify(cl -> addr, as); + + // carry DP value forward + cl -> dpval = cl -> prev -> dpval; + + } + if (!lc && strcmp(cl -> linespec, cl -> prev -> linespec)) + lc = 1; + if (lc) + { + cl -> lineno = 1; + lc = 0; + } + as -> line_tail = cl; + // blank lines don't count for anything + // except a local symbol context break + if (!*line) + { + as -> context = lwasm_next_context(as); + goto nextline; + } + + // skip comments + // commends do not create a context break + if (*line == '*' || *line == ';' || *line == '#') + goto nextline; + + p1 = line; + if (isdigit(*p1)) + { + // skip line number + while (*p1 && isdigit(*p1)) + p1++; + if (!*p1 && !isspace(*p1)) + p1 = line; + else if (*p1 && !isspace(*p1)) + p1 = line; + else if (*p1 && isspace(*p1)) + p1++; + } + + // blank line - context break + if (!*p1) + { + as -> context = lwasm_next_context(as); + goto nextline; + } + + // comment - no context break + if (*p1 == '*' || *p1 == ';' || *p1 == '#') + goto nextline; + + if (isspace(*p1)) + { + for (; *p1 && isspace(*p1); p1++) + /* do nothing */ ; + stspace = 1; + } + else + stspace = 0; + + if (*p1 == '*' || *p1 == ';' || *p1 == '#') + goto nextline; + if (!*p1) + { + // nothing but whitespace - context break + as -> context = lwasm_next_context(as); + goto nextline; + } + + // find the end of the first token + for (tok = p1; *p1 && !isspace(*p1) && *p1 != ':' && *p1 != '='; p1++) + /* do nothing */ ; + + if (*p1 == ':' || *p1 == '=' || stspace == 0) + { + // have a symbol here + sym = lw_strndup(tok, p1 - tok); + if (*p1 == ':') + p1++; + for (; *p1 && isspace(*p1); p1++) + /* do nothing */ ; + + if (*p1 == '=') + { + tok = p1++; + } + else + { + for (tok = p1; *p1 && !isspace(*p1); p1++) + /* do nothing */ ; + } + } + if (sym && strcmp(sym, "!") == 0) + cl -> isbrpt = 1; + else if (sym) + cl -> sym = lw_strdup(sym); + cl -> symset = 0; + + // tok points to the opcode for the line or NUL if none + if (*tok) + { + // look up operation code + sym = lw_strndup(tok, p1 - tok); + for (; *p1 && isspace(*p1); p1++) + /* do nothing */ ; + + for (opnum = 0; instab[opnum].opcode; opnum++) + { + if (!strcasecmp(instab[opnum].opcode, sym)) + break; + } + + // p1 points to the start of the operand + + // if we're inside a macro definition and not at ENDM, + // add the line to the macro definition and continue + if (as -> inmacro && !(instab[opnum].flags & lwasm_insn_endm)) + { + add_macro_line(as, line); + goto linedone; + } + + // if skipping a condition and the operation code doesn't + // operate within a condition (not a conditional) + // do nothing + if (as -> skipcond && !(instab[opnum].flags & lwasm_insn_cond)) + goto linedone; + + if (instab[opnum].opcode == NULL) + { + cl -> insn = -1; + if (*tok != ';' && *tok != '*') + { + // bad opcode; check for macro here + if (expand_macro(as, cl, &p1, sym) != 0) + { + // macro expansion failed + if (expand_struct(as, cl, &p1, sym) != 0) + { + // structure expansion failed + lwasm_register_error(as, cl, "Bad opcode"); + } + } + } + } + else + { + cl -> insn = opnum; + // no parse func means operand doesn't matter + if (instab[opnum].parse) + { + if (as -> instruct == 0 || instab[opnum].flags & lwasm_insn_struct) + { + cl -> len = -1; + // call parse function + (instab[opnum].parse)(as, cl, &p1); + + if (*p1 && !isspace(*p1)) + { + // flag bad operand error + lwasm_register_error(as, cl, "Bad operand (%s)", p1); + } + } + else if (as -> instruct == 1) + { + lwasm_register_error(as, cl, "Bad operand (%s)", p1); + } + } + } + } + + linedone: + lw_free(sym); + + if (!as -> skipcond && !as -> inmacro) + { + if (cl -> sym && cl -> symset == 0) + { + debug_message(as, 50, "Register symbol %s: %s", cl -> sym, lw_expr_print(cl -> addr)); + + // register symbol at line address + if (!register_symbol(as, cl, cl -> sym, cl -> addr, symbol_flag_none)) + { + // symbol error + // lwasm_register_error(as, cl, "Bad symbol '%s'", cl -> sym); + } + } + debug_message(as, 40, "Line address: %s", lw_expr_print(cl -> addr)); + } + + nextline: + lw_free(line); + + // if we've hit the "end" bit, finish out + if (as -> endseen) + return; + } +}