Mercurial > hg > index.cgi
view lwasm/pass1.c @ 349:b62af915c2cc
Fix includebin to use binary mode when emitting the contents of the file.
For systems with the stupid distinction between binary and text files (I'm
looking at you Windows), actually specify binary mode when reading the
include file for a binary include.
It worked fine on Linux and other Unix-like systems which treat files as
a simple sequence of bytes but on Windows, you get the benefit of 0x1A
causing an EOF signal with text mode files which is not helpful.
author | William Astle <lost@l-w.ca> |
---|---|
date | Sun, 12 Apr 2015 12:11:19 -0600 |
parents | 98f3e016cfd8 |
children | c6d2a1f54e0c |
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++) { // ignore 6800 compatibility entries unless asked for if ((instab[opnum].flags & lwasm_insn_is6800) && !CURPRAGMA(cl, PRAGMA_6800COMPAT)) continue; if (!strcasecmp(instab[opnum].opcode, sym)) break; } // 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) || ((as -> target != TARGET_6309) && (instab[opnum].flags & lwasm_insn_is6309)))) { // 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 -> target != TARGET_6309) && (instab[opnum].flags & lwasm_insn_is6309)) lwasm_register_error(as, cl, "Illegal use of 6309 instruction in 6809 mode (%s)", sym); if (as -> instruct == 0 || instab[opnum].flags & lwasm_insn_struct) { 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 we're forcing address modes on pass 1, force a resolution if (CURPRAGMA(cl, PRAGMA_FORWARDREFMAX) && instab[opnum].resolve) { (instab[opnum].resolve)(as, cl, 1); } 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 */ lwasm_reduce_line_exprs(cl); } 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)); } if (as -> skipcond || as -> inmacro || cl -> ltext[0] == 1) cl -> hideline = 1; nextline: if (sym) lw_free(sym); sym = NULL; lw_free(line); if (as -> preprocess && cl -> hideline == 0) { printf("%s\n", cl -> ltext); } // if we've hit the "end" bit, finish out if (as -> endseen) return; } }