Mercurial > hg > index.cgi
view lwasm/pass1.c @ 207:07e1fac76321
Added pragma to allow non case sensitive symbols
Added "nosymbolcase" and "symbolnocase" pragmas to cause symbols defined
while the pragma is in effect to be treated as case insensitive. Also
documented the new pragma.
author | William Astle <lost@l-w.ca> |
---|---|
date | Sat, 09 Jun 2012 15:47:22 -0600 |
parents | d59f17580e8b |
children | b0d53e2f3f53 |
line wrap: on
line source
/* 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 <ctype.h> #include <stdlib.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); extern int add_macro_line(asmstate_t *as, char *optr); /* 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 = NULL; int opnum; int lc = 1; int nomacro; for (;;) { nomacro = 0; if (sym) lw_free(sym); 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); } else if (!strcmp(line + 2, "SETLINENO")) { lc = strtol(p1, NULL, 10); } else if (!strcmp(line + 2, "SETNOEXPANDSTART")) { as -> line_tail -> noexpand_start = 1; } else if (!strcmp(line + 2, "SETNOEXPANDEND")) { as -> line_tail -> noexpand_end = 1; } lw_free(line); if (lc == 0) 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; cl -> dlen = 0; as -> cl = cl; if (!as -> line_tail) { as -> line_head = cl; cl -> addr = lw_expr_build(lw_expr_type_int, 0); cl -> daddr = 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); // set the data address if relevant if (as -> output_format == OUTPUT_OS9) { te = lw_expr_build(lw_expr_type_special, lwasm_expr_linedlen, cl -> prev); cl -> daddr = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, cl -> prev -> daddr, te); lw_expr_destroy(te); lwasm_reduce_expr(as, cl -> daddr); } else { cl -> daddr = lw_expr_copy(cl -> addr); } // carry DP value forward cl -> dpval = cl -> prev -> dpval; } if (!lc && strcmp(cl -> linespec, cl -> prev -> linespec)) lc = 1; if (lc) { cl -> lineno = lc; 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) { if (*tok == '*' || *tok == ';' || *tok == '#') goto nextline; // 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 the first two chars of the opcode are "??", that's // a flag to inhibit macro expansion if (*tok && tok[0] == '?' && tok[1] == '?') { nomacro = 1; tok += 2; } if (*tok) { // look up operation code lw_free(sym); 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; } if ((as -> target == TARGET_6309) && (instab[opnum].flags & lwasm_insn_is6309)) lwasm_register_error(as, cl, "Illegal use of 6309 instruction in 6809 mode (%s)", sym); // have to go to linedone here in case there was a symbol // to register on this line if (instab[opnum].opcode == NULL && (*tok == '*' || *tok == ';' || *tok == '#')) goto linedone; // 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 (!nomacro && (as -> pragmas & PRAGMA_SHADOW)) { // check for macros even if they shadow real operations // NOTE: "ENDM" cannot be shadowed if (expand_macro(as, cl, &p1, sym) == 0) { // a macro was expanded here goto linedone; } } if (instab[opnum].opcode == NULL) { cl -> insn = -1; if (*tok != ';' && *tok != '*') { // bad opcode; check for macro here // but don't expand it if "nomacro" is in effect if (nomacro || 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) { struct line_expr_s *le; cl -> len = -1; // call parse function debug_message(as, 100, "len = %d, dlen = %d", cl -> len, cl -> dlen); (instab[opnum].parse)(as, cl, &p1); if ((cl -> inmod == 0) && cl -> len >= 0 && cl -> dlen >= 0) { if (cl -> len == 0) cl -> len = cl -> dlen; else cl -> dlen = cl -> len; } if (*p1 && !isspace(*p1) && !(cl -> err)) { // flag bad operand error lwasm_register_error(as, cl, "Bad operand (%s)", p1); } /* do a reduction on the line expressions to avoid carrying excessive expression baggage if not needed */ as -> cl = cl; // simplify address lwasm_reduce_expr(as, cl -> addr); // simplify each expression for (le = cl -> exprs; le; le = le -> next) lwasm_reduce_expr(as, le -> expr); /* try resolving the instruction as well */ if (cl -> insn >= 0 && instab[cl -> insn].resolve) { (instab[cl -> insn].resolve)(as, cl, 0); if ((cl -> inmod == 0) && cl -> len >= 0 && cl -> dlen >= 0) { if (cl -> len == 0) cl -> len = cl -> dlen; else cl -> dlen = cl -> len; } } } else if (as -> instruct == 1) { lwasm_register_error(as, cl, "Bad operand (%s)", p1); } } } } linedone: 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 (instab[cl -> insn].flags & lwasm_insn_setdata) { if (!register_symbol(as, cl, cl -> sym, cl -> daddr, symbol_flag_none)) { // symbol error // lwasm_register_error(as, cl, "Bad symbol '%s'", cl -> sym); } } else { 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: if (sym) lw_free(sym); sym = NULL; lw_free(line); // if we've hit the "end" bit, finish out if (as -> endseen) return; } }