From efa3beca488b481c0b30c25199c209a2d762623a Mon Sep 17 00:00:00 2001 From: John Brandwood Date: Sun, 28 Apr 2024 12:30:49 -0400 Subject: [PATCH] Restore src/huc directory after duplication --- src/huc/Makefile | 52 ++ src/huc/code.c | 841 +++++++++++++++++ src/huc/code.h | 29 + src/huc/const.c | 407 ++++++++ src/huc/const.h | 19 + src/huc/data.c | 122 +++ src/huc/data.h | 120 +++ src/huc/defs.h | 433 +++++++++ src/huc/enum.c | 107 +++ src/huc/enum.h | 3 + src/huc/error.c | 83 ++ src/huc/error.h | 9 + src/huc/expr.c | 950 +++++++++++++++++++ src/huc/expr.h | 31 + src/huc/fastcall.h | 9 + src/huc/function.c | 1157 +++++++++++++++++++++++ src/huc/function.h | 18 + src/huc/gen.c | 733 +++++++++++++++ src/huc/gen.h | 65 ++ src/huc/initials.c | 154 +++ src/huc/initials.h | 5 + src/huc/io.c | 613 ++++++++++++ src/huc/io.h | 56 ++ src/huc/lex.c | 175 ++++ src/huc/lex.h | 32 + src/huc/main.c | 1143 +++++++++++++++++++++++ src/huc/main.h | 32 + src/huc/optimize.c | 2026 ++++++++++++++++++++++++++++++++++++++++ src/huc/optimize.h | 14 + src/huc/pragma.c | 539 +++++++++++ src/huc/pragma.h | 21 + src/huc/preproc.c | 807 ++++++++++++++++ src/huc/preproc.h | 44 + src/huc/primary.c | 867 +++++++++++++++++ src/huc/primary.h | 24 + src/huc/pseudo.c | 1164 +++++++++++++++++++++++ src/huc/pseudo.h | 20 + src/huc/stmt.c | 586 ++++++++++++ src/huc/stmt.h | 30 + src/huc/struct.c | 116 +++ src/huc/struct.h | 3 + src/huc/sym.c | 600 ++++++++++++ src/huc/sym.h | 17 + src/huc/uncrustify.cfg | 143 +++ src/huc/version.h | 12 + src/huc/version.h.in | 12 + src/huc/while.c | 81 ++ src/huc/while.h | 11 + 48 files changed, 14535 insertions(+) create mode 100644 src/huc/Makefile create mode 100644 src/huc/code.c create mode 100644 src/huc/code.h create mode 100644 src/huc/const.c create mode 100644 src/huc/const.h create mode 100644 src/huc/data.c create mode 100644 src/huc/data.h create mode 100644 src/huc/defs.h create mode 100644 src/huc/enum.c create mode 100644 src/huc/enum.h create mode 100644 src/huc/error.c create mode 100644 src/huc/error.h create mode 100644 src/huc/expr.c create mode 100644 src/huc/expr.h create mode 100644 src/huc/fastcall.h create mode 100644 src/huc/function.c create mode 100644 src/huc/function.h create mode 100644 src/huc/gen.c create mode 100644 src/huc/gen.h create mode 100644 src/huc/initials.c create mode 100644 src/huc/initials.h create mode 100644 src/huc/io.c create mode 100644 src/huc/io.h create mode 100644 src/huc/lex.c create mode 100644 src/huc/lex.h create mode 100644 src/huc/main.c create mode 100644 src/huc/main.h create mode 100644 src/huc/optimize.c create mode 100644 src/huc/optimize.h create mode 100644 src/huc/pragma.c create mode 100644 src/huc/pragma.h create mode 100644 src/huc/preproc.c create mode 100644 src/huc/preproc.h create mode 100644 src/huc/primary.c create mode 100644 src/huc/primary.h create mode 100644 src/huc/pseudo.c create mode 100644 src/huc/pseudo.h create mode 100644 src/huc/stmt.c create mode 100644 src/huc/stmt.h create mode 100644 src/huc/struct.c create mode 100644 src/huc/struct.h create mode 100644 src/huc/sym.c create mode 100644 src/huc/sym.h create mode 100644 src/huc/uncrustify.cfg create mode 100644 src/huc/version.h create mode 100644 src/huc/version.h.in create mode 100644 src/huc/while.c create mode 100644 src/huc/while.h diff --git a/src/huc/Makefile b/src/huc/Makefile new file mode 100644 index 00000000..02d6a7c7 --- /dev/null +++ b/src/huc/Makefile @@ -0,0 +1,52 @@ +# Makefile for HuC +# +# Written for Linux development version, March 4, 2001 by Dave Shadoff +# + +# +# Defines +# +BASEDIR=..d .. +include ../Make_src.inc + + +HDRS = code.h data.h defs.h error.h gen.h lex.h preproc.h pseudo.h sym.h while.h +OBJS = code.o const.o data.o error.o expr.o \ + function.o gen.o io.o lex.o main.o \ + optimize.o pragma.o preproc.o primary.o pseudo.o \ + stmt.o sym.o while.o struct.o enum.o initials.o +EXE = huc$(EXESUFFIX) + +all: $(EXE) + +$(EXE): $(OBJS) $(LIBS) $(HDRS) + $(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ + $(CP) $(EXE) $(BINDIR) + +$(OBJS): code.h data.h defs.h error.h io.h + +code.o: function.h main.h optimize.h +const.o: const.h lex.h primary.h sym.h +expr.o: expr.h function.h gen.h lex.h primary.h +function.o: expr.h function.h gen.h lex.h optimize.h pragma.h pseudo.h stmt.h sym.h +gen.o: primary.h sym.h +io.o: optimize.h preproc.h +lex.o: lex.h preproc.h +main.o: const.h function.h gen.h lex.h main.h optimize.h pragma.h preproc.h \ + pseudo.h sym.h +optimize.o: function.h +pragma.o: lex.h pragma.h sym.h +preproc.o: lex.h optimize.h preproc.h sym.h +primary.o: expr.h gen.h lex.h primary.h sym.h +pseudo.o: lex.h optimize.h primary.h pseudo.h sym.h +stmt.o: expr.h gen.h lex.h preproc.h primary.h stmt.h sym.h while.h +sym.o: const.h gen.h lex.h primary.h pragma.h sym.h +while.o: gen.h while.h + +indent: uncrustify.cfg + uncrustify -l c -c $< --replace *.c *.h + +# +# Targets +# +include $(MAKETARG) diff --git a/src/huc/code.c b/src/huc/code.c new file mode 100644 index 00000000..c92963c9 --- /dev/null +++ b/src/huc/code.c @@ -0,0 +1,841 @@ +/* File code.c: 2.2 (84/08/31,10:05:13) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include + +#include "defs.h" +#include "data.h" +#include "code.h" +#include "error.h" +#include "function.h" +#include "io.h" +#include "main.h" +#include "optimize.h" + +/* locals */ +intptr_t segment; + +/* externs */ +extern intptr_t arg_stack_flag; + +/* + * print all assembler info before any code is generated + * + */ +void gdata (void) +{ + if (segment == 1) { + segment = 0; + ol(".bss"); + } +} + +void gtext (void) +{ + if (segment == 0) { + segment = 1; + ol(".code"); + } +} + +void header (void) +{ + time_t today; + + outstr("; Small C HuC6280 (v0.2, 08/Nov/97)\n;\n"); + outstr("; Taken to HuC (22/Feb/00)\n;\n"); + outstr(";\n"); + outstr("; This file generated by "); + outstr(HUC_VERSION); + outstr("\n"); + outstr("; on "); + time(&today); + outstr(ctime(&today)); + outstr(";\n"); + outstr("\n"); + outstr("HUC\t= 1\n"); + /* Reserve space for further global definitions. */ + output_globdef = ftell(output); + outstr(" "); + nl(); +} + +void asmdefines (void) +{ + outstr(asmdefs); +} + +void inc_startup (void) +{ + if (startup_incl == 0) { + startup_incl = 1; + + nl(); + outstr("\t.include \"startup.asm\"\n"); + outstr("\t.data\n"); + outstr("\t.bank DATA_BANK\n\n"); + gtext(); + nl(); + } +} + +/* + * print pseudo-op to define a byte + * + */ +void defbyte (void) +{ + ot(".db\t"); +} + +/* + * print pseudo-op to define storage + * + */ +void defstorage (void) +{ + ot(".ds\t"); +} + +/* + * print pseudo-op to define a word + * + */ +void defword (void) +{ + ot(".dw\t"); +} + +/* + * output instructions + * + */ +void out_ins (intptr_t code, intptr_t type, intptr_t data) +{ + INS tmp; + + memset(&tmp, 0, sizeof(INS)); + + tmp.code = code; + tmp.type = type; + tmp.data = data; + gen_ins(&tmp); +} + +void out_ins_ex (intptr_t code, intptr_t type, intptr_t data, intptr_t imm_type, intptr_t imm_data) +{ + INS tmp; + + memset(&tmp, 0, sizeof(INS)); + + tmp.code = code; + tmp.type = type; + tmp.data = data; + tmp.imm_type = imm_type; + tmp.imm_data = imm_data; + gen_ins(&tmp); +} + +void out_ins_sym (intptr_t code, intptr_t type, intptr_t data, SYMBOL *sym) +{ + INS tmp; + + memset(&tmp, 0, sizeof(INS)); + + tmp.code = code; + tmp.type = type; + tmp.data = data; + tmp.sym = sym; + gen_ins(&tmp); +} + +void gen_ins (INS *tmp) +{ + if (optimize) + push_ins(tmp); + else { + if (arg_stack_flag) + arg_push_ins(tmp); + else + gen_code(tmp); + } +} + +static void out_type (intptr_t type, intptr_t data) +{ + switch (type) { + case T_VALUE: + outdec(data); + break; + case T_LABEL: + outlabel(data); + break; + case T_SYMBOL: + outsymbol((char *)data); + break; + case T_LITERAL: + outstr((char *)data); + break; + case T_STRING: + outlabel(litlab); + outbyte('+'); + outdec(data); + break; + case T_BANK: + outstr("BANK("); + outstr((char *)data); + outstr(")"); + break; + case T_VRAM: + outstr("VRAM("); + outstr((char *)data); + outstr(")"); + break; + case T_PAL: + outstr("PAL("); + outstr((char *)data); + outstr(")"); + break; + } +} + +static void out_addr (intptr_t type, intptr_t data) +{ + switch (type) { + case T_LABEL: + outlabel(data); + break; + case T_SYMBOL: + outsymbol((char *)data); + break; + case T_LITERAL: + outstr((char *)data); + break; + case T_PTR: + outstr("__ptr"); + break; + case T_VALUE: + outdec(data); + break; + case T_STACK: + outstr("__stack"); + break; + } +} + +void dump_ins (INS *tmp) +{ + FILE *save = output; + + output = stdout; + gen_code(tmp); + output = save; +} + +/* + * gen assembly code + * + */ +void gen_code (INS *tmp) +{ + intptr_t code; + intptr_t type; + intptr_t data; + intptr_t imm_type; + intptr_t imm_data; + + code = tmp->code; + type = tmp->type; + data = tmp->data; + imm_type = tmp->imm_type; + imm_data = tmp->imm_data; + + if (type == T_NOP) + return; + + switch (code) { + case I_FARPTR: + ot("__farptr\t"); + + switch (type) { + case T_LABEL: + outlabel(data); + break; + case T_SYMBOL: + outsymbol((char *)data); + break; + } + outstr(","); + outstr(tmp->arg[0]); + outstr(","); + outstr(tmp->arg[1]); + nl(); + break; + + case I_FARPTR_I: + ot("__farptr_i\t"); + outsymbol((char *)data); + outstr(","); + outstr(tmp->arg[0]); + outstr(","); + outstr(tmp->arg[1]); + nl(); + break; + + case I_FARPTR_GET: + ot("__farptr_get\t"); + outstr(tmp->arg[0]); + outstr(","); + outstr(tmp->arg[1]); + nl(); + break; + + case I_FGETB: + ot("__farptr_i\t"); + outsymbol((char *)data); + nl(); + ol("__fgetb"); + break; + + case I_FGETUB: + ot("__farptr_i\t"); + outsymbol((char *)data); + nl(); + ol("__fgetub"); + break; + + case I_FGETW: + ot("__farptr_i\t"); + outsymbol((char *)data); + nl(); + ol(" jsr\t_farpeekw.fast"); + break; + + case I_VGETW: + ol("__ldw\tvideo_data"); + break; + + case I_VPUTW: + ol("__stw\tvideo_data"); + break; + + case I_LDB: + case I_LDBY: + if (code == I_LDBY) + ot("__ldby\t"); + else + ot("__ldb\t"); + out_type(type, data); + nl(); + break; + + case I_LDYB: + ot(" ldy\t"); + out_type(type, data); + nl(); + break; + + case I_LDUB: + ot("__ldub\t"); + out_type(type, data); + nl(); + break; + + case I_LDBP: + ot("__ldbp\t"); + out_addr(type, data); + nl(); + break; + + case I_LDUBP: + ot("__ldubp\t"); + out_addr(type, data); + nl(); + break; + + case I_STBP: + ot("__stbp\t"); + out_addr(type, data); + nl(); + break; + + case I_LDW: + ot("__ldw\t"); + out_addr(type, data); + nl(); + break; + + case I_LDWI: + ot("__ldwi\t"); + out_type(type, data); + nl(); + break; + + case I_LDWP: + ot("__ldwp\t"); + out_addr(type, data); + nl(); + break; + + case I_STWP: + ot("__stwp\t"); + out_addr(type, data); + nl(); + break; + + case I_STB: + ot(" stx\t"); + out_addr(type, data); + nl(); + break; + + case I_STBPS: + ol("__stbps"); + break; + + case I_STW: + ot("__stw\t"); + if (type == T_PTR) + outstr("<"); + out_addr(type, data); + nl(); + break; + + case I_STWI: + case I_STBI: + if (code == I_STWI) + ot("__stwi\t"); + else + ot("__stbi\t"); + out_type(type, data); + outstr(", "); + out_type(imm_type, imm_data); + nl(); + break; + + case I_STWZ: + ot("__stwz\t"); + out_type(type, data); + nl(); + break; + + case I_STBZ: + ot("stz\t"); + out_type(type, data); + nl(); + break; + case I_STWPS: + ol("__stwps"); + break; + + case I_ADDW: + ot("__addw\t"); + out_addr(type, data); + nl(); + break; + + case I_ADDB: + ot("__addb\t"); + out_addr(type, data); + nl(); + break; + + case I_ADDUB: + ot("__addub\t"); + out_addr(type, data); + nl(); + break; + + case I_ADDWI: + case I_ADDBI: + if (code == I_ADDBI) + ot("__addbi"); + else + ot("__addwi"); + /* Assembler workaround; pceas doesn't like if the code + size changes as it resolved a symbol, so we use the + variant without ".if"s if there is a symbol involved. */ + if (type == T_SYMBOL || + type == T_LITERAL || + type == T_STRING) + outstr("_sym"); + outstr("\t"); + out_type(type, data); + nl(); + break; + + case I_ADDBI_P: + ot("__addbi_p\t"); + out_type(type, data); + nl(); + break; + + case I_ADDWS: + ol("__addws"); + break; + + case I_ADDBS: + ol("__addbs"); + break; + + case I_ADDMI: + ot("__addmi"); + if (type == T_LITERAL) { + outstr("_sym\t"); + outstr((char *)data); + } + else { + outstr("\t"); + outdec(data); + } + outstr(",__stack"); + nl(); + break; + + case I_SUBW: + ot("__subw\t"); + out_addr(type, data); + nl(); + break; + + case I_SUBWI: + ot("__subwi\t"); + outdec(data); + nl(); + break; + + case I_SUBWS: + ol("__subws"); + break; + + case I_ORWI: + ot("__orwi\t"); + outdec(data); + nl(); + break; + + case I_STBIP: + ot("__stbip\t"); + outdec(data); + nl(); + break; + + case I_STWIP: + ot("__stwip\t"); + outdec(data); + nl(); + break; + + case I_ORWS: + ol("__orws"); + break; + + case I_EORWS: + ol("__eorws"); + break; + + case I_ANDWI: + ot("__andwi\t"); + outdec(data); + nl(); + break; + + case I_ANDWS: + ol("__andws"); + break; + + case I_ASLW: + ol("__aslw"); + break; + + case I_ASLWI: + ot("__aslwi\t"); + out_type(type, data); + nl(); + break; + + case I_LSRWI: + ot("__lsrwi\t"); + out_type(type, data); + nl(); + break; + + case I_ASRWI: + ot("__asrwi\t"); + out_type(type, data); + nl(); + break; + + case I_ASLWS: + ol("__aslws"); + break; + + case I_ASRW: + ol("__asrw"); + break; + + case I_COMW: + ol("__comw"); + break; + + case I_NEGW: + ol("__negw"); + break; + + case I_SWAPW: + ol("__swapw"); + break; + + case I_EXTW: + ol("__extw"); + break; + + case I_BOOLW: + ol("__boolw"); + break; + + case I_NOTW: + ol("__notw"); + break; + + case I_JMP: + ot(" jmp\t"); + outsymbol((char *)data); + nl(); + break; + + case I_JSR: + ot(" jsr\t"); + + switch (type) { + case T_SYMBOL: + outsymbol((char *)data); + break; + case T_LIB: + outstr((char *)data); + break; + } + nl(); + break; + + case I_CALL: + switch (type) { + case T_SYMBOL: + ot(" call\t"); + outsymbol((char *)data); + if (imm_data) { + outstr("."); + outdec(imm_data); + } + break; + case T_LIB: + ot(" jsr\t"); + outstr((char *)data); + break; + } + nl(); + break; + + case I_MACRO: + switch (type) { + case T_SYMBOL: + ot(" \t"); + outsymbol((char *)data); + if (imm_data) { + outstr("."); + outdec(imm_data); + } + break; + case T_LIB: + ot(" \t"); + outstr((char *)data); + break; + } + nl(); + break; + + case I_MAPCBANK: + ot("__map_callbank\t"); + outsymbol((char *)data); + if (imm_data) { + outstr("."); + outdec(imm_data); + } + nl(); + break; + + case I_UNMAPCBANK: + ot("__unmap_callbank\t"); + outsymbol((char *)data); + if (imm_data) { + outstr("."); + outdec(imm_data); + } + nl(); + break; + + case I_CALLS: + ot("__calls\t"); + outdec(data); + nl(); + break; + + case I_RTS: + ol(" rts"); + break; + + case I_PUSHW: + ol("__pushw"); + break; + + case I_POPW: + ol("__popw"); + break; + + case I_SAVEW: + ol("__phax"); + break; + + case I_RESW: + ol("__plax"); + break; + + case I_SAVEB: + ol("phx"); + break; + + case I_RESB: + ol("plx"); + break; + + case I_TSTW: + ol("__tstw"); + break; + + case I_LBRA: + ot("__lbra\t"); + outlabel(data); + nl(); + break; + + case I_LBRAN: + ot("__lbran\t"); + outlabel(data); + nl(); + break; + + case I_LBEQ: + ot("__lbeq\t"); + outlabel(data); + nl(); + break; + + case I_LBEQN: + ot("__lbeqn\t"); + outlabel(data); + nl(); + break; + + case I_LBNE: + ot("__lbne\t"); + outlabel(data); + nl(); + break; + + case I_LBNEN: + ot("__lbnen\t"); + outlabel(data); + nl(); + break; + + case I_CMPWI_EQ: + ot("__cmpwi_eq\t"); + out_type(type, data); + nl(); + break; + + case I_CMPWI_NE: + ot("__cmpwi_ne\t"); + out_type(type, data); + nl(); + break; + + case I_BANK: + ot(".bank\t"); + switch (type) { + case T_VALUE: + outdec(data); + break; + default: + error("bank type switching not handled"); + break; + } + nl(); + break; + + case I_OFFSET: + ot(".org\t"); + switch (type) { + case T_VALUE: + outhex((unsigned short)data); + break; + default: + error("org type setting not handled"); + break; + } + nl(); + break; + + case I_INCW: + ot("incw\t"); + out_addr(type, data); + nl(); + break; + + case I_INCB: + ot("inc\t"); + out_addr(type, data); + nl(); + break; + + case I_LABEL: + outlabel(data); + col(); + nl(); + break; + + case I_MULWI: + ot("__mulwi\t"); + outdec(data); + nl(); + break; + + case I_EXTUW: + ol("cla"); + break; + + case I_DEF: + outstr((char *)data); + outstr(" .equ "); + outdec(imm_data); + nl(); + break; + + case I_SEI: + ol("sei"); + break; + + case I_CLI: + ol("cli"); + break; + + default: + gen_asm(tmp); + break; + } +} diff --git a/src/huc/code.h b/src/huc/code.h new file mode 100644 index 00000000..ca464c9f --- /dev/null +++ b/src/huc/code.h @@ -0,0 +1,29 @@ +/* File code.h: 2.2 (84/11/27,16:26:11) */ +/*% cc -O -c % + * + */ + +#ifndef _CODE_H +#define _CODE_H + +#include "defs.h" + +extern intptr_t segment; + +void gdata (void); +void gtext (void); +void header (void); +void inc_startup (void); +void asmdefines (void); +void defbyte (void); +void defstorage (void); +void defword (void); +void out_ins (intptr_t code, intptr_t type, intptr_t data); +void out_ins_ex (intptr_t code, intptr_t type, intptr_t data, intptr_t imm_type, intptr_t imm_data); +void out_ins_sym (intptr_t code, intptr_t type, intptr_t data, SYMBOL *sym); +void gen_ins (INS *tmp); +void gen_code (INS *tmp); + +void dump_ins (INS *tmp); + +#endif diff --git a/src/huc/const.c b/src/huc/const.c new file mode 100644 index 00000000..3e986a27 --- /dev/null +++ b/src/huc/const.c @@ -0,0 +1,407 @@ +/* File const.c: 2.1 (00/07/17,16:02:19) */ +/*% cc -O -c % + * + */ + +/* XXX: This passes the initializer more or less verbatim to the assembler, + which unsurprisingly does not care much for C semantics, breaking stuff + like pointer arithmetic, and probably many non-trivial expressions. + Needs a rewrite. */ + +#include +#include +#include "defs.h" +#include "data.h" +#include "code.h" +#include "const.h" +#include "error.h" +#include "io.h" +#include "lex.h" +#include "primary.h" +#include "sym.h" + +/* + * setup a new const array + * + */ +void new_const (void) +{ + const_ptr = &const_var[const_nb]; + const_val_idx = const_val_start; + const_data_idx = const_data_start; +} + + +/* + * add a const array + * + */ +void add_const (intptr_t typ) +{ + if ((const_data_idx >= MAX_CONST_DATA) || (const_val_idx >= MAX_CONST_VALUE)) + error("too much constant data (> 8KB)"); + if (const_nb >= MAX_CONST) + error("too much constant arrays"); + else { + const_ptr->sym = cptr; + const_ptr->typ = typ; + const_ptr->size = const_val_idx - const_val_start; + const_ptr->data = const_val_start; + const_val_start = const_val_idx; + const_data_start = const_data_idx; + const_nb++; + } +} + + +/* + * array initializer + * + */ +intptr_t array_initializer (intptr_t typ, intptr_t id, intptr_t stor) +{ + intptr_t nb; + intptr_t k; + intptr_t i; + + nb = 0; + k = needsub(); + + if (stor == CONST) + new_const(); + if (match("=")) { + if (stor != CONST) + error("can't initialize non-const arrays"); + if (!match("{")) { + error("syntax error"); + return (-1); + } + if (!match("}")) { + for (;;) { + if (match("}")) { + error("value missing"); + break; + } + if (match(",")) { + error("value missing"); + continue; + } + if ((ch() == '\"') && (id == POINTER)) + i = get_string_ptr(typ); + else + i = get_raw_value(','); + nb++; + blanks(); + if (const_val_idx < MAX_CONST_VALUE) + const_val[const_val_idx++] = i; + if ((ch() != ',') && (ch() != '}')) { + error("syntax error"); + return (-1); + } + if (match("}")) + break; + gch(); + } + } + if (k == 0) + k = nb; + if (nb > k) { + nb = k; + error("excess elements in array initializer"); + } + } + if (stor == CONST) { + while (nb < k) { + nb++; + if (const_val_idx < MAX_CONST_VALUE) + const_val[const_val_idx++] = -1; + } + } + return (k); +} + +/* + * scalar initializer + * + */ +intptr_t scalar_initializer (intptr_t typ, intptr_t id, intptr_t stor) +{ + intptr_t i; + + if (stor == CONST) + new_const(); + if (match("=")) { + if (stor != CONST) + error("can't initialize non-const scalars"); + blanks(); + if (ch() == ';') { + error("value missing"); + return (-1); + } + if (ch() == '\"' && id == POINTER) + i = get_string_ptr(typ); + else + i = get_raw_value(';'); + if (const_val_idx < MAX_CONST_VALUE) + const_val[const_val_idx++] = i; + blanks(); + if (ch() != ';') { + error("syntax error"); + return (-1); + } + } + return (1); +} + + +/* + * add a string to the literal pool and return a pointer (index) to it + * + */ +intptr_t get_string_ptr (intptr_t typ) +{ + intptr_t num[1]; + + if (typ == CINT || typ == CUINT) + error("incompatible pointer type"); + if (qstr(num)) + return (-(num[0] + 1024)); + else + return (-1); +} + + +/* + * get value raw text + * + */ +intptr_t get_raw_value (char sep) +{ + char c; + char tmp[LINESIZE + 1]; + char *ptr; + intptr_t level; + intptr_t flag; + intptr_t start; + int is_address = 0; + int had_address = 0; + + flag = 0; + level = 0; + start = const_data_idx; + ptr = tmp; + + for (;;) { + c = ch(); + + /* discard blanks */ + if ((c == ' ') || (c == '\t')) { + gch(); + continue; + } + /* string */ + if (c == '\"') { + for (;;) { + gch(); + + /* add char */ + if (const_data_idx < MAX_CONST_DATA) + const_data[const_data_idx++] = c; + + /* next */ + c = ch(); + + if ((c == 0) || (c == '\"')) + break; + } + } + /* parenthesis */ + if (c == '(') + level++; + else if (c == ')') + level--; + /* comma separator */ + else if (c == sep) { + if (level == 0) + break; + } + /* end */ + else if ((c == 0) || (c == '}')) { + if (level) + error("syntax error"); + break; + } + + /* parse */ + if (an(c)) { + flag = 1; + *ptr++ = c; + } + else { + /* add buffer */ + if (flag) { + flag = 0; + *ptr = '\0'; + ptr = tmp; + had_address += add_buffer(tmp, c, is_address); + is_address = 0; + if ((c == '+' || c == '-') && had_address) { + /* Initializers are passed almost + verbatim to the assembler, which + doesn't know anything about types + and thus doesn't know how to do + pointer arithmetic correctly, so + we don't allow it. */ + error("pointer arithmetic in initializers not supported"); + return (0); + } + } + + /* add char */ + if (c == '&') { + /* we want the succeeding identifier's address */ + is_address = 1; + /* we need to remember that we had an address + somewhere so we can barf if the identifier + contains arithmetic */ + had_address = 1; + } + else if (const_data_idx < MAX_CONST_DATA) + const_data[const_data_idx++] = c; + } + gch(); + } + /* add buffer */ + if (flag) { + *ptr = '\0'; + add_buffer(tmp, c, is_address); + } + /* close string */ + if (const_data_idx < MAX_CONST_DATA) + const_data[const_data_idx++] = '\0'; + + return (start); +} + + +/* + * add a string to the constant pool + * handle underscore + * + */ +int add_buffer (char *p, char c, int is_address) +{ + SYMBOL *s = 0; + + /* underscore */ + if (alpha(*p)) { + if (!is_address) { + s = findglb(p); + if (!s) { + error("undefined global"); + return (0); + } + /* Unless preceded by an address operator, we + need to get the value, and it better be + constant... */ + p = get_const(s); + if (!p) { + error("non-constant initializer"); + return (0); + } + } + else if (c != '(') { + /* If we want the address, we need an underscore + prefix. */ + if (const_data_idx < MAX_CONST_DATA) + const_data[const_data_idx++] = '_'; + } + } + + /* string */ + while (*p) { + if (const_data_idx < MAX_CONST_DATA) + const_data[const_data_idx++] = *p; + p++; + } + + /* tell the caller if there were any addresses involved */ + return ((s && s->ident == POINTER) || is_address); +} + +char *get_const (SYMBOL *s) +{ + int i; + struct const_array *const_ptr; + + if (const_nb) { + const_ptr = const_var; + + for (i = 0; i < const_nb; i++) { + if (const_ptr->sym == s) { + int j = const_val[const_ptr->data]; + if (j >= 0) + return (&const_data[j]); + else + return (0); + } + const_ptr++; + } + } + return (0); +} + +/* + * dump the constant pool + * + */ +void dump_const (void) +{ + intptr_t i, j, k; + intptr_t size; + +/* intptr_t c; */ + + if (const_nb) { + const_ptr = const_var; + + for (i = 0; i < const_nb; i++) { + size = const_ptr->size; + cptr = const_ptr->sym; + cptr->storage = EXTERN; + prefix(); + outstr(cptr->name); + outstr(":"); + nl(); + j = const_ptr->data; + + while (size) { + k = const_val[j++]; + + if ((cptr->type == CCHAR || cptr->type == CUCHAR) && + cptr->ident != POINTER && + !(cptr->ident == ARRAY && cptr->ptr_order > 0)) { + defbyte(); + const_size += 1; + } + else { + defword(); + const_size += 2; + } + if ((k == -1) || (k >= MAX_CONST_DATA)) + outstr("0"); + else if (k <= -1024) { + k = (-k) - 1024; + outlabel(litlab); + outbyte('+'); + outdec(k); + } + else + outstr(&const_data[k]); + nl(); + size--; + } + const_ptr++; + } + } +} diff --git a/src/huc/const.h b/src/huc/const.h new file mode 100644 index 00000000..e7ca709f --- /dev/null +++ b/src/huc/const.h @@ -0,0 +1,19 @@ +/* File const.h: 2.1 (00/07/17,16:02:19) */ +/*% cc -O -c % + * + */ + +#ifndef _CONST_H +#define _CONST_H + +void new_const (void); +void add_const (intptr_t typ); +intptr_t array_initializer (intptr_t typ, intptr_t id, intptr_t stor); +intptr_t scalar_initializer (intptr_t typ, intptr_t id, intptr_t stor); +intptr_t get_string_ptr (intptr_t typ); +intptr_t get_raw_value (char sep); +int add_buffer (char *p, char c, int is_address); +void dump_const (void); +char *get_const (SYMBOL *); + +#endif diff --git a/src/huc/data.c b/src/huc/data.c new file mode 100644 index 00000000..c4d77375 --- /dev/null +++ b/src/huc/data.c @@ -0,0 +1,122 @@ +/* File data.c: 2.2 (84/11/27,16:26:13) */ +/*% cc -O -c % + * + */ + +#include +#include +#include "defs.h" + +/* constant arrays storage */ + +struct const_array *const_ptr; +struct const_array const_var[MAX_CONST]; +intptr_t const_val[MAX_CONST_VALUE]; +char const_data[MAX_CONST_DATA]; +intptr_t const_val_start; +intptr_t const_val_idx; +intptr_t const_data_start; +intptr_t const_data_idx; +intptr_t const_size; +intptr_t const_nb; + +/* storage words */ + +SYMBOL symtab[SYMTBSZ]; +SYMBOL *glbptr, *rglbptr, *locptr; +intptr_t ws[WSTABSZ]; +intptr_t *wsptr; +intptr_t swstcase[SWSTSZ]; +intptr_t swstlab[SWSTSZ]; +intptr_t swstp; +char litq[LITABSZ]; +char litq2[LITABSZ]; +intptr_t litptr; +struct macro macq[MACQSIZE]; +intptr_t macptr; +char line[LINESIZE]; +char mline[LINESIZE]; +intptr_t lptr, mptr; + +TAG_SYMBOL tag_table[NUMTAG]; // start of structure tag table +int tag_table_index; // ptr to next entry + +SYMBOL member_table[NUMMEMB]; // structure member table +int member_table_index; // ptr to next member + +char asmdefs[LITABSZ]; + +/* miscellaneous storage */ + +intptr_t nxtlab, + litlab, + stkp, + zpstkp, + argstk, + ncmp, + errcnt, + glbflag, + indflg, + ctext, + cmode, + lastst, + overlayflag, + optimize, + globals_h_in_process; + +intptr_t top_level_stkp; + +FILE *input, *input2, *output; +FILE *inclstk[INCLSIZ]; + +char inclstk_name[INCLSIZ][FILENAMESIZE]; +char fname_copy[FILENAMESIZE]; +char user_outfile[FILENAMESIZE]; +intptr_t inclstk_line[INCLSIZ]; +intptr_t line_number; + +intptr_t inclsp; +char fname[FILENAMESIZE]; + +char quote[2]; +char *cptr; +intptr_t *iptr; +intptr_t fexitlab; +intptr_t iflevel, skiplevel; +intptr_t errfile; +intptr_t sflag; +intptr_t cdflag; +intptr_t verboseflag; +intptr_t startup_incl; +intptr_t errs; + +int norecurse = 0; +intptr_t locals_ptr; + +struct type *typedefs; +int typedef_ptr = 0; + +struct clabel *clabels; +int clabel_ptr = 0; + +struct enum_s *enums; +int enum_ptr = 0; +struct enum_type *enum_types; +int enum_type_ptr = 0; + +int user_short_enums = 1; +int user_signed_char = 0; + +intptr_t output_globdef; +int have_irq_handler; +int have_sirq_handler; + +int need_map_call_bank; + +char **leaf_functions = 0; +int leaf_cnt = 0; +int leaf_size = 0; + +INITIALS initials_table[NUMGLBS]; +char initials_data_table[INITIALS_SIZE]; // 5kB space for initialisation data +int initials_idx = 0, initials_data_idx = 0; diff --git a/src/huc/data.h b/src/huc/data.h new file mode 100644 index 00000000..a7c0c593 --- /dev/null +++ b/src/huc/data.h @@ -0,0 +1,120 @@ +/* File data.h: 2.2 (84/11/27,16:26:11) */ + +#include +#include + +#include "defs.h" + +/* constant arrays storage */ + +extern struct const_array *const_ptr; +extern struct const_array const_var[MAX_CONST]; +extern intptr_t const_val[MAX_CONST_VALUE]; +extern char const_data[MAX_CONST_DATA]; +extern intptr_t const_val_start; +extern intptr_t const_val_idx; +extern intptr_t const_data_start; +extern intptr_t const_data_idx; +extern intptr_t const_size; +extern intptr_t const_nb; + +/* storage words */ + +extern SYMBOL symtab[]; +extern SYMBOL *glbptr, *rglbptr, *locptr; +extern intptr_t ws[]; +extern intptr_t *wsptr; +extern intptr_t swstcase[]; +extern intptr_t swstlab[]; +extern intptr_t swstp; +extern char litq[]; +extern char litq2[]; +extern intptr_t litptr; +extern struct macro macq[]; +extern intptr_t macptr; +extern char line[]; +extern char mline[]; +extern intptr_t lptr, mptr; + +extern TAG_SYMBOL tag_table[NUMTAG]; // start of structure tag table +extern int tag_table_index; // ptr to next entry + +extern SYMBOL member_table[NUMMEMB]; // structure member table +extern int member_table_index; // ptr to next member< + +extern char asmdefs[]; + +/* miscellaneous storage */ + +extern intptr_t nxtlab, + litlab, + stkp, + zpstkp, + argstk, + ncmp, + errcnt, + glbflag, + indflg, + ctext, + cmode, + lastst, + overlayflag, + optimize, + globals_h_in_process; + +extern FILE *input, *input2, *output; +extern FILE *inclstk[]; + +extern char inclstk_name[INCLSIZ][FILENAMESIZE]; +extern intptr_t inclstk_line[]; +extern char fname_copy[FILENAMESIZE]; +extern char user_outfile[FILENAMESIZE]; +extern intptr_t line_number; + +extern intptr_t inclsp; +extern char fname[]; + +extern char quote[]; +extern SYMBOL *cptr; +extern intptr_t *iptr; +extern intptr_t fexitlab; +extern intptr_t iflevel, skiplevel; +extern intptr_t errfile; +extern intptr_t sflag; +extern intptr_t cdflag; +extern intptr_t verboseflag; +extern intptr_t startup_incl; +extern intptr_t errs; + +extern intptr_t top_level_stkp; +extern int norecurse; +extern intptr_t locals_ptr; +extern char current_fn[]; + +extern struct type *typedefs; +extern int typedef_ptr; + +extern struct clabel *clabels; +extern int clabel_ptr; + +extern struct enum_s *enums; +extern int enum_ptr; +extern struct enum_type *enum_types; +extern int enum_type_ptr; + +extern int user_short_enums; +extern int user_signed_char; + +extern intptr_t output_globdef; +extern int have_irq_handler; +extern int have_sirq_handler; + +extern int need_map_call_bank; + +extern char **leaf_functions; +extern int leaf_cnt; +extern int leaf_size; + +extern INITIALS initials_table[NUMGLBS]; +extern char initials_data_table[INITIALS_SIZE]; // 5kB space for initialisation data +extern int initials_idx, initials_data_idx; diff --git a/src/huc/defs.h b/src/huc/defs.h new file mode 100644 index 00000000..3b5b62b8 --- /dev/null +++ b/src/huc/defs.h @@ -0,0 +1,433 @@ +/* File defs.h: 2.1 (83/03/21,02:07:20) */ + +#ifndef INCLUDE_DEFS_H +#define INCLUDE_DEFS_H + +/* + * INTSIZE is the size of an integer in the target machine + * BYTEOFF is the offset of an byte within an integer on the + * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, + * 360 = 3) + * This compiler assumes that an integer is the SAME length as + * a pointer - in fact, the compiler uses INTSIZE for both. + */ + +#define INTSIZE 2 +#define BYTEOFF 0 + +/* pseudo instruction arg types */ +#define T_NOP -1 +#define T_VALUE 1 +#define T_LABEL 2 +#define T_SYMBOL 3 +#define T_PTR 4 +#define T_STACK 5 +#define T_STRING 6 +#define T_LIB 7 +#define T_SIZE 8 +#define T_BANK 9 +#define T_VRAM 10 +#define T_PAL 11 +#define T_LITERAL 12 + +/* basic pseudo instructions */ +#define I_LDB 1 +#define I_LDBP 2 +#define I_LDW 3 +#define I_LDWI 4 +#define I_LDWP 5 +#define I_STB 6 +#define I_STBPS 7 +#define I_STW 8 +#define I_STWPS 9 +#define I_ADDWI 10 +#define I_ADDWS 11 +#define I_ADDMI 12 +#define I_SUBWI 13 +#define I_SUBWS 14 +#define I_ORWS 15 +#define I_EORWS 16 +#define I_ANDWS 17 +#define I_ASLW 18 +#define I_ASLWS 19 +#define I_ASRW 20 +#define I_COMW 21 +#define I_NEGW 22 +#define I_SWAPW 23 +#define I_EXTW 24 +#define I_BOOLW 25 +#define I_NOTW 26 +#define I_JMP 27 +#define I_JSR 28 +#define I_RTS 29 +#define I_CALL 30 +#define I_CALLS 31 +#define I_PUSHW 32 +#define I_POPW 33 +#define I_TSTW 34 +#define I_LBRA 35 +#define I_LBEQ 36 +#define I_LBNE 37 +#define I_BANK 38 +#define I_OFFSET 39 +#define I_FARPTR 40 +#define I_FARPTR_I 41 +#define I_FARPTR_GET 42 +#define I_FGETB 43 +#define I_FGETW 44 +#define I_VGETW 45 +#define I_VPUTW 46 +#define I_INCW 50 +#define I_ANDWI 51 +#define I_ORWI 52 +#define I_ADDW 53 +#define I_SUBW 54 +#define I_LDUB 55 +#define I_LDUBP 56 +#define I_FGETUB 57 +#define I_ADDBS 58 +#define I_ADDBI 59 +#define I_LABEL 60 +#define I_STWIP 61 +#define I_STBIP 62 +#define I_MULWI 63 +#define I_STWI 64 +#define I_STBI 65 +#define I_ASLWI 66 +#define I_LSRWI 67 +#define I_ASRWI 68 +#define I_LBEQN 69 +#define I_LBNEN 70 +#define I_LBRAN 71 +#define I_LDYB 72 +#define I_LDBY 73 +#define I_ADDB 74 +#define I_ADDUB 75 +#define I_ADDBI_P 76 +#define I_INCB 77 +#define I_STWZ 78 +#define I_STBZ 79 +#define I_CMPWI_EQ 80 +#define I_CMPWI_NE 81 +#define I_STBP 82 +#define I_STWP 83 +#define I_EORWI 84 +#define I_SAVEW 85 +#define I_SAVEB 86 +#define I_RESW 87 +#define I_RESB 88 +#define I_EXTUW 89 +#define I_DEF 90 +#define I_SEI 91 +#define I_CLI 92 +#define I_MAPCBANK 93 +#define I_UNMAPCBANK 94 +#define I_MACRO 95 // Used to fastcall macro calling support + +/* optimized pseudo instructions */ +#define X_MASK 0xFFFF0 +#define X_LDB 0x10000 +#define X_LDB_S 0x10001 +#define X_LDB_P 0x10002 +#define X_LDW_S 0x10011 +#define X_LDD_I 0x10100 +#define X_LDD_B 0x10101 +#define X_LDD_W 0x10102 +#define X_LDD_S_B 0x10105 +#define X_LDD_S_W 0x10106 +#define X_LEA_S 0x10021 +#define X_PEA 0x10030 +#define X_PEA_S 0x10031 +#define X_PUSHW_A 0x10040 /* XXX: unused? */ +#define X_STB_S 0x10051 +#define X_STW_S 0x10061 +#define X_STBI_S 0x10071 +#define X_STWI_S 0x10081 +#define X_ADDW_S 0x10091 +#define X_INCW_S 0x100A1 +#define X_DECW_S 0x100B1 +#define X_LDUB 0x10003 +#define X_LDUB_S 0x10004 +#define X_LDUB_P 0x10005 +#define X_ADDB_S 0x100C1 +#define X_ADDUB_S 0x100D1 +#define X_INCB_S 0x100E1 + +#define FOREVER for (;;) +#define FALSE 0 +#define TRUE 1 +#define NO 0 +#define YES 1 + +/* miscellaneous */ + +#define EOS 0 +#define EOL 10 +#define BKSP 8 +#define CR 13 +#define FFEED 12 +#define TAB 9 + +#define FILENAMESIZE 256 + +/* symbol table parameters */ + +/* old values, too restrictive + * #define SYMSIZ 14 + * #define SYMTBSZ 32768 + * #define NUMGLBS 1500 + */ +#define SYMTBSZ 4096 +#define NUMGLBS 2048 + +#define STARTGLB symtab +#define ENDGLB (STARTGLB + NUMGLBS) +#define STARTLOC (ENDGLB + 1) +#define ENDLOC (symtab + SYMTBSZ - 1) + +/* symbol table entry format */ +/* N.B. nasty hack to allow space beyond NAMEMAX (see "copysym") */ + +#define NAMESIZE 48 +#define NAMEMAX 47 +#define NAMEALLOC 64 + +struct symbol { + char name[NAMEALLOC]; + char ident; + char type; + char storage; + char far; + short offset; + short tagidx; + int size; + int ptr_order; +}; + +typedef struct symbol SYMBOL; + +#define NUMTAG 64 + +struct tag_symbol { + char name[NAMESIZE]; // structure tag name + int size; // size of struct in bytes + int member_idx; // index of first member + int number_of_members; // number of tag members +}; +#define TAG_SYMBOL struct tag_symbol + +#define NULL_TAG 0 + +// Define the structure member table parameters +#define NUMMEMB 256 + +/* possible entries for "ident" */ + +#define VARIABLE 1 +#define ARRAY 2 +#define POINTER 3 +#define FUNCTION 4 + +/* possible entries for "type" */ + +#define CCHAR 1 +#define CINT 2 +#define CVOID 3 +#define CSTRUCT 4 +#define CENUM 5 +#define CSIGNED 0 +#define CUNSIGNED 8 +#define CUINT (CINT | CUNSIGNED) +#define CUCHAR (CCHAR | CUNSIGNED) + +/* possible entries for storage */ + +#define PUBLIC 1 +#define AUTO 2 +#define EXTERN 3 + +#define STATIC 4 +#define LSTATIC 5 +#define DEFAUTO 6 +#define CONST 7 + +#define WRITTEN 128 + +/* "do"/"for"/"while"/"switch" statement stack */ + +#define WSTABSZ 100 +#define WSSIZ 7 +#define WSMAX ws + WSTABSZ - WSSIZ + +/* entry offsets in "do"/"for"/"while"/"switch" stack */ + +#define WSSYM 0 +#define WSSP 1 +#define WSTYP 2 +#define WSCASEP 3 +#define WSTEST 3 +#define WSINCR 4 +#define WSDEF 4 +#define WSBODY 5 +#define WSTAB 5 +#define WSEXIT 6 + +/* possible entries for "wstyp" */ + +#define WSWHILE 0 +#define WSFOR 1 +#define WSDO 2 +#define WSSWITCH 3 + +/* "switch" label stack */ + +#define SWSTSZ 256 + +/* literal pool */ + +#define LITABSZ 8192 +#define LITMAX LITABSZ - 1 + +/* input string */ + +#define LITMAX2 LITABSZ - 1 + +/* input line */ + +#define LINESIZE 384 +#define LINEMAX (LINESIZE - 1) +#define MPMAX LINEMAX + +/* macro (define) pool */ + +#define MACQSIZE 16384 +#define MACMAX (MACQSIZE - 1) + +struct macro { + char *name; + char **args; + int argc; + struct { + int arg; + int pos; + } *argpos; + char *def; +}; + +/* "include" stack */ + +#define INCLSIZ 3 + +/* statement types (tokens) */ + +#define STIF 1 +#define STWHILE 2 +#define STRETURN 3 +#define STBREAK 4 +#define STCONT 5 +#define STASM 6 +#define STEXP 7 +#define STDO 8 +#define STFOR 9 +#define STSWITCH 10 +#define STGOTO 11 + +/* pseudo instruction structure */ + +typedef struct { + intptr_t code; + intptr_t type; + intptr_t data; + intptr_t imm_type; + intptr_t imm_data; + char *arg[3]; + SYMBOL *sym; +} INS; + +/* constant array struct */ + +#define MAX_CONST 1024 +#define MAX_CONST_VALUE 8192 +#define MAX_CONST_DATA 65536 + +struct const_array { + SYMBOL *sym; + intptr_t typ; + intptr_t size; + intptr_t data; +}; + +/* fastcall func struct */ + +#define MAX_FASTCALL_ARGS 8 +#define FASTCALL_NOP 0x01 // bitmask values +#define FASTCALL_MACRO 0x04 // bitmask values + +struct fastcall { + struct fastcall *next; + char fname[NAMESIZE]; + intptr_t nargs; + intptr_t flags; + char argtype[MAX_FASTCALL_ARGS]; + char argname[MAX_FASTCALL_ARGS][NAMESIZE]; +}; + +// initialisation of global variables +#define INIT_TYPE NAMESIZE +#define INIT_LENGTH NAMESIZE + 1 +#define INITIALS_SIZE 5 * 1024 + +struct initials_table { + char name[NAMESIZE]; // symbol name + int type; // type + int dim; // length of data (possibly an array) + int data_len; // index of tag or zero +}; +#define INITIALS struct initials_table + +SYMBOL *find_member (TAG_SYMBOL *tag, char *sname); + +struct lvalue { + SYMBOL *symbol; + intptr_t indirect; + intptr_t ptr_type; + SYMBOL *symbol2; + intptr_t value; + TAG_SYMBOL *tagsym; + int ptr_order; + int type; +}; +#define LVALUE struct lvalue + +#define W_GENERAL 1 + +struct type { + int type; + int ident; + int ptr_order; + int otag; + int flags; + char sname[NAMESIZE]; +}; +#define F_REGISTER 1 +#define F_CONST 2 +#define F_VOLATILE 4 +#define F_STRUCT 8 /* set if CSTRUCT is struct, not union */ + +struct clabel { + char name[NAMESIZE]; + int stkp; + int label; +}; + +struct enum_s { + char name[NAMESIZE]; + int value; +}; +struct enum_type { + char name[NAMESIZE]; + int start; + int base; +}; + +#endif diff --git a/src/huc/enum.c b/src/huc/enum.c new file mode 100644 index 00000000..6344fad1 --- /dev/null +++ b/src/huc/enum.c @@ -0,0 +1,107 @@ +/* Copyright (c) 2014, Ulrich Hecht + All rights reserved. + See LICENSE for details on use and redistribution. */ + +#include +#include +#include +#include "data.h" +#include "error.h" +#include "io.h" +#include "lex.h" +#include "primary.h" +#include "sym.h" + +int define_enum (char *sname, int storage) +{ + char n[NAMESIZE]; + int count, min, max; + int start = enum_ptr; + + printf("defenum %s\n", sname); + needbrack("{"); + count = min = max = 0; + for (;;) { + if (!symname(n)) { + illname(); + return (-1); + } + /* Add to global table of enum values. */ + enums = realloc(enums, (enum_ptr + 1) * sizeof(*enums)); + strcpy(enums[enum_ptr].name, n); + /* optional initializer */ + if (match("=")) { + intptr_t num; + if (const_expr(&num, ",", "}")) + count = num; + } + /* Remember minima and maxima to find the shortest type. */ + if (count > max) max = count; + if (count < min) min = count; + enums[enum_ptr].value = count++; + enum_ptr++; + if (match("}")) + break; + if (!match(",")) { + error("expected comma"); + return (-1); + } + if (match("}")) + break; + } + /* Add to table of enum types. */ + enum_types = realloc(enum_types, (enum_type_ptr + 1) * sizeof(*enum_types)); + struct enum_type *et = &enum_types[enum_type_ptr]; + if (sname) + strcpy(et->name, sname); + else + et->name[0] = 0; + et->start = start; + if (!user_short_enums) { + et->base = CINT; + if (min < -32768 || max > 32767) + warning(W_GENERAL, "enum range too large"); + } + else if (min < 0) { + if (min < -128 || max > 127) { + et->base = CINT; + if (min < -32768 || max > 32767) + warning(W_GENERAL, "enum range too large"); + } + et->base = CCHAR; + } + else { + if (max > 65535) + warning(W_GENERAL, "enum range too large"); + if (max > 127) + et->base = CUINT; + else + et->base = CUCHAR; + } + printf("enum base type %d\n", et->base); + return (enum_type_ptr++); +} + +int find_enum_type (char *name) +{ + int i; + + for (i = 0; i < enum_type_ptr; i++) { + if (!strcmp(enum_types[i].name, name)) + return (i); + } + return (-1); +} + +int find_enum (char *sname, intptr_t *val) +{ + int i; + + for (i = 0; i < enum_ptr; i++) { + if (!strcmp(sname, enums[i].name)) { + *val = enums[i].value; + return (1); + } + } + return (0); +} diff --git a/src/huc/enum.h b/src/huc/enum.h new file mode 100644 index 00000000..16a4ae6d --- /dev/null +++ b/src/huc/enum.h @@ -0,0 +1,3 @@ +int define_enum (char *sname, int storage); +int find_enum_type (char *name); +int find_enum (char *sname, intptr_t *val); diff --git a/src/huc/error.c b/src/huc/error.c new file mode 100644 index 00000000..f0494f80 --- /dev/null +++ b/src/huc/error.c @@ -0,0 +1,83 @@ +/* File error.c: 2.1 (83/03/20,16:02:00) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "error.h" +#include "io.h" + +void error (char *ptr) +{ + FILE *tempfile; + + if (output == NULL) { + fprintf(stderr, "%s\n", ptr); + exit(1); + } + + tempfile = output; + output = stderr; + doerror(ptr, 0); + output = tempfile; + errcnt++; + if (errcnt > 3) { + errcnt = 0; + error("too many errors, aborting"); + exit(1); + } +} + +void warning (int type, char *text) +{ + FILE *tfp; + + assert(type > 0); + tfp = output; + output = stderr; + doerror(text, type); + output = tfp; +} + +void doerror (char *ptr, int type) +{ + intptr_t k; + + comment(); + if (!type) + outstr("error: "); + else + outstr("warning: "); + if (inclsp) + outstr(inclstk_name[inclsp - 1]); + else + outstr(fname_copy); + outbyte('('); + outdec(line_number); + outbyte(')'); + nl(); + comment(); + outstr(line); + nl(); + comment(); + k = 0; + while (k < lptr) { + if (line[k] == 9) + tab(); + else + outbyte(' '); + k++; + } + outbyte('^'); + nl(); + comment(); + outstr("****** "); + outstr(ptr); + outstr(" ******"); + nl(); +} diff --git a/src/huc/error.h b/src/huc/error.h new file mode 100644 index 00000000..1bd4e119 --- /dev/null +++ b/src/huc/error.h @@ -0,0 +1,9 @@ +#ifndef _INCLUDE_ERROR_H +#define _INCLUDE_ERROR_H + +void error (char *); +void warning (int, char *); + +void doerror (char *, int); + +#endif diff --git a/src/huc/expr.c b/src/huc/expr.c new file mode 100644 index 00000000..0a800b1c --- /dev/null +++ b/src/huc/expr.c @@ -0,0 +1,950 @@ +/* File expr.c: 2.2 (83/06/21,11:24:26) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "code.h" +#include "error.h" +#include "expr.h" +#include "function.h" +#include "gen.h" +#include "io.h" +#include "lex.h" +#include "primary.h" +#include "sym.h" + +/* + * lval->symbol - symbol table address, else 0 for constant + * lval->indirect - type indirect object to fetch, else 0 for static object + * lval->ptr_type - type pointer or array, else 0 + */ +void expression (int comma) +{ + LVALUE lval[1] = {{0}}; + + expression_ex(lval, comma, NO); +} + +intptr_t expression_ex (LVALUE *lval, int comma, int norval) +{ + intptr_t k; + + do { + if ((k = heir1(lval, comma)) && !norval) + rvalue(lval); + if (!comma) + return (k); + } while (match(",")); + return (k); +} + +static int is_unsigned (LVALUE *lval) +{ + if (lval->type && !(lval->type & CUNSIGNED)) + return (0); + + /* C only promotes operations with an unsigned int + to unsigned, not unsigned char! */ + if (lval->type == CUINT) + return (1); + + if (lval->symbol && lval->symbol->type == CUINT) + return (1); + + return (0); +} + +static void gen_scale_right (LVALUE *lval, LVALUE *lval2) +{ + if (dbltest(lval, lval2)) { + if (lval->tagsym) { + TAG_SYMBOL *tag = (TAG_SYMBOL *)(lval->tagsym); + if (tag->size == 2) + gaslint(); + else if (tag->size > 1) + gmult_imm(tag->size); + } + else + gaslint(); + } +} + +static int is_ptrptr (LVALUE *lval) +{ + SYMBOL *s = lval->symbol; + + return (s && (s->ptr_order > 1 || (s->ident == ARRAY && s->ptr_order > 0))); +} + +intptr_t heir1 (LVALUE *lval, int comma) +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + char fc; + + k = heir1a(lval, comma); + if (match("=")) { + if (k == 0) { + needlval(); + return (0); + } + if (lval->indirect) + gpush(); + if (heir1(lval2, comma)) + rvalue(lval2); + store(lval); + return (0); + } + else { + fc = ch(); + if (match("-=") || + match("+=") || + match("*=") || + match("/=") || + match("%=") || + match(">>=") || + match("<<=") || + match("&=") || + match("^=") || + match("|=")) { + if (k == 0) { + needlval(); + return (0); + } + if (lval->indirect) + gpush(); + rvalue(lval); + gpush(); + if (heir1(lval2, comma)) + rvalue(lval2); + switch (fc) { + case '-': { + gen_scale_right(lval, lval2); + gsub(); + result(lval, lval2); + break; + } + case '+': { + gen_scale_right(lval, lval2); + gadd(lval, lval2); + result(lval, lval2); + break; + } + case '*': gmult(is_unsigned(lval) || is_unsigned(lval2)); break; + case '/': gdiv(is_unsigned(lval) || is_unsigned(lval2)); break; + case '%': gmod(is_unsigned(lval) || is_unsigned(lval2)); break; + case '>': gasr(is_unsigned(lval)); break; + case '<': gasl(); break; + case '&': gand(); break; + case '^': gxor(); break; + case '|': gor(); break; + } + store(lval); + return (0); + } + else + return (k); + } +} + +intptr_t heir1a (LVALUE *lval, int comma) +/* intptr_t lval[]; */ +{ + intptr_t k, lab1, lab2; + LVALUE lval2[1] = {{0}}; + + k = heir1b(lval, comma); + blanks(); + if (ch() != '?') + return (k); + + if (k) + rvalue(lval); + FOREVER + if (match("?")) { + testjump(lab1 = getlabel(), FALSE); + if (heir1b(lval2, comma)) + rvalue(lval2); + jump(lab2 = getlabel()); + gnlabel(lab1); + blanks(); + if (!match(":")) { + error("missing colon"); + return (0); + } + if (heir1b(lval2, comma)) + rvalue(lval2); + gnlabel(lab2); + } + else + return (0); +} + +intptr_t heir1b (LVALUE *lval, int comma) +/*intptr_t lval[]; */ +{ + intptr_t k, lab; + LVALUE lval2[1] = {{0}}; + + k = heir1c(lval, comma); + blanks(); + if (!sstreq("||")) + return (k); + + if (k) + rvalue(lval); + FOREVER + if (match("||")) { + testjump(lab = getlabel(), TRUE); + if (heir1c(lval2, comma)) + rvalue(lval2); + gnlabel(lab); + gbool(); + } + else + return (0); +} + +intptr_t heir1c (LVALUE *lval, int comma) +/*intptr_t lval[]; */ +{ + intptr_t k, lab; + LVALUE lval2[1] = {{0}}; + + k = heir2(lval, comma); + blanks(); + if (!sstreq("&&")) + return (k); + + if (k) + rvalue(lval); + FOREVER + if (match("&&")) { + testjump(lab = getlabel(), FALSE); + if (heir2(lval2, comma)) + rvalue(lval2); + gnlabel(lab); + gbool(); + } + else + return (0); +} + +intptr_t heir2 (LVALUE *lval, int comma) +/*intptr_t lval[]; */ +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + + k = heir3(lval, comma); + blanks(); + if ((ch() != '|') || (nch() == '|') || (nch() == '=')) + return (k); + + if (k) + rvalue(lval); + FOREVER { + if ((ch() == '|') && (nch() != '|') && (nch() != '=')) { + inbyte(); + gpush(); + if (heir3(lval2, comma)) + rvalue(lval2); + gor(); + blanks(); + } + else + return (0); + } +} + +intptr_t heir3 (LVALUE *lval, int comma) +/* intptr_t lval[]; */ +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + + k = heir4(lval, comma); + blanks(); + if ((ch() != '^') || (nch() == '=')) + return (k); + + if (k) + rvalue(lval); + FOREVER { + if ((ch() == '^') && (nch() != '=')) { + inbyte(); + gpush(); + if (heir4(lval2, comma)) + rvalue(lval2); + gxor(); + blanks(); + } + else + return (0); + } +} + +intptr_t heir4 (LVALUE *lval, int comma) +/* intptr_t lval[]; */ +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + + k = heir5(lval, comma); + blanks(); + if ((ch() != '&') || (nch() == '|') || (nch() == '=')) + return (k); + + if (k) + rvalue(lval); + FOREVER { + if ((ch() == '&') && (nch() != '&') && (nch() != '=')) { + inbyte(); + gpush(); + if (heir5(lval2, comma)) + rvalue(lval2); + gand(); + blanks(); + } + else + return (0); + } +} + +int is_byte (LVALUE *lval) +{ + if (lval->symbol && !lval->ptr_type && + (lval->symbol->type == CCHAR || lval->symbol->type == CUCHAR)) + return (1); + + return (0); +} + +intptr_t heir5 (LVALUE *lval, int comma) +/*intptr_t lval[]; */ +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + + k = heir6(lval, comma); + blanks(); + if ((!sstreq("==")) && + (!sstreq("!="))) + return (k); + + if (k) + rvalue(lval); + FOREVER { + if (match("==")) { + gpush(); + if (heir6(lval2, comma)) + rvalue(lval2); + geq(is_byte(lval) && is_byte(lval2)); + } + else if (match("!=")) { + gpush(); + if (heir6(lval2, comma)) + rvalue(lval2); + gne(is_byte(lval) && is_byte(lval2)); + } + else + return (0); + } +} + +intptr_t heir6 (LVALUE *lval, int comma) +/* intptr_t lval[]; */ +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + + k = heir7(lval, comma); + blanks(); + if (!sstreq("<") && + !sstreq("<=") && + !sstreq(">=") && + !sstreq(">")) + return (k); + + if (sstreq("<<") || sstreq(">>")) + return (k); + + if (k) + rvalue(lval); + FOREVER { + if (match("<=")) { + gpush(); + if (heir7(lval2, comma)) + rvalue(lval2); + if (lval->ptr_type || lval2->ptr_type || + is_unsigned(lval) || + is_unsigned(lval2) + ) { + gule(is_byte(lval) && is_byte(lval2)); + continue; + } + gle(is_byte(lval) && is_byte(lval2)); + } + else if (match(">=")) { + gpush(); + if (heir7(lval2, comma)) + rvalue(lval2); + if (lval->ptr_type || lval2->ptr_type || + is_unsigned(lval) || + is_unsigned(lval2) + ) { + guge(is_byte(lval) && is_byte(lval2)); + continue; + } + gge(is_byte(lval) && is_byte(lval2)); + } + else if ((sstreq("<")) && + !sstreq("<<")) { + inbyte(); + gpush(); + if (heir7(lval2, comma)) + rvalue(lval2); + if (lval->ptr_type || lval2->ptr_type || + is_unsigned(lval) || + is_unsigned(lval2) + ) { + gult(is_byte(lval) && is_byte(lval2)); + continue; + } + glt(is_byte(lval) && is_byte(lval2)); + } + else if ((sstreq(">")) && + !sstreq(">>")) { + inbyte(); + gpush(); + if (heir7(lval2, comma)) + rvalue(lval2); + if (lval->ptr_type || lval2->ptr_type || + is_unsigned(lval) || + is_unsigned(lval2) + ) { + gugt(is_byte(lval) && is_byte(lval2)); + continue; + } + ggt(is_byte(lval) && is_byte(lval2)); + } + else + return (0); + + blanks(); + } +} + +intptr_t heir7 (LVALUE *lval, int comma) +/*intptr_t lval[]; */ +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + + k = heir8(lval, comma); + blanks(); + if ((!sstreq(">>") && !sstreq("<<")) || + sstreq(">>=") || sstreq("<<=")) + return (k); + + if (k) + rvalue(lval); + FOREVER { + if (sstreq(">>") && !sstreq(">>=")) { + inbyte(); inbyte(); + gpush(); + if (heir8(lval2, comma)) + rvalue(lval2); + gasr(is_unsigned(lval)); + } + else if (sstreq("<<") && !sstreq("<<=")) { + inbyte(); inbyte(); + gpush(); + if (heir8(lval2, comma)) + rvalue(lval2); + gasl(); + } + else + return (0); + + blanks(); + } +} + +intptr_t heir8 (LVALUE *lval, int comma) +/*intptr_t lval[]; */ +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + + k = heir9(lval, comma); + blanks(); + if (((ch() != '+') && (ch() != '-')) || (nch() == '=')) + return (k); + + if (k) + rvalue(lval); + FOREVER { + if (match("+")) { + gpush(); + if (heir9(lval2, comma)) + rvalue(lval2); + /* if left is pointer and right is int, scale right */ + gen_scale_right(lval, lval2); + /* will scale left if right int pointer and left int */ + gadd(lval, lval2); + result(lval, lval2); + } + else if (match("-")) { + gpush(); + if (heir9(lval2, comma)) + rvalue(lval2); + /* if dbl, can only be: pointer - int, or + pointer - pointer, thus, + in first case, int is scaled up, + in second, result is scaled down. */ + gen_scale_right(lval, lval2); + gsub(); + /* if both pointers, scale result */ + if ((lval->ptr_type == CINT || lval->ptr_type == CUINT || is_ptrptr(lval)) && + (lval2->ptr_type == CINT || lval2->ptr_type == CUINT || is_ptrptr(lval2))) + gasrint(); /* divide by intsize */ + else if (lval->ptr_type == CSTRUCT && lval2->ptr_type == CSTRUCT) { + TAG_SYMBOL *tag = lval->tagsym; + if (tag->size == 2) + gasrint(); + else if (tag->size > 1) + gdiv_imm(tag->size); + } + result(lval, lval2); + } + else + return (0); + } +} + +intptr_t heir9 (LVALUE *lval, int comma) +/* intptr_t lval[]; */ +{ + intptr_t k; + LVALUE lval2[1] = {{0}}; + + k = heir10(lval, comma); + blanks(); + if (((ch() != '*') && (ch() != '/') && + (ch() != '%')) || (nch() == '=')) + return (k); + + if (k) + rvalue(lval); + FOREVER { + if (match("*")) { + gpush(); + if (heir10(lval2, comma)) + rvalue(lval2); + gmult(is_unsigned(lval) || is_unsigned(lval2)); + } + else if (match("/")) { + gpush(); + if (heir10(lval2, comma)) + rvalue(lval2); + gdiv(is_unsigned(lval) || is_unsigned(lval2)); + } + else if (match("%")) { + gpush(); + if (heir10(lval2, comma)) + rvalue(lval2); + gmod(is_unsigned(lval) || is_unsigned(lval2)); + } + else + return (0); + } +} + +intptr_t heir10 (LVALUE *lval, int comma) +/* intptr_t lval[]; */ +{ + intptr_t k; + SYMBOL *ptr; + + if (match("++")) { + indflg = 0; + if ((k = heir10(lval, comma)) == 0) { + needlval(); + return (0); + } + if (lval->indirect) + gpush(); + rvalue(lval); + ginc(lval); + store(lval); + return (0); + } + else if (match("--")) { + indflg = 0; + if ((k = heir10(lval, comma)) == 0) { + needlval(); + return (0); + } + if (lval->indirect) + gpush(); + rvalue(lval); + gdec(lval); + store(lval); + return (0); + } + else if (match("-")) { + indflg = 0; + k = heir10(lval, comma); + if (k) + rvalue(lval); + gneg(); + return (0); + } + else if (match("~")) { + indflg = 0; + k = heir10(lval, comma); + if (k) + rvalue(lval); + gcom(); + return (0); + } + else if (match("!")) { + indflg = 0; + k = heir10(lval, comma); + if (k) + rvalue(lval); + glneg(); + return (0); + } + else if (ch() == '*' && nch() != '=') { + inbyte(); + indflg = 1; + k = heir10(lval, comma); + indflg = 0; + ptr = lval->symbol; + /* vram */ + if (ptr && !strcmp(ptr->name, "vram")) { + lval->ptr_type = 0; + lval->ptr_order = 0; + return (1); + } + if (k) + rvalue(lval); + if (lval->ptr_order < 2) + lval->indirect = lval->ptr_type; + else + lval->indirect = CUINT; + /* XXX: what about multiple indirection? */ + if (lval->ptr_order > 1) + lval->ptr_order--; + else { + lval->ptr_type = 0; /* flag as not pointer or array */ + lval->ptr_order = 0; + } + return (1); + } + else if (ch() == '&' && nch() != '&' && nch() != '=') { + indflg = 0; + inbyte(); + k = heir10(lval, comma); + if (k == 0) { + error("illegal address"); + return (0); + } + if (lval->symbol) { + ptr = lval->symbol; + lval->ptr_type = ptr->type; + lval->ptr_order = ptr->ptr_order; + } + lval->ptr_order++; + if (lval->indirect) + return (0); + + /* global and non-array */ + ptr = lval->symbol; + immed(T_SYMBOL, (intptr_t)ptr); + lval->indirect = ptr->type; + return (0); + } + else { + k = heir11(lval, comma); + ptr = lval->symbol; + if (match("++")) { + if (k == 0) { + needlval(); + return (0); + } + /* vram */ + if (ptr && !strcmp(ptr->name, "vram")) + return (0); + + if (lval->indirect) + gpush(); + rvalue(lval); + ginc(lval); + store(lval); + gdec(lval); + return (0); + } + else if (match("--")) { + if (k == 0) { + needlval(); + return (0); + } + /* vram */ + if (ptr && !strcmp(ptr->name, "vram")) { + error("can't decrement vram pointer"); + return (0); + } + if (lval->indirect) + gpush(); + rvalue(lval); + gdec(lval); + store(lval); + ginc(lval); + return (0); + } + else + return (k); + } +} + +intptr_t heir11 (LVALUE *lval, int comma) +/*intptr_t *lval; */ +{ + intptr_t direct, k; + SYMBOL *ptr; + char sname[NAMESIZE]; + + k = primary(lval, comma); + ptr = lval->symbol; + blanks(); + for (;;) { + if (match("[")) { + if (ptr == 0) { + if (lval->ptr_type) { + /* subscription of anonymous array + ATM this can only happen for a + string literal. */ + if (lval->ptr_type != CCHAR) + error("internal error: cannot subscript non-character literals"); + /* Primary contains literal pointer, add subscript. */ + gpush(); + expression(YES); + needbrack("]"); + gadd(NULL, NULL); + /* Dereference final pointer. */ + lval->symbol = lval->symbol2 = 0; + lval->indirect = lval->ptr_type; + if (lval->ptr_order > 1) + lval->ptr_order--; + else { + lval->ptr_type = 0; + lval->ptr_order = 0; + } + k = 1; + continue; + } + else { + error("can't subscript"); + junk(); + needbrack("]"); + return (0); + } + } + else if (ptr->ident == POINTER) + rvalue(lval); + else if (ptr->ident != ARRAY) { + error("can't subscript"); + k = 0; + } + if (!ptr->far) + gpush(); + expression(YES); + needbrack("]"); + if (ptr->type == CINT || ptr->type == CUINT || lval->ptr_order > 1 || + (ptr->ident == ARRAY && lval->ptr_order > 0)) + gaslint(); + else if (ptr->type == CSTRUCT) { + int size = tag_table[ptr->tagidx].size; + if (size == 2) + gaslint(); + else if (size > 1) + gmult_imm(size); + } + if (!ptr->far) + gadd(NULL, NULL); + lval->symbol = 0; + if (lval->ptr_order > 1 || (ptr->ident == ARRAY && lval->ptr_order > 0)) + lval->indirect = CUINT; + else + lval->indirect = ptr->type; + if (lval->ptr_order > 1) + lval->ptr_order--; + else { + blanks(); + if (ptr->ident == ARRAY && ch() == '[') { + /* Back-to-back indexing: We loop + right inside this function, so + nobody else takes care of + actually loading the pointer. */ + rvalue(lval); + lval->indirect = ptr->type; + lval->ptr_type = ptr->type; + lval->ptr_order = 0; + } + else { + lval->type = lval->ptr_type; + lval->ptr_type = 0; // VARIABLE; /* David, bug patch ?? */ + lval->ptr_order = 0; + } + } + lval->symbol2 = ptr->far ? ptr : NULL; + k = 1; + } + else if (match("(")) { + if (ptr == 0) { + error("invalid or unsupported function call"); + callfunction(0); + } + else if (ptr->ident != FUNCTION) { + if (strcmp(ptr->name, "vram") == 0) + callfunction(ptr->name); + else { + if (ptr->far) { + lval->symbol2 = ptr; + immed(T_VALUE, 0); + } + rvalue(lval); + callfunction(0); + } + } + else + callfunction(ptr->name); + k = 0; + /* Encode return type in lval. */ + SYMBOL *s = lval->symbol; + if (s) { + if (s->ptr_order >= 1) { + lval->ptr_type = s->type; + lval->ptr_order = s->ptr_order; + } + if (s->type == CSTRUCT) + lval->tagsym = &tag_table[s->tagidx]; + lval->symbol = 0; + } + } + else if ((direct = match(".")) || match("->")) { + if (lval->tagsym == 0) { + error("can't take member"); + junk(); + return (0); + } + if (symname(sname) == 0 || + ((ptr = find_member(lval->tagsym, sname)) == 0)) { + error("unknown member"); + junk(); + return (0); + } + if (k && direct == 0) + rvalue(lval); + out_ins(I_ADDWI, T_VALUE, ptr->offset); // move pointer from struct begin to struct member + lval->symbol = ptr; + lval->indirect = ptr->type; // lval->indirect = lval->val_type = ptr->type + lval->ptr_type = 0; + lval->ptr_order = 0; + lval->tagsym = NULL_TAG; + if (ptr->type == CSTRUCT) + lval->tagsym = &tag_table[ptr->tagidx]; + if (ptr->ident == POINTER) { + lval->indirect = CINT; + lval->ptr_type = ptr->type; + lval->ptr_order = ptr->ptr_order; + // lval->val_type = CINT; + } + if (ptr->ident == ARRAY || + (ptr->type == CSTRUCT && ptr->ident == VARIABLE)) { + // array or struct + lval->ptr_type = ptr->type; + lval->ptr_order = ptr->ptr_order; + // lval->val_type = CINT; + k = 0; + } + else k = 1; + } + else + return (k); + } + if (ptr == 0) + return (k); + + if (ptr->ident == FUNCTION) { + immed(T_SYMBOL, (intptr_t)ptr); + return (0); + } + return (k); +} + +void store (LVALUE *lval) +/* intptr_t *lval; */ +{ + if (lval->symbol2) { + /* far arrays (or special arrays) */ + if (!strcmp(lval->symbol2->name, "vdc")) + putio(lval->symbol2); + else if (!strcmp(lval->symbol2->name, "vram")) + putvram(lval->symbol2); + else { + error("const arrays can't be written"); + gpop(); + } + } + else { + /* other */ + if (lval->indirect != 0) + putstk(lval->indirect); + else { + if (lval->symbol && strcmp(lval->symbol->name, "vram") == 0) + out_ins(I_VPUTW, (intptr_t)NULL, (intptr_t)NULL); + else if (lval->symbol) + putmem(lval->symbol); + else + out_ins(I_STW, T_VALUE, lval->value); + } + } +} + +void rvalue (LVALUE *lval) +/* intptr_t *lval; */ +{ + if ((lval->symbol != 0) && (lval->indirect == 0)) { + if (strcmp(lval->symbol->name, "vram") == 0) + out_ins(I_VGETW, (intptr_t)NULL, (intptr_t)NULL); + else + getmem(lval->symbol); + } + else { + if (lval->symbol2 == 0) + indirect(lval->indirect); + else { + /* far arrays (or special arrays) */ + if (!strcmp(lval->symbol2->name, "vdc")) + getio(lval->symbol2); + else if (!strcmp(lval->symbol2->name, "vram")) + getvram(lval->symbol2); + else + farpeek(lval->symbol2); + } + } +} + +void needlval (void) +{ + error("must be lvalue"); +} diff --git a/src/huc/expr.h b/src/huc/expr.h new file mode 100644 index 00000000..0c2afe50 --- /dev/null +++ b/src/huc/expr.h @@ -0,0 +1,31 @@ +/* File expr.c: 2.2 (83/06/21,11:24:26) */ +/*% cc -O -c % + * + */ + +#ifndef _EXPR_H +#define _EXPR_H + +void expression (int comma); +intptr_t expression_ex (LVALUE *lval, int comma, int norval); +intptr_t heir1 (LVALUE *lval, int comma); +intptr_t heir1a (LVALUE *lval, int comma); +intptr_t heir1b (LVALUE *lval, int comma); +intptr_t heir1c (LVALUE *lval, int comma); +intptr_t heir2 (LVALUE *lval, int comma); +intptr_t heir3 (LVALUE *lval, int comma); +intptr_t heir4 (LVALUE *lval, int comma); +intptr_t heir5 (LVALUE *lval, int comma); +intptr_t heir6 (LVALUE *lval, int comma); +intptr_t heir7 (LVALUE *lval, int comma); +intptr_t heir8 (LVALUE *lval, int comma); +intptr_t heir9 (LVALUE *lval, int comma); +intptr_t heir10 (LVALUE *lval, int comma); +intptr_t heir11 (LVALUE *lval, int comma); +void store (LVALUE *lval); +void rvalue (LVALUE *lval); +void needlval (void); + +int is_byte (LVALUE *lval); + +#endif diff --git a/src/huc/fastcall.h b/src/huc/fastcall.h new file mode 100644 index 00000000..5d4f536b --- /dev/null +++ b/src/huc/fastcall.h @@ -0,0 +1,9 @@ +/* defines */ +#define TYPE_ACC 0x00 +#define TYPE_BYTE 0x01 +#define TYPE_WORD 0x02 +#define TYPE_FARPTR 0x03 +#define TYPE_DWORD 0x04 + +extern struct fastcall ftemp; +extern struct fastcall *fastcall_tbl[256]; diff --git a/src/huc/function.c b/src/huc/function.c new file mode 100644 index 00000000..8edf2ff3 --- /dev/null +++ b/src/huc/function.c @@ -0,0 +1,1157 @@ +/* File function.c: 2.1 (83/03/20,16:02:04) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "code.h" +#include "error.h" +#include "expr.h" +#include "fastcall.h" +#include "function.h" +#include "gen.h" +#include "io.h" +#include "lex.h" +#include "optimize.h" +#include "pragma.h" +#include "primary.h" +#include "pseudo.h" +#include "stmt.h" +#include "sym.h" +#include "struct.h" + +/* locals */ +static INS ins_stack[1024]; +static intptr_t ins_stack_idx; +/* static char ins_stack_fname[NAMESIZE]; */ +static intptr_t arg_list[32][2]; +/* static intptr_t arg_list_idx; */ +static intptr_t arg_idx; +static intptr_t func_call_stack; + +/* globals */ +intptr_t arg_stack_flag; +intptr_t argtop; + +/* protos */ +void arg_flush (intptr_t arg, intptr_t adj); +void arg_to_fptr (struct fastcall *fast, intptr_t i, intptr_t arg, intptr_t adj); +void arg_to_dword (struct fastcall *fast, intptr_t i, intptr_t arg, intptr_t adj); + +/* function declaration styles */ +#define KR 0 +#define ANSI 1 + +/* argument address pointers for ANSI arguments */ +short *fixup[32]; +char current_fn[NAMESIZE]; + +static int is_leaf_function; + +/* + * begin a function + * + * called from "parse", this routine tries to make a function out + * of what follows + * modified version. p.l. woods + * + */ +void newfunc (const char *sname, int ret_ptr_order, int ret_type, int ret_otag, int is_fastcall) +{ + char n[NAMESIZE]; + SYMBOL *ptr; + intptr_t nbarg = 0; + int is_irq_handler = 0; + int is_firq_handler = 0; + int save_norecurse = norecurse; + struct fastcall *fc; + intptr_t hash; + int fc_args; + + need_map_call_bank = 0; + is_leaf_function = 1; + + if (sname) { + /* At the opening parenthesis, declglb() found out that this + is a function declaration and called us. The function + name has therefore already been parsed. */ + strcpy(current_fn, sname); + strcpy(n, sname); + } + else { + /* The function name has not been parsed yet. This can happen + in two cases: + - No return type: We were called from parse(). + - fastcall: declglb() found the __fastcall attribute after + the type and called us. */ + if (is_fastcall) { + fc = &ftemp; + /* fc->nargs is the number of declared arguments; + fc_args is the number of arguments passed when + calling the function, which can be higher than + fc->nargs if types larger than 16 bits are used. */ + fc->nargs = 0; + fc_args = 0; + fc->flags = 0; + if (match("__nop")) + fc->flags = 0x01; + if (match("__macro")) + fc->flags = 0x04; + } + else { + /* No explicit return type. */ + ret_type = CINT; + } + if (!symname(n)) { + error("illegal function or declaration"); + kill(); + return; + } + strcpy(current_fn, n); + + if (!match("(")) + error("missing open paren"); + + if (is_fastcall) + strcpy(fc->fname, n); + } + + locptr = STARTLOC; + argstk = 0; + argtop = 0; + nbarg = 0; + memset(fixup, 0, sizeof(fixup)); + while (!match(")")) { + /* check if we have an ANSI argument */ + struct type t; + if (match_type(&t, NO, NO)) { + int ptr_order; + + if (t.type == CVOID) { + if (match(")")) + break; + } + + if (is_fastcall) { + if (match("far")) + fc->argtype[fc_args] = TYPE_FARPTR; + else { + if (t.type == CINT || t.type == CUINT) + fc->argtype[fc_args] = TYPE_WORD; + else + fc->argtype[fc_args] = TYPE_BYTE; + /* We'll change this to TYPE_WORD later + if it turns out to be a pointer. */ + } + } + + ptr_order = getarg(t.type, ANSI, t.otag, is_fastcall); + + if (is_fastcall) { + if (fc->argtype[fc_args] == TYPE_FARPTR) { + if (ptr_order < 1) { + error("far attribute to non-pointer type"); + return; + } + } + else if (ptr_order) + fc->argtype[fc_args] = TYPE_WORD; + + /* Parse the destination fastcall register + in angle brackets. */ + if (!match("<")) { + error("missing fastcall register"); + kill(); + return; + } + if (!symname(fc->argname[fc_args])) { + error("illegal fastcall register"); + kill(); + return; + } + if (fc->argtype[fc_args] == TYPE_FARPTR) { + /* We have the far pointer bank + register, expecting ":". */ + if (!match(":")) { + error("missing far pointer offset"); + kill(); + return; + } + + /* Far pointers are handled as two + arguments internally. */ + fc_args++; + if (fc_args >= MAX_FASTCALL_ARGS) { + error("too many fastcall arguments"); + kill(); + return; + } + + /* Far pointer offset register. */ + if (!symname(fc->argname[fc_args])) { + error("illegal far pointer offset register"); + return; + } + fc->argtype[fc_args] = TYPE_WORD; + } + if (!match(">")) { + error("missing closing angle bracket"); + return; + } + + if (!strcmp(fc->argname[fc_args], "acc")) + fc->argtype[fc_args] = TYPE_ACC; + } + nbarg++; + if (is_fastcall) { + fc->nargs++; + fc_args++; + if (fc_args >= MAX_FASTCALL_ARGS) { + error("too many fastcall arguments"); + kill(); + return; + } + } + } + else { + if (is_fastcall) { + error("fastcall argument without type"); + kill(); + return; + } + /* no valid type, assuming K&R argument */ + if (symname(n)) { + if (findloc(n)) + multidef(n); + else { + addloc(n, 0, 0, argstk, AUTO, INTSIZE); + argstk = argstk + INTSIZE; + nbarg++; + } + } + else { + error("illegal argument name"); + junk(); + } + } + blanks(); + if (!streq(line + lptr, ")")) { + if (!match(",")) + error("expected comma"); + } + if (endst()) + break; + } + + for (;;) { + if (amatch("__firq", 6)) { + /* Goes to LIB1_BANK for performance. */ + is_firq_handler = 1; + have_irq_handler++; + continue; + } + else if (amatch("__irq", 5)) { + /* Goes to regular code bank, with a mapping stub in + LIB1_BANK. */ + is_irq_handler = 1; + have_irq_handler++; + continue; + } + else if (amatch("__sirq", 6)) { + /* Same as __irq to us, but we need to inform the system + interrupt handler that it needs extra context saving + because it calls fastcall functions. */ + is_irq_handler = 1; + have_sirq_handler++; + continue; + } + + if (amatch("__mapcall", 9)) { + need_map_call_bank = 1; + continue; + } + + if (amatch("__norecurse", 14)) { + norecurse = 1; + continue; + } + else if (amatch("__recurse", 9)) { + norecurse = 0; + continue; + } + break; + } + + if (match(";")) { + /* function prototype */ + ptr = addglb(current_fn, FUNCTION, ret_type, 0, EXTERN, 0); + norecurse = save_norecurse; + + if (is_fastcall) { + /* XXX: pragma code sets flag 0x02 if there are + memory arguments, but that's not used + anywhere... */ + + int i; + for (i = 0; i < fc_args - 1; i++) { + if (fc->argtype[i] == TYPE_ACC) { + error("fastcall accumulator argument must come last"); + kill(); + return; + } + } + + if (fastcall_look(n, fc->nargs, NULL)) { + error("fastcall already defined"); + return; + } + + /* insert function into fastcall table */ + fc = (void *)malloc(sizeof(struct fastcall)); + if (!fc) { + error("out of memory"); + return; + } + *fc = ftemp; + hash = symhash(n); + fc->next = fastcall_tbl[hash]; + fastcall_tbl[hash] = fc; + } + + return; + } + else if (is_fastcall) { + error("__fastcall can only be used in prototypes"); + return; + } + + if (fastcall_look(n, nbarg, NULL)) { + error("implementation of fastcall functions in C not supported yet"); + return; + } + + stkp = 0; + clabel_ptr = 0; + argtop = argstk; + while (argstk) { + /* We only know the final argument offset once we have parsed + all of them. That means that for ANSI arguments we have + to fix up the addresses for the locations generated in + getarg() here. */ + if (fixup[argstk / INTSIZE - 1]) { + argstk -= INTSIZE; + *fixup[argstk / INTSIZE] += argtop; + } + else { + struct type t; + if (match_type(&t, NO, NO)) { + getarg(t.type, KR, t.otag, is_fastcall); + ns(); + } + else { + error("wrong number args"); + break; + } + } + } + + fexitlab = getlabel(); + + if ((ptr = findglb(current_fn))) { + if (ptr->ident != FUNCTION) + multidef(current_fn); + else if (ptr->offset == FUNCTION) + multidef(current_fn); + else + /* XXX: sanity check? */ + ptr->offset = FUNCTION; + } + else + ptr = addglb(current_fn, FUNCTION, ret_type, FUNCTION, PUBLIC, 0); + ptr->ptr_order = ret_ptr_order; + ptr->tagidx = ret_otag; + + flush_ins(); /* David, .proc directive support */ + gtext(); + if (is_firq_handler) { + ol(".bank LIB1_BANK"); + prefix(); outstr(current_fn); outstr(":"); nl(); + } + else if (is_irq_handler) { + ol(".bank LIB1_BANK"); + prefix(); outstr(current_fn); outstr(":"); nl(); + ot("maplibfunc\t"); outstr(current_fn); nl(); + ol("rts"); + ot(".proc "); outstr(current_fn); nl(); + } + else { + ot(".proc "); + prefix(); + outstr(current_fn); + nl(); + } + + if (nbarg) /* David, arg optimization */ + gpusharg(0); + + /* When using fixed-address locals, locals_ptr is used to + keep track of their memory offset instead of stkp, so + we have to reset it before producing code. */ + if (norecurse) + locals_ptr = 0; + + statement(YES); + gnlabel(fexitlab); + modstk(nbarg * INTSIZE); + gtext(); + gret(); /* generate the return statement */ + flush_ins(); /* David, optimize.c related */ + if (!is_firq_handler) + ol(".endp"); /* David, .endp directive support */ + + /* Add space for fixed-address locals to .bss section. */ + if (norecurse && locals_ptr < 0) { + if (is_leaf_function) { + leaf_functions = realloc(leaf_functions, (leaf_cnt + 1) * sizeof(*leaf_functions)); + leaf_functions[leaf_cnt++] = strdup(current_fn); + if (-locals_ptr > leaf_size) + leaf_size = -locals_ptr; + } + else { + ot(".data"); nl(); + ot(".bss"); nl(); + ot("__"); outstr(current_fn); outstr("_loc: .ds "); + outdec(-locals_ptr); nl(); + ot("__"); outstr(current_fn); outstr("_lend:"); nl(); + ot(".code"); nl(); + } + } + + nl(); + stkp = 0; + locptr = STARTLOC; + norecurse = save_norecurse; +} + +/* + * declare argument types + * + * called from "newfunc", this routine add an entry in the local + * symbol table for each named argument + * completely rewritten version. p.l. woods + * + */ +int getarg (intptr_t t, int syntax, int otag, int is_fastcall) +{ + intptr_t j, legalname, address; + char n[NAMESIZE]; + SYMBOL *argptr; + int ptr_order = 0; + +/* char c; */ + + FOREVER { + if (syntax == KR && argstk == 0) + return (ptr_order); + + j = VARIABLE; + while (match("*")) { + j = POINTER; + ptr_order++; + } + + if (t == CSTRUCT && j != POINTER) + error("passing structures as arguments by value not implemented yet"); + + if (t == CVOID) { + if (j != POINTER) + error("illegal argument type \"void\""); + else + t = CUINT; + } + + if (!(legalname = symname(n))) { + if (syntax == ANSI && (ch() == ',' || ch() == ')')) + sprintf(n, "__anon_%d\n", (int) -argstk); + else { + illname(); + junk(); + } + } + if (match("[")) { + while (inbyte() != ']') + if (endst()) + break; + j = POINTER; + ptr_order++; + } + if (legalname) { + if (syntax == ANSI) { + if (findloc(n)) + multidef(n); + else { + addloc(n, 0, 0, argstk, AUTO, INTSIZE); + argstk = argstk + INTSIZE; + } + } + if ((argptr = findloc(n))) { + argptr->ident = j; + argptr->type = t; + address = argtop - glint(argptr) - 2; + if ((t == CCHAR || t == CUCHAR) && j == VARIABLE) + address = address + BYTEOFF; + argptr->offset = address; + argptr->tagidx = otag; + argptr->ptr_order = ptr_order; + if (syntax == ANSI) + fixup[argstk / INTSIZE - 1] = &argptr->offset; + } + else + error("expecting argument name"); + } + if (syntax == KR) { + argstk = argstk - INTSIZE; + if (endst()) + return (ptr_order); + + if (!match(",")) + error("expected comma"); + } + else { + blanks(); + if (streq(line + lptr, ")") || + streq(line + lptr, ",") || + (is_fastcall && streq(line + lptr, "<")) + ) + return (ptr_order); + else + error("expected comma, closing bracket, or fastcall register"); + } + } + return (ptr_order); +} + +/* + * perform a function call + * + * called from "heir11", this routine will either call the named + * function, or if the supplied ptr is zero, will call the contents + * of HL + * + */ +#define SPILLB(a) { \ + spilled_args[sparg_idx] = (a); \ + spilled_arg_sizes[sparg_idx++] = 1; \ + out_ins(I_SAVEB, 0, 0); \ +} + +#define SPILLW(a) { \ + spilled_args[sparg_idx] = (a); \ + spilled_arg_sizes[sparg_idx++] = 2; \ + out_ins(I_SAVEW, 0, 0); \ +} + +void callfunction (char *ptr) +{ + extern char *new_string (intptr_t, char *); + struct fastcall *fast; + intptr_t call_stack_ref; + intptr_t i, j; + intptr_t nb; + intptr_t adj; + intptr_t nargs; + intptr_t cnt; + int max_fc_arg = 0; /* highest arg with a fastcall inside */ + /* args spilled to the native stack */ + const char *spilled_args[MAX_FASTCALL_ARGS]; + /* byte sizes of spilled args */ + int spilled_arg_sizes[MAX_FASTCALL_ARGS]; + int sparg_idx = 0; /* index into spilled_args[] */ + int uses_acc = 0; /* does callee use acc? */ + + is_leaf_function = 0; + + cnt = 0; + nargs = 0; + fast = NULL; + call_stack_ref = ++func_call_stack; + + /* skip blanks */ + blanks(); + + /* check if it's a special function, + * if yes handle it externaly + */ + if (ptr) { + if (!strcmp(ptr, "bank")) { + do_asm_func(T_BANK); return; + } + else if (!strcmp(ptr, "vram")) { + do_asm_func(T_VRAM); return; + } + else if (!strcmp(ptr, "pal")) { + do_asm_func(T_PAL); return; + } + else if (!strcmp(ptr, "set_bgpal")) { + doset_bgpalstatement(); return; + } + else if (!strcmp(ptr, "set_sprpal")) { + doset_sprpalstatement(); return; + } + else if (!strcmp(ptr, "load_sprites")) { + doload_spritesstatement(); return; + } + else if (!strcmp(ptr, "load_background")) { + doload_backgroundstatement(); return; + } + } + + /* indirect call (push func address) */ + if (ptr == NULL) + gpush(); + + /* fastcall check */ + if (ptr == NULL) + nb = 0; + else + nb = fastcall_look(ptr, -1, NULL); + + /* calling regular functions in fastcall arguments is OK */ + if (!nb) + --func_call_stack; + + if (nb) + flush_ins(); + + /* get args */ + while (!streq(line + lptr, ")")) { + if (endst()) + break; + /* fastcall func */ + if (nb) { + int nfc = func_call_stack; + + if (nargs) + stkp = stkp - INTSIZE; + arg_stack(arg_idx++); + expression(NO); + flush_ins(); + + /* Check if we had a fastcall in our argument. */ + if (nfc < func_call_stack) { + /* Remember the last argument with an FC. */ + if (max_fc_arg < arg_idx - 1) + max_fc_arg = arg_idx - 1; + } + } + /* standard func */ + else { + if (nargs) + gpusharg(INTSIZE); + expression(NO); + } + nargs = nargs + INTSIZE; + cnt++; + if (!match(",")) + break; + } + + /* adjust arg stack */ + if (nb) { + if (cnt) { + arg_list[arg_idx - 1][1] = ins_stack_idx; + arg_idx -= cnt; + } + if (arg_idx) + ins_stack_idx = arg_list[arg_idx - 1][1]; + else { + ins_stack_idx = 0; + arg_stack_flag = 0; + } + } + + /* fastcall func */ + if (nb) { + nb = fastcall_look(ptr, cnt, &fast); + + /* flush arg instruction stacks */ + if (nb) { + /* fastcall */ + for (i = 0, j = 0, adj = 0; i < cnt; i++) { + /* flush arg stack (except for farptr and dword args) */ + if ((fast->argtype[j] != TYPE_FARPTR) && + (fast->argtype[j] != TYPE_DWORD)) + arg_flush(arg_idx + i, adj); + + /* Either store the argument in its designated + location, or save it on the (native) stack + if there is another fastcall ahead. */ + switch (fast->argtype[j]) { + case TYPE_BYTE: + if (i < max_fc_arg) + SPILLB(fast->argname[j]) + else + out_ins(I_STB, T_LITERAL, (intptr_t)fast->argname[j]); + break; + case TYPE_WORD: + if (i < max_fc_arg) + SPILLW(fast->argname[j]) + else + out_ins(I_STW, T_LITERAL, (intptr_t)fast->argname[j]); + break; + case TYPE_FARPTR: + arg_to_fptr(fast, j, arg_idx + i, adj); + if (i < max_fc_arg) { + out_ins(I_LDUB, T_LITERAL, (intptr_t)fast->argname[j]); + SPILLB(fast->argname[j]) + out_ins(I_LDW, T_LITERAL, (intptr_t)fast->argname[j + 1]); + SPILLW(fast->argname[j + 1]) + } + j += 1; + break; + case TYPE_DWORD: + arg_to_dword(fast, j, arg_idx + i, adj); + if (i < max_fc_arg) { + out_ins(I_LDW, T_LITERAL, (intptr_t)fast->argname[j]); + SPILLW(fast->argname[j]) + out_ins(I_LDW, T_LITERAL, (intptr_t)fast->argname[j + 1]); + SPILLW(fast->argname[j + 1]) + out_ins(I_LDW, T_LITERAL, (intptr_t)fast->argname[j + 2]); + SPILLW(fast->argname[j + 2]) + } + j += 2; + break; + case TYPE_ACC: + if (i < max_fc_arg) + SPILLW(0) + uses_acc = 1; + break; + default: + error("fastcall internal error"); + break; + } + + /* next */ + adj += INTSIZE; + j++; + } + } + else { + /* standard call */ + for (i = 0; i < cnt;) { + arg_flush(arg_idx + i, 0); + i++; + if (i < cnt) + gpusharg(0); + } + } + } + + /* reset func call stack */ + if (call_stack_ref == 1) + func_call_stack = 0; + + /* close */ + needbrack(")"); + + /* call function */ + /* Reload fastcall arguments spilled to the native stack. */ + if (sparg_idx) { + /* Reloading corrupts acc, so we need to save it if it + is used by the callee. */ + if (uses_acc) + out_ins(I_STW, T_LITERAL, (intptr_t)"<__temp"); + + for (i = sparg_idx - 1; i > -1; i--) { + if (spilled_arg_sizes[i] == 1) { + out_ins(I_RESB, 0, 0); + out_ins(I_STB, T_LITERAL, (intptr_t)spilled_args[i]); + } + else { + out_ins(I_RESW, 0, 0); + if (spilled_args[i]) + out_ins(I_STW, T_LITERAL, (intptr_t)spilled_args[i]); + } + } + + if (uses_acc) + out_ins(I_LDW, T_LITERAL, (intptr_t)"<__temp"); + } + + if (ptr == NULL) + callstk(nargs); + else { + if (fast && ((fast->flags & FASTCALL_NOP) || (fast->flags & FASTCALL_MACRO))) { + + // Only macro fastcalls get a name generated + if (fast->flags & FASTCALL_MACRO) { + if (nb) + gmacro(ptr, cnt); + else + gmacro(ptr, 0); + } + } + // Else not a NOP or MACRO fastcall + else if (nb) + gcall(ptr, cnt); + else + gcall(ptr, 0); + } + + /* adjust stack */ + if (nargs > INTSIZE) { + nargs = nargs - INTSIZE; + stkp = stkp + nargs; + out_ins(I_ADDMI, T_NOP, nargs); + } +} + +/* + * start arg instruction stacking + * + */ +void arg_stack (intptr_t arg) +{ + if (arg > 31) + error("too many args"); + else { + /* close previous stack */ + if (arg) + arg_list[arg - 1][1] = ins_stack_idx; + + /* init new stack */ + ins_stack_idx += 4; + arg_list[arg][0] = ins_stack_idx; + arg_list[arg][1] = -1; + arg_stack_flag = 1; + } +} + +/* + * put instructions in a temporary stack (one for each func arg) + * + */ +void arg_push_ins (INS *ptr) +{ + if (ins_stack_idx < 1024) + ins_stack[ins_stack_idx++] = *ptr; + else { + if (ins_stack_idx < 1025) { + ins_stack_idx++; + error("arg stack full"); + } + } +} + +/* + * flush arg instruction stacks + * + */ +void arg_flush (intptr_t arg, intptr_t adj) +{ + INS *ins; + intptr_t idx; + intptr_t nb; + intptr_t i; + + if (arg > 31) + return; + + idx = arg_list[arg][0]; + nb = arg_list[arg][1] - arg_list[arg][0]; + + for (i = 0; i < nb;) { + /* adjust stack refs */ + i++; + ins = &ins_stack[idx]; + + if ((ins->type == T_STACK) && (ins->code == I_LDW)) { + if (i < nb) { + ins = &ins_stack[idx + 1]; + if ((ins->code == I_ADDWI) && (ins->type == T_VALUE)) + ins->data -= adj; + } + } + else { + switch (ins->code) { + case X_LEA_S: + case X_PEA_S: + case X_LDB_S: + case X_LDUB_S: + case X_LDW_S: + case X_LDD_S_B: + case X_LDD_S_W: + case X_STB_S: + case X_STW_S: + case X_INCW_S: + case X_ADDW_S: + case X_ADDB_S: + case X_ADDUB_S: + case X_STBI_S: + case X_STWI_S: + ins->data -= adj; + break; + } + } + + /* flush */ + gen_ins(&ins_stack[idx++]); + } +} + +void arg_to_fptr (struct fastcall *fast, intptr_t i, intptr_t arg, intptr_t adj) +{ + INS *ins, tmp; + SYMBOL *sym; + intptr_t idx; + intptr_t err; + intptr_t nb; + + if (arg > 31) + return; + + idx = arg_list[arg][0]; + nb = arg_list[arg][1] - arg_list[arg][0]; + ins = &ins_stack[idx]; + err = 0; + + /* check arg */ + /* this code can be fooled, but it should catch most common errors */ + err = 1; + if (nb == 1) { + if (ins->type == T_SYMBOL) { + /* allow either "function", "array", or "array+const" */ + sym = (SYMBOL *)ins->data; + switch (sym->ident) { + case FUNCTION: + case ARRAY: + if (ins->code == I_LDWI) + err = 0; + break; + case POINTER: + if (ins->code == I_LDW) + err = 0; + break; + } + } + } + else if (nb > 1) { + /* complex expression */ + for (idx = 0; idx < nb; ++idx, ++ins) { + if (ins->type == T_SYMBOL) { + /* allow either "function", "array", or "array+const" */ + sym = (SYMBOL *)ins->data; + switch (sym->ident) { + case ARRAY: + if ((ins->code == I_LDWI) || + (ins->code == I_ADDWI)) + err = 0; + break; + case POINTER: + if (ins->code == I_LDW) + err = 0; + break; + } + } + if (err == 0) break; + } + + /* check if last instruction is a pointer dereference */ + switch (ins_stack[ arg_list[arg][0] + nb - 1 ].code) { + case I_LDBP: + case I_LDWP: + err = 1; + break; + } + } + + if (err) { + error("can't get farptr"); + return; + } + + /* ok */ + if (nb == 1) { + ins->code = I_FARPTR; + ins->arg[0] = fast->argname[i]; + ins->arg[1] = fast->argname[i + 1]; + gen_ins(ins); + } + else { + sym = (SYMBOL *)ins->data; + + /* check symbol type */ + if (sym->far) { + tmp.code = I_FARPTR_I; + tmp.type = T_SYMBOL; + tmp.data = ins->data; + tmp.arg[0] = fast->argname[i]; + tmp.arg[1] = fast->argname[i + 1]; + ins->type = T_VALUE; + ins->data = 0; + } + else { + if (((sym->ident == ARRAY) || + (sym->ident == POINTER)) && + (sym->type == CINT || sym->type == CUINT)) { + tmp.code = I_FARPTR_GET; + tmp.type = (intptr_t)NULL; + tmp.data = (intptr_t)NULL; + tmp.arg[0] = fast->argname[i]; + tmp.arg[1] = fast->argname[i + 1]; + } + else { + error("can't get farptr"); + return; + } + } + arg_flush(arg, adj); + gen_ins(&tmp); + } +} + +void arg_to_dword (struct fastcall *fast, intptr_t i, intptr_t arg, intptr_t adj) +{ + INS *ins, *ptr, tmp; + SYMBOL *sym; + intptr_t idx; + intptr_t gen; + intptr_t err; + intptr_t nb; + + if (arg > 31) + return; + + idx = arg_list[arg][0]; + nb = arg_list[arg][1] - arg_list[arg][0]; + ins = &ins_stack[idx]; + gen = 0; + err = 1; + + /* check arg */ + if (nb == 1) { + /* immediate value */ + if ((ins->code == I_LDWI) && (ins->type == T_VALUE)) { + ins->code = X_LDD_I; + ins->arg[0] = fast->argname[i + 1]; + ins->arg[1] = fast->argname[i + 2]; + gen = 1; + } + + /* var/ptr */ + else if ((((ins->code == I_LDW) || (ins->code == I_LDB) || (ins->code == I_LDUB)) + && (ins->type == T_SYMBOL)) || (ins->type == T_LABEL)) { + /* check special cases */ + if (ins->type == T_LABEL) { + error("dword arg can't be a static var"); + return; + } + + /* get symbol */ + sym = (SYMBOL *)ins->data; + + /* check type */ + if (sym->ident == POINTER) + gen = 1; + else if (sym->ident == VARIABLE) { + if (ins->code == I_LDW) + ins->code = X_LDD_W; + else + ins->code = X_LDD_B; + + ins->type = T_SYMBOL; + ins->data = (intptr_t)sym; + ins->arg[0] = fast->argname[i + 1]; + ins->arg[1] = fast->argname[i + 2]; + gen = 1; + } + } + + /* var/ptr */ + else if ((ins->code == X_LDW_S) || (ins->code == X_LDB_S) || ins->code == X_LDUB_S) { + /* get symbol */ + sym = ins->sym; + + /* check type */ + if (sym) { + if (sym->ident == POINTER) + gen = 1; + else if (sym->ident == VARIABLE) { + if (ins->code == X_LDW_S) + ins->code = X_LDD_S_W; + else + ins->code = X_LDD_S_B; + + ins->data -= adj; + ins->arg[0] = fast->argname[i + 1]; + ins->arg[1] = fast->argname[i + 2]; + gen = 1; + } + } + } + + /* array */ + else if (ins->code == X_LEA_S) { + sym = ins->sym; + + if (sym && (sym->ident == ARRAY)) { + ins->data -= adj; + gen = 1; + } + } + + /* array */ + else if ((ins->code == I_LDWI) && (ins->type == T_SYMBOL)) { + /* get symbol */ + sym = (SYMBOL *)ins->data; + + /* check type */ + if (sym->ident == ARRAY) + gen = 1; + } + } + else if (nb == 2) { + /* array */ + if ((ins->code == I_LDWI) && (ins->type == T_SYMBOL)) { + /* get symbol */ + sym = (SYMBOL *)ins->data; + + /* check type */ + if (sym->ident == ARRAY) { + ptr = ins; + ins = &ins_stack[idx + 1]; + + if ((ins->code == I_ADDWI) && (ins->type == T_VALUE)) { + gen_ins(ptr); + gen = 1; + } + } + } + } + + /* gen code */ + if (gen) { + gen_ins(ins); + err = 0; + + if (strcmp(fast->argname[i], "#acc") != 0) { + tmp.code = I_STW; + tmp.type = T_SYMBOL; + tmp.data = (intptr_t)fast->argname[i]; + gen_ins(&tmp); + } + } + + /* errors */ + if (err) { + if (optimize < 1) + error("dword arg support works only with optimization enabled"); + else + error("invalid or too complex dword arg syntax"); + } +} diff --git a/src/huc/function.h b/src/huc/function.h new file mode 100644 index 00000000..0542154b --- /dev/null +++ b/src/huc/function.h @@ -0,0 +1,18 @@ +/* File function.c: 2.1 (83/03/20,16:02:04) */ +/*% cc -O -c % + * + */ + +#ifndef _FUNCTION_H +#define _FUNCTION_H + +void newfunc (const char *sname, int ret_ptr_order, int ret_type, int ret_otag, int is_fastcall); +int getarg (intptr_t t, int syntax, int otag, int is_fastcall); +void callfunction (char *ptr); +void arg_stack (intptr_t arg); +void arg_push_ins (INS *ptr); +void arg_flush (intptr_t arg, intptr_t adj); +void arg_to_fptr (struct fastcall *fast, intptr_t i, intptr_t arg, intptr_t adj); +void arg_to_dword (struct fastcall *fast, intptr_t i, intptr_t arg, intptr_t adj); + +#endif diff --git a/src/huc/gen.c b/src/huc/gen.c new file mode 100644 index 00000000..1bac582f --- /dev/null +++ b/src/huc/gen.c @@ -0,0 +1,733 @@ +/* File gen.c: 2.1 (83/03/20,16:02:06) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "code.h" +#include "primary.h" +#include "sym.h" +#include "gen.h" +#include "expr.h" +#include "const.h" +#include "error.h" + +/* + * return next available internal label number + * + */ +intptr_t getlabel (void) +{ + return (nxtlab++); +} + +/* + * fetch a static memory cell into the primary register + */ +void getmem (SYMBOL *sym) +{ + char *data; + + if ((sym->ident != POINTER) && (sym->type == CCHAR || sym->type == CUCHAR)) { + int op = I_LDB; + if (sym->type & CUNSIGNED) + op = I_LDUB; + if ((sym->storage & ~WRITTEN) == LSTATIC) + out_ins(op, T_LABEL, glint(sym)); + else + out_ins(op, T_SYMBOL, (intptr_t)(sym->name)); + } + else { + if ((sym->storage & ~WRITTEN) == LSTATIC) + out_ins(I_LDW, T_LABEL, glint(sym)); + else if ((sym->storage & ~WRITTEN) == CONST && (data = get_const(sym))) + out_ins(I_LDWI, T_LITERAL, (intptr_t)data); + else + out_ins(I_LDW, T_SYMBOL, (intptr_t)(sym->name)); + } +} + +/* + * fetch a hardware register into the primary register + */ +void getio (SYMBOL *sym) +{ + out_ins(I_CALL, T_LIB, (intptr_t)"getvdc"); +} +void getvram (SYMBOL *sym) +{ + out_ins(I_CALL, T_LIB, (intptr_t)"readvram"); +} + +/* + * fetch the address of the specified symbol into the primary register + * + */ +void getloc (SYMBOL *sym) +{ + intptr_t value; + + if ((sym->storage & ~WRITTEN) == LSTATIC) + out_ins(I_LDWI, T_LABEL, glint(sym)); + else { + value = glint(sym); + if (norecurse && value < 0) { + /* XXX: bit of a memory leak, but whatever... */ + SYMBOL * locsym = copysym(sym); + if (NAMEALLOC <= + sprintf(locsym->name, "_%s_lend-%ld", current_fn, (long) -value)) + error("norecurse local name too intptr_t"); + out_ins(I_LDWI, T_SYMBOL, (intptr_t)locsym); + } + else { + value -= stkp; + out_ins_sym(X_LEA_S, T_STACK, value, sym); + } + } +} + +/* + * store the primary register into the specified static memory cell + * + */ +void putmem (SYMBOL *sym) +{ + intptr_t code; + + /* XXX: What about 1-byte structs? */ + if ((sym->ident != POINTER) & (sym->type == CCHAR || sym->type == CUCHAR)) + code = I_STB; + else + code = I_STW; + + if ((sym->storage & ~WRITTEN) == LSTATIC) + out_ins(code, T_LABEL, glint(sym)); + else + out_ins(code, T_SYMBOL, (intptr_t)(sym->name)); +} + +/* + * store the specified object type in the primary register + * at the address on the top of the stack + * + */ +void putstk (char typeobj) +{ + if (typeobj == CCHAR || typeobj == CUCHAR) + out_ins(I_STBPS, (intptr_t)NULL, (intptr_t)NULL); + else + out_ins(I_STWPS, (intptr_t)NULL, (intptr_t)NULL); + stkp = stkp + INTSIZE; +} + +/* + * store the primary register + * at the address on the top of the stack + * + */ +void putio (SYMBOL *sym) +{ + out_ins(I_JSR, T_LIB, (intptr_t)"setvdc"); + stkp = stkp + INTSIZE; +} +void putvram (SYMBOL *sym) +{ + out_ins(I_JSR, T_LIB, (intptr_t)"writevram"); + stkp = stkp + INTSIZE; +} + +/* + * fetch the specified object type indirect through the primary + * register into the primary register + * + */ +void indirect (char typeobj) +{ + out_ins(I_STW, T_PTR, (intptr_t)NULL); + if (typeobj == CCHAR) + out_ins(I_LDBP, T_PTR, (intptr_t)NULL); + else if (typeobj == CUCHAR) + out_ins(I_LDUBP, T_PTR, (intptr_t)NULL); + else + out_ins(I_LDWP, T_PTR, (intptr_t)NULL); +} + +void farpeek (SYMBOL *ptr) +{ + if (ptr->type == CCHAR) + out_ins(I_FGETB, T_SYMBOL, (intptr_t)ptr); + else if (ptr->type == CUCHAR) + out_ins(I_FGETUB, T_SYMBOL, (intptr_t)ptr); + else + out_ins(I_FGETW, T_SYMBOL, (intptr_t)ptr); +} + +/* + * print partial instruction to get an immediate value into + * the primary register + * + */ +void immed (intptr_t type, intptr_t data) +{ + if (type == T_VALUE && (data < -32768 || data > 65535)) + warning(W_GENERAL, "large integer truncated"); + out_ins(I_LDWI, type, data); +} + +/* + * push the primary register onto the stack + * + */ +void gpush (void) +{ +// out_ins(I_PUSHWZ, T_VALUE, zpstkp); +// zpstkp = zpstkp - INTSIZE; + + out_ins(I_PUSHW, T_VALUE, INTSIZE); + stkp = stkp - INTSIZE; +} + +/* + * push the primary register onto the stack + * + */ +void gpusharg (intptr_t size) +{ + out_ins(I_PUSHW, T_SIZE, size); + stkp = stkp - size; +} + +/* + * pop the top of the stack into the secondary register + * + */ +void gpop (void) +{ + out_ins(I_POPW, (intptr_t)NULL, (intptr_t)NULL); + stkp = stkp + INTSIZE; +} + +/* + * swap the primary register and the top of the stack + * + */ +void swapstk (void) +{ + out_ins(I_SWAPW, (intptr_t)NULL, (intptr_t)NULL); +} + +/* + * call the specified subroutine name + * + */ +void gcall (char *sname, intptr_t nargs) +{ + if (need_map_call_bank) + out_ins_ex(I_MAPCBANK, T_SYMBOL, (intptr_t)sname, T_VALUE, nargs); + out_ins_ex(I_CALL, T_SYMBOL, (intptr_t)sname, T_VALUE, nargs); + if (need_map_call_bank) + out_ins_ex(I_UNMAPCBANK, T_SYMBOL, (intptr_t)sname, T_VALUE, nargs); +} + +/* + * call the specified macro name + * + */ +void gmacro (char *sname, intptr_t nargs) +{ + out_ins_ex(I_MACRO, T_SYMBOL, (intptr_t)sname, T_VALUE, nargs); +} + +/* + * generate a bank pseudo instruction + * + */ +void gbank (unsigned char bank, unsigned short offset) +{ + out_ins(I_BANK, T_VALUE, bank); + out_ins(I_OFFSET, T_VALUE, offset); +} + +/* + * return from subroutine + * + */ +void gret (void) +{ + out_ins(I_RTS, (intptr_t)NULL, (intptr_t)NULL); +} + +/* + * perform subroutine call to value on top of stack + * + */ +void callstk (intptr_t nargs) +{ + if (nargs <= INTSIZE) + out_ins(I_CALLS, T_STACK, 0); + else + out_ins(I_CALLS, T_STACK, nargs - INTSIZE); + + stkp = stkp + INTSIZE; +} + +/* + * jump to specified internal label number + * + */ +void jump (intptr_t label) +{ + out_ins(I_LBRA, T_LABEL, label); +} + +/* + * test the primary register and jump if false to label + * + */ +void testjump (intptr_t label, intptr_t ft) +{ + out_ins(I_TSTW, (intptr_t)NULL, (intptr_t)NULL); + if (ft) + out_ins(I_LBNE, T_LABEL, label); + else + out_ins(I_LBEQ, T_LABEL, label); +} + +/* + * modify the stack pointer to the new value indicated + * Is it there that we decrease the value of the stack to add local vars ? + */ +intptr_t modstk (intptr_t newstkp) +{ + intptr_t k; + +// k = galign(newstkp - stkp); + k = newstkp - stkp; + if (k) { + gtext(); + out_ins(I_ADDMI, T_STACK, k); + } + return (newstkp); +} + +/* + * multiply the primary register by INTSIZE + */ +void gaslint (void) +{ + out_ins(I_ASLW, (intptr_t)NULL, (intptr_t)NULL); +} + +/* + * divide the primary register by INTSIZE + */ +void gasrint (void) +{ + out_ins(I_ASRW, (intptr_t)NULL, (intptr_t)NULL); +} + +/* + * Case jump instruction + */ +void gjcase (void) +{ + out_ins(I_JMP, T_SYMBOL, (intptr_t)"__case"); +} + +/* + * add the primary and secondary registers + * if lval2 is int pointer and lval is int, scale lval + */ +void gadd (LVALUE *lval, LVALUE *lval2) +{ + /* XXX: isn't this done in expr.c already? */ + if (dbltest(lval2, lval)) + out_ins(I_ASLWS, (intptr_t)NULL, (intptr_t)NULL); + if (lval && lval2 && is_byte(lval) && is_byte(lval2)) + out_ins(I_ADDBS, (intptr_t)NULL, (intptr_t)NULL); + else + out_ins(I_ADDWS, (intptr_t)NULL, (intptr_t)NULL); + stkp = stkp + INTSIZE; +} + +/* + * subtract the primary register from the secondary + * + */ +void gsub (void) +{ + out_ins(I_SUBWS, (intptr_t)NULL, (intptr_t)NULL); + stkp = stkp + INTSIZE; +} + +/* + * multiply the primary and secondary registers + * (result in primary) + * + */ +void gmult (int is_unsigned) +{ + if (is_unsigned) + out_ins(I_JSR, T_LIB, (intptr_t)"umul"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"smul"); + stkp = stkp + INTSIZE; +} + +void gmult_imm (int value) +{ + out_ins(I_MULWI, T_VALUE, (intptr_t)value); +} + +/* + * divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + * + */ +void gdiv (int is_unsigned) +{ + if (is_unsigned) + out_ins(I_JSR, T_LIB, (intptr_t)"udiv"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"sdiv"); + stkp = stkp + INTSIZE; +} + +void gdiv_imm (int value) +{ + gpush(); + immed(T_VALUE, value); + gdiv(1); +} + +/* + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + * + */ +void gmod (int is_unsigned) +{ + if (is_unsigned) + out_ins(I_JSR, T_LIB, (intptr_t)"umod"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"smod"); + stkp = stkp + INTSIZE; +} + +/* + * inclusive 'or' the primary and secondary registers + * + */ +void gor (void) +{ + out_ins(I_ORWS, (intptr_t)NULL, (intptr_t)NULL); + stkp = stkp + INTSIZE; +} + +/* + * exclusive 'or' the primary and secondary registers + * + */ +void gxor (void) +{ + out_ins(I_EORWS, (intptr_t)NULL, (intptr_t)NULL); + stkp = stkp + INTSIZE; +} + +/* + * 'and' the primary and secondary registers + * + */ +void gand (void) +{ + out_ins(I_ANDWS, (intptr_t)NULL, (intptr_t)NULL); + stkp = stkp + INTSIZE; +} + +/* + * arithmetic shift right the secondary register the number of + * times in the primary register + * (results in primary register) + * + */ +void gasr (int is_unsigned) +{ + if (is_unsigned) + out_ins(I_JSR, T_LIB, (intptr_t)"lsr"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"asr"); + stkp = stkp + INTSIZE; +} + +/* + * arithmetic shift left the secondary register the number of + * times in the primary register + * (results in primary register) + * + */ +void gasl (void) +{ + out_ins(I_JSR, T_LIB, (intptr_t)"asl"); + stkp = stkp + INTSIZE; +} + +/* + * two's complement of primary register + * + */ +void gneg (void) +{ + out_ins(I_NEGW, (intptr_t)NULL, (intptr_t)NULL); +} + +/* + * one's complement of primary register + * + */ +void gcom (void) +{ + out_ins(I_COMW, (intptr_t)NULL, (intptr_t)NULL); +} + +/* + * convert primary register into logical value + * + */ +void gbool (void) +{ + out_ins(I_BOOLW, (intptr_t)NULL, (intptr_t)NULL); +} + +/* + * logical complement of primary register + * + */ +void glneg (void) +{ + out_ins(I_NOTW, (intptr_t)NULL, (intptr_t)NULL); +} + +/* + * increment the primary register by 1 if char, INTSIZE if + * intptr_t + */ +void ginc (LVALUE *lval) +{ + SYMBOL *sym = lval->symbol; + + if (lval->ptr_type == CINT || lval->ptr_type == CUINT || + (sym && (sym->ptr_order > 1 || (sym->ident == ARRAY && sym->ptr_order > 0)))) + out_ins(I_ADDWI, T_VALUE, 2); + else if (lval->ptr_type == CSTRUCT) + out_ins(I_ADDWI, T_VALUE, lval->tagsym->size); + else + out_ins(I_ADDWI, T_VALUE, 1); +} + +/* + * decrement the primary register by one if char, INTSIZE if + * intptr_t + */ +void gdec (LVALUE *lval) +{ + SYMBOL *sym = lval->symbol; + + if (lval->ptr_type == CINT || lval->ptr_type == CUINT || + (sym && (sym->ptr_order > 1 || (sym->ident == ARRAY && sym->ptr_order > 0)))) + out_ins(I_SUBWI, T_VALUE, 2); + else if (lval->ptr_type == CSTRUCT) + out_ins(I_SUBWI, T_VALUE, lval->tagsym->size); + else + out_ins(I_SUBWI, T_VALUE, 1); +} + +/* + * following are the conditional operators. + * they compare the secondary register against the primary register + * and put a literl 1 in the primary if the condition is true, + * otherwise they clear the primary register + * + */ + +/* + * equal + * + */ +void geq (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"eqb"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"eq"); + stkp = stkp + INTSIZE; +} + +/* + * not equal + * + */ +void gne (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"neb"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"ne"); + stkp = stkp + INTSIZE; +} + +/* + * less than (signed) + * + */ +/*void glt (intptr_t lvl) */ +void glt (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"ltb"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"lt"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (signed) + * + */ +void gle (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"leb"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"le"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (signed) + * + */ +void ggt (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"gtb"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"gt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (signed) + * + */ +void gge (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"geb"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"ge"); + stkp = stkp + INTSIZE; +} + +/* + * less than (unsigned) + * + */ +/*void gult (intptr_t lvl)*/ +void gult (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"ublt"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"ult"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (unsigned) + * + */ +void gule (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"uble"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"ule"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (unsigned) + * + */ +void gugt (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"ubgt"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"ugt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (unsigned) + * + */ +void guge (int is_byte) +{ + if (is_byte) + out_ins(I_JSR, T_LIB, (intptr_t)"ubge"); + else + out_ins(I_JSR, T_LIB, (intptr_t)"uge"); + stkp = stkp + INTSIZE; +} + +void scale_const (int type, int otag, intptr_t *size) +{ + switch (type) { + case CINT: + case CUINT: + *size += *size; + break; + case CSTRUCT: + *size *= tag_table[otag].size; + break; + default: + break; + } +} + +void gcast (int type) +{ + switch (type) { + case CCHAR: + out_ins(I_EXTW, 0, 0); + break; + case CUCHAR: + out_ins(I_EXTUW, 0, 0); + break; + case CINT: + case CUINT: + case CVOID: + break; + default: + abort(); + } + ; +} + +void gsei (void) +{ + out_ins(I_SEI, 0, 0); +} +void gcli (void) +{ + out_ins(I_CLI, 0, 0); +} diff --git a/src/huc/gen.h b/src/huc/gen.h new file mode 100644 index 00000000..d1ce72b1 --- /dev/null +++ b/src/huc/gen.h @@ -0,0 +1,65 @@ +#ifndef _GEN_H +#define _GEN_H + +intptr_t getlabel (void); +void getmem (SYMBOL *sym); +void getio (SYMBOL *sym); +void getvram (SYMBOL *sym); +void getloc (SYMBOL *sym); +void putmem (SYMBOL *sym); +void putstk (char typeobj); +void putio (SYMBOL *sym); +void putvram (SYMBOL *sym); +void indirect (char typeobj); +void farpeek (SYMBOL *ptr); +void immed (intptr_t type, intptr_t data); +void gpush (void); +void gpusharg (intptr_t size); +void gpop (void); +void swapstk (void); +void gcall (char *sname, intptr_t nargs); +void gmacro (char *sname, intptr_t nargs); +void gbank (unsigned char bank, unsigned short offset); +void gret (void); +void callstk (intptr_t nargs); +void jump (intptr_t label); +void testjump (intptr_t label, intptr_t ft); +intptr_t modstk (intptr_t newstkp); +void gaslint (void); +void gasrint (void); +void gjcase (void); +void gadd (LVALUE *lval, LVALUE *lval2); +void gsub (void); +void gmult (int is_unsigned); +void gmult_imm (int value); +void gdiv (int is_unsigned); +void gdiv_imm (int value); +void gmod (int is_unsigned); +void gor (void); +void gxor (void); +void gand (void); +void gasr (int is_unsigned); +void gasl (void); +void gneg (void); +void gcom (void); +void gbool (void); +void glneg (void); +void ginc (LVALUE *lval); +void gdec (LVALUE *lval); +void geq (int is_byte); +void gne (int is_byte); +void glt (int is_byte); +void gle (int is_byte); +void ggt (int is_byte); +void gge (int is_byte); +void gult (int is_byte); +void gule (int is_byte); +void gugt (int is_byte); +void guge (int is_byte); +void gcast (int type); +void gsei (void); +void gcli (void); + +void scale_const (int type, int otag, intptr_t *size); + +#endif diff --git a/src/huc/initials.c b/src/huc/initials.c new file mode 100644 index 00000000..e38109a7 --- /dev/null +++ b/src/huc/initials.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "error.h" +#include "lex.h" + +/** + * erase the data storage + */ +void create_initials() { + /*int i; + for (i=0; i= NUMGLBS) + error("initials table overrun"); + if (astreq(symbol_name, initials_table[initials_idx].name, NAMEMAX) != 0) { + result = 1; + break; + } + else { + // move to next symbol + // count position in data array + initials_data_idx += initials_table[initials_idx].data_len; + } + } + return (result); +} + +/** + * add data to table for given symbol + * @param symbol_name + * @param type + * @param value + * @param tag + */ +void add_data_initials (char *symbol_name, int type, int value, TAG_SYMBOL *tag) +{ + int position; + + if (find_symbol_initials(symbol_name) == 0) + add_symbol_initials(symbol_name, tag == 0 ? type : CSTRUCT); + if (tag != 0) { + // find number of members, dim is total number of values added + int index = initials_table[initials_idx].dim % tag->number_of_members; + int member_type = member_table[tag->member_idx + index].type; + // add it recursively + add_data_initials(symbol_name, member_type, value, 0); + } + else { + position = initials_table[initials_idx].data_len; + if (type == CCHAR || type == CUCHAR) { + initials_data_table[initials_data_idx + position] = 0xff & value; + initials_table[initials_idx].data_len += 1; + } + else { + initials_data_table[initials_data_idx + position] = (0xff00 & value) >> 8; + initials_data_table[initials_data_idx + position + 1] = 0xff & value; + initials_table[initials_idx].data_len += INTSIZE; + } + initials_table[initials_idx].dim += 1; + } +} + +/** + * get number of data items for given symbol + * @param symbol_name + * @return + */ +int get_size (char *symbol_name) +{ + int result = 0; + + if (find_symbol_initials(symbol_name) != 0) + result = initials_table[initials_idx].dim; + return (result); +} + +/** + * get item at position + * @param symbol_name + * @param position + * @param itag index of tag in tag table + * @return + */ +int get_item_at (char *symbol_name, int position, TAG_SYMBOL *tag) +{ + int result = 0, i, type; + + if (find_symbol_initials(symbol_name) != 0) { + if ((initials_table[initials_idx].type & ~CUNSIGNED) == CCHAR) + result = initials_data_table[initials_data_idx + position]; + else if ((initials_table[initials_idx].type & ~CUNSIGNED) == CINT) { + position *= INTSIZE; + result = (initials_data_table[initials_data_idx + position] << 8) + + (unsigned char)initials_data_table[initials_data_idx + position + 1]; + } + else if (initials_table[initials_idx].type == CSTRUCT) { + // find number of members + int number_of_members = tag->number_of_members; + // point behind the last full struct + int index = (position / number_of_members) * tag->size; + // move to required member + for (i = 0; i < (position % number_of_members); i++) { + type = member_table[tag->member_idx + i].type; + if (type == CCHAR || type == CUCHAR) + index += 1; + else + index += INTSIZE; + } + // get value + type = member_table[tag->member_idx + i].type; + if (type == CCHAR || type == CUCHAR) + result = initials_data_table[initials_data_idx + index]; + else { + result = (initials_data_table[initials_data_idx + index] << 8) + + (unsigned char)initials_data_table[initials_data_idx + index + 1]; + } + } + } + return (result); +} diff --git a/src/huc/initials.h b/src/huc/initials.h new file mode 100644 index 00000000..810dff18 --- /dev/null +++ b/src/huc/initials.h @@ -0,0 +1,5 @@ +#include "defs.h" +void add_data_initials (char *symbol_name, int type, int value, TAG_SYMBOL *tag); +int get_item_at (char *symbol_name, int position, TAG_SYMBOL *tag); +int get_size (char *symbol_name); +int find_symbol_initials (char *symbol_name); diff --git a/src/huc/io.c b/src/huc/io.c new file mode 100644 index 00000000..5be7e75e --- /dev/null +++ b/src/huc/io.c @@ -0,0 +1,613 @@ +/* File io.c: 2.1 (83/03/20,16:02:07) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "io.h" +#include "optimize.h" +#include "preproc.h" +#include "main.h" +#include "code.h" + +/* + * open input file + * Input : char* p + * Output : intptr_t error code + * + * Try to open the file whose filename is p, return YES if opened, else NO + * Updates fname with the actual opened name + * input is the handle of the opened file + * + */ +intptr_t openin (char *p) +{ + strcpy(fname, p); + strcpy(fname_copy, fname); + fixname(fname); + if (!checkname(fname)) { + fprintf(stderr, "%s: unknown file type\n", fname); + return (NO); + } + if ((input = fopen(fname, "r")) == NULL) { + perror(fname); + return (NO); + } + kill(); + return (YES); +} + +/* + * open output file + * Input : nothing but uses global fname + * Output : nothing but fname contain the name of the out file now + * + * Guess the name of the outfile thanks to the input one and try to open it + * In case of succes returns YES and output is the handle of the opened file + * else returns NO + * + */ +intptr_t openout (void) +{ + if (user_outfile[0]) + output = fopen(user_outfile, "w"); + else { + outfname(fname); + output = fopen(fname, "w"); + } + if (output == NULL) { + pl("Open failure : "); + if (user_outfile[0]) + pl(user_outfile); + else + pl(fname); + pl("\n"); + return (NO); + } + kill(); + return (YES); +} + +/* + * change input filename to output filename + * Input : char* s + * Output : char* s is updated + * + * Simply replace the last letter of s by 's' + * Used to return "file.s" from "file.c" + * + */ +void outfname (char *s) +{ + while (*s) + s++; + *--s = 's'; +} + +/* + * remove NL from filenames + * Input : char* s + * Output : char* s is updated + * + * if any, remove the trailing newline char from the s string + * + */ +void fixname (char *s) +{ + while (*s && *s++ != EOL) ; + if (!*s) return; + + *(--s) = 0; +} + +/* + * check that filename is "*.c" + * Input : char* s + * Output : intptr_t + * + * verify that the 2 last letter of s are ".c", returns YES in this case, + * else NO + * + */ +intptr_t checkname (char *s) +{ + while (*s) + s++; + if (*--s != 'c' && *s != 'C') + return (NO); + + if (*--s != '.') + return (NO); + + return (YES); +} + +/* + * kill + * Input : nothing + * Output : nothing but updates lptr and line[lptr] + * + * lptr and line[lptr] are set to zero what appears to clear the current + * input line + * + */ +void kill (void) +{ + lptr = 0; + line[lptr] = 0; +} + +/* + * unget_line + * Input : # of characters to kill preceding what we see in line[lptr] + * Output : nothing + * + * This function looks at line and lptr variables with a line of text + * and moves the file pointer back as though the line was never read + * then kills line/lptr + * + * Only use this function for operations at the top level (ie. the + * file pointer 'fp') + * + */ +void unget_line (void) +{ + intptr_t i; + + i = strlen(line); + if (i > 0) { + fseek(input, 0 - i - CR_LEN, SEEK_CUR); + line_number--; + } + + kill(); +} + + +/* + * readline + * Input : nothing + * Output : nothing + * + * This function seems to fill line and lptr variables with a line of text + * coming either form an included file or the main one + * + */ +void readline (void) +{ + intptr_t k; + FILE *unit; + + FOREVER { + if (!input || feof(input)) + return; + + if ((unit = input2) == NULL) + unit = input; + kill(); + while ((k = fgetc(unit)) != EOF) { + if ((k == '\r') | (k == EOL) | (lptr >= LINEMAX)) + break; + line[lptr++] = k; + } + line_number++; + line[lptr] = 0; + if (k <= 0) + if (input2 != NULL) { + if (globals_h_in_process) { + /* Add special treatment to ensure globals.h stuff appears at the beginning */ + dumpglbs(); + ol(".code"); + globals_h_in_process = 0; + } + input2 = inclstk[--inclsp]; + line_number = inclstk_line[inclsp]; + fclose(unit); + } + if (lptr) { + if ((ctext) & (cmode)) { + flush_ins(); + comment(); + tab(); + tab(); + tab(); + tab(); + tab(); + tab(); + outstr(line); + nl(); + } + lptr = 0; + return; + } + } +} + +/* + * inbyte + * Input : nothing + * Output : intptr_t, (actualy char) + * + * Uses the preprocessor as much as possible to get readable data + * then read the next char and make lptr points to the next one + * + */ +intptr_t inbyte (void) +{ + while (ch() == 0) { + if (feof(input)) + return (0); + + preprocess(); + } + return (gch()); +} + +/* + * inchar + * Input : nothing + * Output : intptr_t, (actualy char) + * + * Returns the current char, making lptr points to the next one + * If the buffer if empty, fill it with next line from input + * + */ +intptr_t inchar (void) +{ + if (ch() == 0) + readline(); + if (feof(input)) + return (0); + + return (gch()); +} + +/* + * gch + * Input : nothing + * Output : intptr_t, (actualy char) + * + * If the pointed char (by line and lptr) is 0, return this value + * else return the current pointed char and advance the lptr to point + * on the following char + * + */ +intptr_t gch (void) +{ + if (ch() == 0) + return (0); + else + return (line[lptr++] & 127); +} + +/* + * nch + * Input : nothing + * Output : intptr_t, (actualy char) + * + * If called when the pointed char is at the end of the line, return 0 + * else return the following char + * Doesn't change line nor lptr variable + * + */ +intptr_t nch (void) +{ + if (ch() == 0) + return (0); + else + return (line[lptr + 1] & 127); +} + +/* + * ch + * + * Input : nothing but use global line and lptr variables + * Output : intptr_t, (actually char), corresponding to the current pointed char + * during the parsing + * + * Appears to be the major function used during the parsing. + * The global variables line and lptr aren't changed + * + */ +intptr_t ch (void) +{ + return (line[lptr] & 127); +} + +/* + * print a carriage return and a string only to console + * + */ +void pl (char *str) +/*char *str; */ +{ + intptr_t k; + + k = 0; + putchar(EOL); + while (str[k]) + putchar(str[k++]); +} + +/* + * glabel - generate label + */ +void glabel (char *lab) +/*char *lab;*/ +{ + flush_ins(); /* David - optimize.c related */ + prefix(); + outstr(lab); + col(); + nl(); +} + +/* + * gnlabel - generate numeric label + */ +void gnlabel (intptr_t nlab) +{ + out_ins(I_LABEL, T_VALUE, nlab); +} + +/* + * Output internal generated label prefix + */ +void olprfix (void) +{ + outstr("LL"); +} + +/* + * Output a label definition terminator + */ +void col (void) +{ + outstr(":\n"); +} + +/* + * begin a comment line for the assembler + * + */ +void comment (void) +{ + outbyte(';'); +} + +/* + * Output a prefix in front of user labels + */ +void prefix (void) +{ + outbyte('_'); +} + +/* + * tab + * Input : nothing + * Output : nothing + * + * Write a tab charater in the assembler file + * + */ +void tab (void) +{ + outbyte(9); +} + +/* + * ol + * Input : char* ptr + * Output : nothing + * + * Writes the string ptr to the assembler file, preceded by a tab, ended by + * a newline + * + */ +void ol (char *ptr) +/*char ptr[]; */ +{ + ot(ptr); + nl(); +} + +/* + * ot + * Input : char* ptr + * Output : nothing + * + * Writes the string ptr to the assembler file, preceded by a tab + * + */ +void ot (char *ptr) +/*char ptr[]; */ +{ + tab(); + outstr(ptr); +} + +/* + * nl + * Input : nothing + * Output : nothing + * + * Display a newline in the assembler file + * + */ +void nl (void) +{ + outbyte(EOL); +} + +/* + * outsymbol + * Input : char* ptr + * Output : nothing + * + * Writes the string ptr preceded with the result of the function prefix + * + */ +void outsymbol (char *ptr) +{ + /* Hmmm... try to improve check for things on zero-page */ + + if (strcmp(ptr, "_temp") == 0) + outstr("<"); + prefix(); + outstr(ptr); +} + +/* + * print specified number as label + */ +void outlabel (intptr_t label) +{ + olprfix(); + outdec(label); +} + +/* + * Output a decimal number to the assembler file + */ +/* + void outdec (intptr_t number) + { + intptr_t k, zs; + char c; + + if (number == -32768) { + outstr ("-32768"); + return; + } + zs = 0; + k = 10000; + if (number < 0) { + number = (-number); + outbyte ('-'); + } + while (k >= 1) { + c = number / k + '0'; + if ((c != '0' | (k == 1) | zs)) { + zs = 1; + outbyte (c); + } + number = number % k; + k = k / 10; + } + } + */ + +/* Newer version, shorter and certainly faster */ +void outdec (intptr_t number) +{ + char s[21]; + int i = 0; + + sprintf(s, "%ld", (long) number); + + while (s[i]) + outbyte(s[i++]); +} + +/* + * Output an hexadecimal unsigned number to the assembler file + */ + +/* + void outhex (intptr_t number) + { + intptr_t k, zs; + char c; + + zs = 0; + k = 0x10000000; + + outbyte('$'); + + while (k >= 1) { + c = number / k; + if (c <= 9) + c += '0'; + else + c += 'A' - 10; + + outbyte (c); + + number = number % k; + k = k / 16; + } + } + */ + +/* Newer version, shorter and certainly faster */ +void outhex (intptr_t number) +{ + int i = 0; + char s[10]; + + outbyte('$'); + + sprintf(s, "%0X", (int)number); + + while (s[i]) + outbyte(s[i++]); +} + +/* + * Output an hexadecimal number with a certain number of digits + */ +void outhexfix (intptr_t number, intptr_t length) +{ + int i = 0; + char s[10]; + char format[10]; + + outbyte('$'); + + sprintf(format, "%%0%dX", (int)length); + + sprintf(s, format, number); + + while (s[i]) + outbyte(s[i++]); +} + + +/* + * outbyte + * Input : char c + * Output : same as input, c + * + * if c is different of zero, write it to the output file + * + */ +char outbyte (char c) +{ + if (c == 0) + return (0); + + fputc(c, output); + return (c); +} + +/* + * outstr + * Input : char*, ptr + * Output : nothing + * + * Send the input char* to the assembler file + * + */ +void outstr (char *ptr) +/*char ptr[];*/ +{ + intptr_t k; + + k = 0; + while (outbyte(ptr[k++])) ; +} diff --git a/src/huc/io.h b/src/huc/io.h new file mode 100644 index 00000000..4f747597 --- /dev/null +++ b/src/huc/io.h @@ -0,0 +1,56 @@ +/* File io.h: 2.1 (83/03/20,16:02:07) */ +/*% cc -O -c % + * + */ + +#ifndef _IO_H +#define _IO_H + +#if defined(WIN32) +#define CR_LEN 2 +#else +#define CR_LEN 1 +#endif + + +intptr_t openin (char *p); +intptr_t openout (void); +void outfname (char *s); +void fixname (char *s); +intptr_t checkname (char *s); +#if defined(__APPLE__) || defined(__CYGWIN__) +void _kill (void); +#define kill _kill +#else +void kill (void); +#endif +void unget_line (void); +void readline (void); + +/* could otherwise be char */ +intptr_t inbyte (void); +intptr_t inchar (void); +intptr_t gch (void); +intptr_t nch (void); +intptr_t ch (void); + +void pl (char *str); +void glabel (char *lab); +void gnlabel (intptr_t nlab); +void olprfix (void); +void col (void); +void comment (void); +void prefix (void); +void tab (void); +void ol (char *ptr); +void ot (char *ptr); +void nl (void); +void outsymbol (char *ptr); +void outlabel (intptr_t label); +void outdec (intptr_t number); +void outhex (intptr_t number); +void outhexfix (intptr_t number, intptr_t length); +char outbyte (char c); +void outstr (char *ptr); + +#endif diff --git a/src/huc/lex.c b/src/huc/lex.c new file mode 100644 index 00000000..17ad635e --- /dev/null +++ b/src/huc/lex.c @@ -0,0 +1,175 @@ +/* File lex.c: 2.1 (83/03/20,16:02:09) */ +/*% cc -O -c % + * + */ + +#include +#include +#include "defs.h" +#include "data.h" +#include "error.h" +#include "io.h" +#include "lex.h" +#include "preproc.h" + +/* + * semicolon enforcer + * + * called whenever syntax requires a semicolon + * + */ +void ns (void) +{ + if (!match(";")) + error("missing semicolon"); +} + +void junk (void) +{ + if (an(inbyte())) + while (an(ch())) + gch(); + else + while (an(ch())) { + if (ch() == 0) + break; + gch(); + } + blanks(); +} + +intptr_t endst (void) +{ + blanks(); + return ((streq(line + lptr, ";") | (ch() == 0))); +} + +void needbrack (char *str) +{ + if (!match(str)) { + error("missing bracket"); + comment(); + outstr(str); + nl(); + } +} + +/* + * test if given character is alpha + * + */ +intptr_t alpha (char c) +{ + c = c & 127; + return (((c >= 'a') && (c <= 'z')) | + ((c >= 'A') && (c <= 'Z')) | + (c == '_')); +} + +/* + * test if given character is numeric + * + */ +intptr_t numeric (char c) +{ + c = c & 127; + return ((c >= '0') && (c <= '9')); +} + +/* + * test if given character is alphanumeric + * + */ +intptr_t an (char c) +{ + return ((alpha(c)) | (numeric(c))); +} + +intptr_t sstreq (char *str1) +{ + return (streq(line + lptr, str1)); +} + +intptr_t streq (char *str1, char *str2) +{ + intptr_t k; + + k = 0; + while (str2[k]) { + if ((str1[k] != str2[k])) + return (0); + + k++; + } + return (k); +} + +intptr_t astreq (char *str1, char *str2, intptr_t len) +{ + intptr_t k; + + k = 0; + while (k < len) { + if ((str1[k] != str2[k])) + break; + if (str1[k] == 0) + break; + if (str2[k] == 0) + break; + k++; + } + if (an(str1[k])) + return (0); + + if (an(str2[k])) + return (0); + + return (k); +} + +intptr_t match (char *lit) +{ + intptr_t k; + + blanks(); + k = streq(line + lptr, lit); + if (k) { + lptr = lptr + k; + return (1); + } + return (0); +} + +intptr_t amatch (char *lit, intptr_t len) +{ + intptr_t k; + + blanks(); + k = astreq(line + lptr, lit, len); + if (k) { + lptr = lptr + k; + while (an(ch())) + inbyte(); + return (1); + } + return (0); +} + +int lex_stop_at_eol = 0; + +void blanks (void) +{ + FOREVER { + while (ch() == 0 && !lex_stop_at_eol) { + preprocess(); + if (!input || feof(input)) + break; + } + if (ch() == ' ') + gch(); + else if (ch() == 9) + gch(); + else + return; + } +} diff --git a/src/huc/lex.h b/src/huc/lex.h new file mode 100644 index 00000000..0f6c51ff --- /dev/null +++ b/src/huc/lex.h @@ -0,0 +1,32 @@ +#ifndef _INCLUDE_LEX_H +#define _INCLUDE_LEX_H + +void ns (void); + +void junk (void); + +intptr_t endst (void); + +void needbrack (char *str); + +intptr_t alpha (char c); + +intptr_t numeric (char c); + +intptr_t an (char c); + +intptr_t sstreq (char *str1); + +intptr_t streq (char *str1, char *str2); + +intptr_t astreq (char *str1, char *str2, intptr_t len); + +intptr_t match (char *lit); + +intptr_t amatch (char *lit, intptr_t len); + +void blanks (void); + +extern int lex_stop_at_eol; + +#endif diff --git a/src/huc/main.c b/src/huc/main.c new file mode 100644 index 00000000..a2f86ef0 --- /dev/null +++ b/src/huc/main.c @@ -0,0 +1,1143 @@ +/* File main.c: 2.7 (84/11/28,10:14:56) + * + * PC Engine C Compiler + * based on Small C Compiler by Ron Cain, James E. Hendrix, and others + * hacked to work on PC Engine by David Michel + * work resumed by Zeograd + * work resumed again by Ulrich Hecht + * + * 00/02/22 : added oldargv variable to show real exe name in usage function + */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "code.h" +#include "const.h" +#include "enum.h" +#include "error.h" +#include "function.h" +#include "gen.h" +#include "initials.h" +#include "io.h" +#include "lex.h" +#include "main.h" +#include "optimize.h" +#include "pragma.h" +#include "preproc.h" +#include "primary.h" +#include "pseudo.h" +#include "sym.h" +#include "struct.h" + +static char **link_libs = 0; +static int link_lib_ptr; +static char **infiles = 0; +static int infile_ptr; + +static int user_norecurse = 0; + +#if !((__STDC_VERSION__ >= 201112L) || (_MSC_VER >= 1910)) +# if !defined(HAVE_STRCAT_S) +static int strcat_s(char* dst, size_t len, const char* src) { + size_t i; + if (!dst || !len) { + return EINVAL; + } + if (src) { + for (i = 0; i < len; i++) { + if (dst[i] == '\0') { + size_t j; + for (j = 0; (i+j) < len; j++) { + if ((dst[i+j] = src[j]) == '\0') { + return 0; + } + } + } + } + } + dst[0] = '\0'; + return EINVAL; +} +# endif // !HAVE_STRCAT_S + +# if !defined(HAVE_STRCPY_S) +static int strcpy_s(char* dst, size_t len, const char* src) { + if (!dst || !len) { + return EINVAL; + } + if (src) { + size_t i; + for (i = 0; i < len; i++) { + if ((dst[i] = src[i]) == '\0') { + return 0; + } + } + } + dst[0] = '\0'; + return EINVAL; +} +# endif // !HAVE_STRCPY_S +#endif + +static char *lib_to_file (char *lib) +{ + int i; + static char libfile[FILENAMESIZE]; + char **incd = include_dirs(); + + for (i = 0; incd[i]; i++) { + struct stat st; + sprintf(libfile, "%s/%s.c", incd[i], lib); + if (!stat(libfile, &st)) + return (libfile); + } + return (0); +} +static void dumpfinal (void); + +int main (int argc, char *argv[]) +{ + char *p, *pp, *bp; + char **oldargv = argv; + char **link_lib; + intptr_t smacptr; + int first = 1; + char *asmdefs_global_end; + + macptr = 0; + ctext = 0; + argc--; argv++; + errs = 0; + sflag = 0; + cdflag = 0; + verboseflag = 0; + startup_incl = 0; + optimize = 2; /* -O2 by default */ + overlayflag = 0; + asmdefs[0] = '\0'; + + while ((p = *argv++)) { + if (*p == '-') { + while (*++p) switch (*p) { + case 't': case 'T': + ctext = 1; + fprintf(stderr, "\nwarning: Outputting C source to the listing file disables some optimizations!\n\n"); + break; + + case 'c': + if (*(p + 1) == 'd') { + cdflag = 1; /* pass '-cd' to assembler */ + p++; + break; + } + else { + usage(oldargv[0]); + break; + } + + case 's': + if (strncmp(p, "scd", 3) == 0) { + cdflag = 2; /* pass '-scd' to assembler */ + p += 2; + break; + } + else if (strncmp(p, "sgx", 3) == 0) { + strcat(asmdefs, "_SGX = 1\n"); + defmac("_SGX"); + p += 2; + break; + } + /* fallthrough */ + case 'S': + sflag = 1; + break; + + /* defines to pass to assembler */ + case 'a': + if (strncmp(p, "acd", 3) == 0) { + cdflag = 2; /* pass '-scd' to assembler */ + strcat(asmdefs, "_AC = 1\n"); + defmac("_AC"); + p += 2; + break; + } + /* fallthrough */ + case 'A': + bp = ++p; + if (!*p) usage(oldargv[0]); + while (*p && *p != '=') p++; + strncat(asmdefs, bp, (p - bp)); +/* if (*p == '=') *p = '\t'; */ + bp = ++p; + strcat(asmdefs, "\t= "); + if (*bp == '\0') + strcat(asmdefs, "1\n"); + else { + strcat(asmdefs, bp); + strcat(asmdefs, "\n"); + } + break; + + + case 'v': + verboseflag = 1; + break; + + case 'd': case 'D': + bp = ++p; + if (!*p) usage(oldargv[0]); + while (*p && *p != '=') p++; + if (*p == '=') *p = '\t'; + while (*p) p++; + p--; + defmac(bp); + break; + + case 'o': + if (strncmp(p, "over", 4) == 0) { + overlayflag = 1; + if (strncmp(p, "overlay", 7) == 0) + p += 6; + else + p += 3; + } + else { + bp = ++p; + while (*p && *p != ' ' && *p != '\t') + p++; + memcpy(user_outfile, bp, p - bp); + user_outfile[p - bp] = 0; + p--; + } + break; + case 'O': + /* David, made -O equal to -O2 + * I'm too lazy to tape -O2 each time :) + */ + if (!p[1]) optimize = 2; + else optimize = atoi(++p); + break; + + case 'f': + p++; + if (!strcmp(p, "no-recursive")) { + user_norecurse = 1; + p += 11; + } + else if (!strcmp(p, "recursive")) { + user_norecurse = 0; + p += 8; + } + else if (!strcmp(p, "no-short-enums")) { + user_short_enums = 0; + p += 13; + } + else if (!strcmp(p, "short-enums")) { + user_short_enums = 1; + p += 10; + } + else if (!strcmp(p, "signed-char")) { + user_signed_char = 1; + p += 10; + } + else if (!strcmp(p, "unsigned-char")) { + user_signed_char = 0; + p += 12; + } + else + goto unknown_option; + break; + + case 'l': + bp = ++p; + while (*p && *p != ' ' && *p != '\t') + p++; + link_libs = realloc(link_libs, (link_lib_ptr + 2) * sizeof(*link_libs)); + link_libs[link_lib_ptr] = malloc(p - bp + 1); + memcpy(link_libs[link_lib_ptr], bp, p - bp); + link_libs[link_lib_ptr][p - bp] = 0; + strcat(asmdefs, "LINK_"); + strcat(asmdefs, link_libs[link_lib_ptr]); + strcat(asmdefs, "\t= 1\n"); + link_libs[++link_lib_ptr] = 0; + p--; + break; + + case 'm': + if (!strcmp(p + 1, "small")) { + strcat(asmdefs, "SMALL\t= 1\n"); + p += 5; + } + else { +unknown_option: + fprintf(stderr, "unknown option %s\n", p); + exit(1); + } + break; + + default: + usage(oldargv[0]); + } + } + else { + infiles = realloc(infiles, (infile_ptr + 2) * sizeof(*infiles)); + infiles[infile_ptr++] = p; + infiles[infile_ptr] = 0; + } + } + + smacptr = macptr; + if (!infiles) + usage(oldargv[0]); + printf(HUC_VERSION); + printf("\n"); + init_path(); + /* Remember the first file, it will be used as the base for the + output file name unless there is a user-specified outfile. */ + p = pp = infiles[0]; + /* Labels count is not reset for each file because labels are + global and conflicts would arise. */ + nxtlab = 0; + link_lib = link_libs; + infile_ptr = 1; + /* Remember where the global assembler defines end so we can + reset to that point for each file. */ + /* XXX: Even if we don't repeat the local asm defines, they + are still defined because we compile everything into one + assembly file. */ + asmdefs_global_end = asmdefs + strlen(asmdefs); + while (p) { + errfile = 0; + /* Truncate asm defines to the point where global + defines end. */ + asmdefs_global_end[0] = 0; + if (extension(p) == 'c' || extension(p) == 'C') { + glbptr = STARTGLB; + locptr = STARTLOC; + wsptr = ws; + inclsp = + iflevel = + skiplevel = + swstp = + litptr = + stkp = + errcnt = + ncmp = + lastst = + quote[1] = + const_nb = + line_number = 0; + macptr = smacptr; + input2 = NULL; + quote[0] = '"'; + cmode = 1; + glbflag = 1; + litlab = getlabel(); + member_table_index = 0; + memset(member_table, 0, sizeof(member_table)); + tag_table_index = 0; + norecurse = user_norecurse; + typedef_ptr = 0; + enum_ptr = 0; + enum_type_ptr = 0; + memset(fastcall_tbl, 0, sizeof(fastcall_tbl)); + defpragma(); + + /* Macros and globals have to be reset for each + file, so we have to define the defaults all over + each time. */ + defmac("__end\t__memory"); + addglb("__memory", ARRAY, CCHAR, 0, EXTERN, 0); + addglb("stack", ARRAY, CCHAR, 0, EXTERN, 0); + rglbptr = glbptr; + addglb("etext", ARRAY, CCHAR, 0, EXTERN, 0); + addglb("edata", ARRAY, CCHAR, 0, EXTERN, 0); + /* PCE specific externs */ + addglb("font_base", VARIABLE, CINT, 0, EXTERN, 0); + addglb_far("vdc", CINT); + addglb_far("vram", CCHAR); + /* end specific externs */ + defmac("huc6280\t1"); + defmac("huc\t1"); + + if (cdflag == 1) + defmac("_CD\t1"); + else if (cdflag == 2) + defmac("_SCD\t1"); + else + defmac("_ROM\t1"); + + if (overlayflag == 1) + defmac("_OVERLAY\t1"); + +// initmac(); + /* + * compiler body + */ + if (!openin(p)) + exit(1); + if (first && !openout()) + exit(1); + if (first) + header(); + asmdefines(); +// gtext (); + parse(); + fclose(input); +// gdata (); + dumplits(); + dumpglbs(); + errorsummary(); +// trailer (); + pl(""); + errs = errs || errfile; + } + else { + fputs("Don't understand file ", stderr); + fputs(p, stderr); + fputc('\n', stderr); + exit(1); + } + p = infiles[infile_ptr]; + if (!p && link_lib && *link_lib) { + /* No more command-line files, continue with + libraries. */ + p = lib_to_file(*link_lib); + if (!p) { + fprintf(stderr, "cannot find library %s\n", *link_lib); + exit(1); + } + link_lib++; + } + else + infile_ptr++; + first = 0; + } + dumpfinal(); + fclose(output); + if (!errs && !sflag) { + if (user_outfile[0]) + errs = errs || assemble(user_outfile); + else + errs = errs || assemble(pp); + } + exit(errs != 0); +} + +void FEvers (void) +{ + outstr("\tFront End (2.7,84/11/28)"); +} + +void usage (char *exename) +{ + fprintf(stderr, HUC_VERSION); + fprintf(stderr, "\n\n"); + fprintf(stderr, "USAGE: %s [-options] infile\n", exename); + fprintf(stderr, "\nCompiler options:\n"); + fprintf(stderr, "-Dsym[=val] define symbol 'sym' when compiling\n"); + fprintf(stderr, "-O[val] invoke optimization (level )\n"); + fprintf(stderr, "-fno-recursive optimize assuming non-recursive code\n"); + fprintf(stderr, "-fno-short-enums always use signed int for enums\n"); + fprintf(stderr, "-msmall use single-byte stack pointer\n"); + fprintf(stderr, "\nOutput options:\n"); + fprintf(stderr, "-s/-S create asm output only (do not invoke assembler)\n"); + fprintf(stderr, "\nLinker options:\n"); + fprintf(stderr, "-lname add library 'name.c' from include path\n"); + fprintf(stderr, "-cd create CD-ROM output\n"); + fprintf(stderr, "-scd create Super CD-ROM output\n"); + fprintf(stderr, "-acd create Arcade Card CD output\n"); + fprintf(stderr, "-sgx enable SuperGrafx support\n"); + fprintf(stderr, "-over(lay) create CD-ROM overlay section\n"); + fprintf(stderr, "\nAssembler options:\n"); + fprintf(stderr, "-Asym[=val] define symbol 'sym' to assembler\n"); + fprintf(stderr, "\nDebugging options:\n"); + fprintf(stderr, "-t/-T include C source code in assembler output/listings\n"); + fprintf(stderr, "-v/-V increase verbosity of output files\n\n"); + exit(1); +} + +/* + * process all input text + * + * at this level, only static declarations, defines, includes, + * and function definitions are legal. + * + */ +void parse (void) +{ + if (!startup_incl) { + inc_startup(); + incl_globals(); + } + + while (1) { + blanks(); + if (feof(input)) + break; +// Note: +// At beginning of 'parse' call, the header has been output to '.s' +// file, as well as all the -Asym=val operands from command line. +// +// But initial '#include "startup.asm"' statement was not yet output +// (allowing for additional asm define's to be parsed and output first. +// +// We can parse some trivial tokens first (including the asmdef...), +// but the #include "startup.asm" line must be output before actual code +// (And only once...) +// + if (amatch("#asmdef", 7)) { + doasmdef(); + continue; + } + + if (amatch("extern", 6)) + dodcls(EXTERN, NULL_TAG, 0); + else if (amatch("static", 6)) { + if (amatch("const", 5)) { + /* XXX: what about the static part? */ + dodcls(CONST, NULL_TAG, 0); + } + else + dodcls(STATIC, NULL_TAG, 0); + } + else if (amatch("const", 5)) + dodcls(CONST, NULL_TAG, 0); + else if (amatch("typedef", 7)) + dotypedef(); + else if (dodcls(PUBLIC, NULL_TAG, 0)) ; + else if (match("#asm")) + doasm(); + else if (match("#include")) + doinclude(); + else if (match("#inc")) + dopsdinc(); + else if (match("#def")) + dopsddef(); + else + newfunc(NULL, 0, 0, 0, 0); + } + if (optimize) + flush_ins(); +} + +/* + * parse top level declarations + */ +intptr_t dodcls (intptr_t stclass, TAG_SYMBOL *mtag, int is_struct) +{ + intptr_t err; + struct type t; + + blanks(); + + if (match_type(&t, NO, YES)) { + if (t.type == CSTRUCT && t.otag == -1) + t.otag = define_struct(t.sname, stclass, !!(t.flags & F_STRUCT)); + else if (t.type == CENUM) { + if (t.otag == -1) + t.otag = define_enum(t.sname, stclass); + t.type = enum_types[t.otag].base; + } + err = declglb(t.type, stclass, mtag, t.otag, is_struct); + } + else if (stclass == PUBLIC) + return (0); + else + err = declglb(CINT, stclass, mtag, NULL_TAG, is_struct); + + if (err == 2) /* function */ + return (1); + else if (err) { + kill(); + return (0); + } + else + ns(); + return (1); +} + +void dotypedef (void) +{ + struct type t; + + if (!match_type(&t, YES, NO)) { + error("unknown type"); + kill(); + return; + } + if (t.type == CENUM) { + if (t.otag == -1) { + if (user_short_enums) + warning(W_GENERAL, + "typedef to undefined enum; " + "assuming base type int"); + t.type = CINT; + } + else + t.type = enum_types[t.otag].base; + } + if (!symname(t.sname)) { + error("invalid type name"); + kill(); + return; + } + typedefs = realloc(typedefs, (typedef_ptr + 1) * sizeof(struct type)); + typedefs[typedef_ptr++] = t; + ns(); +} + +/* + * dump the literal pool + */ +void dumplits (void) +{ + intptr_t j, k; + + if ((litptr == 0) && (const_nb == 0)) + return; + + outstr("\t.data\n"); + outstr("\t.bank CONST_BANK\n"); + if (litptr) { + outlabel(litlab); + col(); + k = 0; + while (k < litptr) { + defbyte(); + j = 8; + while (j--) { + outdec(litq[k++] & 0xFF); + if ((j == 0) | (k >= litptr)) { + nl(); + break; + } + outbyte(','); + } + } + } + if (const_nb) + dump_const(); +} + +/** + * dump struct data + * @param symbol struct variable + * @param position position of the struct in the array, or zero + */ +int dump_struct (SYMBOL *symbol, int position) +{ + int dumped_bytes = 0; + int i, number_of_members, value; + + number_of_members = tag_table[symbol->tagidx].number_of_members; + for (i = 0; i < number_of_members; i++) { + // i is the index of current member, get type + int member_type = member_table[tag_table[symbol->tagidx].member_idx + i].type; + if (member_type == CCHAR || member_type == CUCHAR) { + defbyte(); + dumped_bytes += 1; + } + else { + /* XXX: compound types? */ + defword(); + dumped_bytes += 2; + } + if (position < get_size(symbol->name)) { + // dump data + value = get_item_at(symbol->name, position * number_of_members + i, &tag_table[symbol->tagidx]); + outdec(value); + } + else { + // dump zero, no more data available + outdec(0); + } + nl(); + } + return (dumped_bytes); +} + +static int have_init_data = 0; +/* Initialized data must be kept in one contiguous block; pceas does not + provide segments for that, so we keep the definitions and data in + separate buffers and dump them all together after the last input file. + */ +#define DATABUFSIZE 65536 +char data_buffer[DATABUFSIZE+256]; +int data_offset = 0; +char rodata_buffer[DATABUFSIZE+256]; +int rodata_offset = 0; + +char *current_buffer = NULL; +int current_offset = 0; + +/* + * buffered print symbol prefix character + * + */ +void prefixBuffer(void) +{ + current_buffer[current_offset++] = '_'; +} + +/* + * buffered print string + * + */ +void outstrBuffer (char *ptr) +{ + int i = 0; + + if (current_offset >= DATABUFSIZE) { + printf("HuC compiler overrun detected, DATABUFSIZE is too small!\n"); + exit(-1); + } + + while (ptr[i]) + current_buffer[current_offset++] = ptr[i++]; +} + +/* + * buffered print character + * + */ +char outbyteBuffer (char c) +{ + if (c == 0) + return (0); + + current_buffer[current_offset++] = c; + + return (c); +} + +/* + * buffered print decimal number + * + */ +void outdecBuffer (intptr_t number) +{ + if (current_offset >= DATABUFSIZE) { + printf("HuC compiler overrun detected, DATABUFSIZE is too small!\n"); + exit(-1); + } + + current_offset += sprintf(current_buffer + current_offset, "%ld", (long) number); +} + +/* + * buffered print pseudo-op to define a byte + * + */ +void nlBuffer (void) +{ + current_buffer[current_offset++] = EOL; +} + +/* + * buffered print pseudo-op to define a byte + * + */ +void defbyteBuffer (void) +{ + outstrBuffer(".db\t"); +} + +/* + * buffered print pseudo-op to define storage + * + */ +void defstorageBuffer (void) +{ + outstrBuffer(".ds\t"); +} + +/* + * buffered print pseudo-op to define a word + * + */ +void defwordBuffer (void) +{ + outstrBuffer(".dw\t"); +} + +/** + * buffered dump struct data + * @param symbol struct variable + * @param position position of the struct in the array, or zero + */ +int dump_structBuffer (SYMBOL *symbol, int position) +{ + int dumped_bytes = 0; + int i, number_of_members, value; + + number_of_members = tag_table[symbol->tagidx].number_of_members; + for (i = 0; i < number_of_members; i++) { + // i is the index of current member, get type + int member_type = member_table[tag_table[symbol->tagidx].member_idx + i].type; + if (member_type == CCHAR || member_type == CUCHAR) { + defbyteBuffer(); + dumped_bytes += 1; + } + else { + /* XXX: compound types? */ + defwordBuffer(); + dumped_bytes += 2; + } + if (position < get_size(symbol->name)) { + // dump data + value = get_item_at(symbol->name, position * number_of_members + i, &tag_table[symbol->tagidx]); + outdecBuffer(value); + } + else { + // dump zero, no more data available + outdecBuffer(0); + } + nlBuffer(); + } + return (dumped_bytes); +} + +/* + * dump all static variables + */ +void dumpglbs (void) +{ + intptr_t i = 1; + int dim, list_size, line_count; + int j; + FILE *save = output; + + /* This is done in several passes: + Pass 0: Dump initialization data into const bank. + Pass 1: Define space for uninitialized data. + Pass 2: Define space for initialized data. + */ + if (glbflag) { + int pass = 0; +next: + i = 1; + for (cptr = rglbptr; cptr < glbptr; cptr++) { + if (cptr->ident != FUNCTION) { +// ppubext(cptr); + if ((cptr->storage & WRITTEN) == 0 && /* Not yet written to file */ + cptr->storage != EXTERN) { + dim = cptr->offset; + if (find_symbol_initials(cptr->name)) { + // has initials + /* dump initialization data */ + if (pass == 1) /* initialized data not handled in pass 1 */ + continue; + else if (pass == 2) { + /* define space for initialized data */ + current_buffer = data_buffer; + current_offset = data_offset; + if (cptr->storage != LSTATIC) + prefixBuffer(); + outstrBuffer(cptr->name); + outstrBuffer(":\t"); + defstorageBuffer(); + outdecBuffer(cptr->size); + nlBuffer(); + cptr->storage |= WRITTEN; + data_offset = current_offset; + current_buffer = NULL; + current_offset = 0; + continue; + } + /* output initialization data into const bank */ + current_buffer = rodata_buffer; + current_offset = rodata_offset; + have_init_data = 1; + list_size = 0; + line_count = 0; + list_size = get_size(cptr->name); + if (cptr->type == CSTRUCT) + list_size /= tag_table[cptr->tagidx].number_of_members; + if (dim == -1) + dim = list_size; + int item; + /* dim is an item count for non-compound types and a byte size + for compound types; dump_struct() wants an item number, so + we have to count both to get the right members out. */ + for (j = item = 0; j < dim; j++, item++) { + if (cptr->type == CSTRUCT) + j += dump_structBuffer(cptr, item) - 1; + else { + if (line_count % 10 == 0) { + nlBuffer(); + if (cptr->type == CCHAR || cptr->type == CUCHAR) + defbyteBuffer(); + else + defwordBuffer(); + } + if (j < list_size) { + // dump data + int value = get_item_at(cptr->name, j, &tag_table[cptr->tagidx]); + outdecBuffer(value); + } + else { + // dump zero, no more data available + outdecBuffer(0); + } + line_count++; + if (line_count % 10 == 0) + line_count = 0; + else { + if (j < dim - 1) + outbyteBuffer(','); + } + } + } + nlBuffer(); + rodata_offset = current_offset; + current_buffer = NULL; + current_offset = 0; + } + else { + if (pass == 0) + continue; + /* define space in bss */ + if (i) { + i = 0; + nl(); + gdata(); + } + if (cptr->storage != LSTATIC) + prefix(); + outstr(cptr->name); + outstr(":\t"); + defstorage(); + outdec(cptr->size); + nl(); + cptr->storage |= WRITTEN; + } + } + } + else { +// fpubext(cptr); + } + } + if (++pass < 3) + goto next; + } + if (i) { + nl(); + gdata(); + } + output = save; +} + +static void dumpfinal (void) +{ + int i; + + if (leaf_cnt) { + outstr("leaf_loc: .ds "); + outdec(leaf_size); + nl(); + for (i = 0; i < leaf_cnt; i++) { + outstr("__"); + outstr(leaf_functions[i]); + outstr("_lend:\n"); + } + } + if (rodata_offset == 0) { + outstr("huc_rodata:\n"); + outstr("__huc_rodata:\n"); + outstr("huc_rodata_end:\n"); + outstr("__huc_rodata_end:\n"); + } + outstr("huc_data:\n"); + outstr("__huc_data:\n"); + if (data_offset != 0) { + data_buffer[data_offset] = '\0'; + outstr(data_buffer); + } + outstr("huc_data_end:\n"); + outstr("__huc_data_end:\n"); + if (globals_h_in_process != 1) + outstr("__heap_start:\n"); + if (rodata_offset != 0) { + rodata_buffer[rodata_offset] = '\0'; + ol(".data"); + ol(".bank CONST_BANK"); + outstr("huc_rodata:\n"); + outstr("__huc_rodata:\n"); + outstr(rodata_buffer); + outstr("huc_rodata_end:\n"); + outstr("__huc_rodata_end:\n"); + } + fseek(output, output_globdef, SEEK_SET); + if (have_irq_handler || have_sirq_handler) + outstr("HAVE_IRQ = 1\n"); + if (have_sirq_handler) + outstr("HAVE_SIRQ = 1\n"); + if (have_init_data) + outstr("HAVE_INIT = 1\n"); +} + +/* + * report errors + */ +void errorsummary (void) +{ + if (ncmp) + error("missing closing bracket"); + nl(); + comment(); + outdec(errcnt); + if (errcnt) errfile = YES; + outstr(" error(s) in compilation"); + nl(); + comment(); + ot("literal pool:"); + outdec(litptr); + nl(); + comment(); + ot("constant pool:"); + outdec(const_size); + nl(); + comment(); + ot("global pool:"); + outdec(glbptr - rglbptr); + nl(); + comment(); + ot("Macro pool:"); + outdec(macptr); + nl(); + pl(errcnt ? "Error(s)" : "No errors"); +} + +char extension (char *s) +{ + s += strlen(s) - 2; + if (*s == '.') + return (*(s + 1)); + + return (' '); +} + +intptr_t assemble (char *s) +{ +#if defined(_WIN32) + + char *exe; + char buf[512]; + char* p; + + exe = getenv("PCE_PCEAS"); + if (!exe) { + exe = "pceas.exe"; + } + + strcpy_s(buf, sizeof(buf), exe); + strcat_s(buf, sizeof(buf), " "); + for (p = buf; (p = strchr(p, '/')) != NULL; *p++ = '\\'); + + switch (cdflag) { + case 1: + strcat_s(buf, sizeof(buf), "-cd "); + break; + + case 2: + strcat_s(buf, sizeof(buf), "-scd "); + break; + + default: + strcat_s(buf, sizeof(buf), "-raw -pad "); + break; + } + + if (overlayflag) + strcat_s(buf, sizeof(buf), "-over "); + + if (verboseflag) { + strcat_s(buf, sizeof(buf), "-S -l 3 -m "); + } + + strcat_s(buf, sizeof(buf), "-O "); + + strcat_s(buf, sizeof(buf), "\""); + strcat_s(buf, sizeof(buf), s); + buf[strlen(buf) - 1] = 's'; + strcat_s(buf, sizeof(buf), "\""); + +// Comment this out later... +// printf("invoking pceas:\n"); +// printf("%s\n", buf); + + return (system(buf)); + +#elif defined(__unix__) || defined(__APPLE__) + + char *exe; + char buf[256]; + char *opts[12]; + intptr_t i = 0; + + exe = getenv("PCE_PCEAS"); + if (!exe) { + exe = "pceas"; + } + opts[i++] = exe; + switch (cdflag) { + case 1: + opts[i++] = "-cd"; + break; + + case 2: + opts[i++] = "-scd"; + break; + + default: + opts[i++] = "-raw"; + opts[i++] = "-pad"; + break; + } + + if (overlayflag) + opts[i++] = "-over"; /* compile as overlay */ + + if (verboseflag) { + opts[i++] = "-S"; /* asm: display full segment map */ + opts[i++] = "-l 3"; /* top listing output */ + opts[i++] = "-m"; /* force macros also */ + } + else + opts[i++] = "-l 0"; + + opts[i++] = "-O"; /* optimize procedure packing */ + + strcpy(buf, s); + buf[strlen(buf) - 1] = 's'; + opts[i++] = buf; + + opts[i++] = 0; + +// Comment this out later... +// { +// intptr_t j; +// printf("invoking pceas:\n"); +// for (j = 0; j < i; j++) +// printf("arg[%d] = %s\n", j, opts[j]); +// } + + return (execvp(exe, (char *const *)opts)); + +#else +#error Add calling sequence depending on your OS +#endif +} diff --git a/src/huc/main.h b/src/huc/main.h new file mode 100644 index 00000000..144b011a --- /dev/null +++ b/src/huc/main.h @@ -0,0 +1,32 @@ +/* File main.c: 2.7 (84/11/28,10:14:56) + * + * PC Engine C Compiler + * Made by , hacked to work on Pc Engine by David Michel + * resumed work by Zeograd + * + * 00/02/22 : added oldargv variable to show real exe name in usage function + */ +/*% cc -O -c % + * + */ + +#ifndef _MAIN_H +#define _MAIN_H + +#include "version.h" + +#define HUC_VERSION "HuC (" GIT_VERSION ", " GIT_DATE ")" + +void FEvers (void); +void usage (char *exename); +void parse (void); +intptr_t dodcls (intptr_t stclass, TAG_SYMBOL *mtag, int is_struct); +void dumplits (void); +void dumpglbs (void); +void errorsummary (void); +char extension (char *s); +intptr_t assemble (char *s); + +void dotypedef (void); + +#endif diff --git a/src/huc/optimize.c b/src/huc/optimize.c new file mode 100644 index 00000000..1ee079a2 --- /dev/null +++ b/src/huc/optimize.c @@ -0,0 +1,2026 @@ +/* File opt.c: 2.1 (83/03/20,16:02:09) */ +/*% cc -O -c % + * + */ + +// #define DEBUG_OPTIMIZER + +#ifdef DEBUG_OPTIMIZER +#define ODEBUG(x, ...) printf(x ...) +#else +#define ODEBUG(x, ...) +#endif + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "sym.h" +#include "code.h" +#include "function.h" +#include "io.h" +#include "error.h" + +#ifdef _MSC_VER +# include +# define __builtin_popcount __popcnt +# define __builtin_ctz __lzcnt +#endif + +/* defines */ +#define Q_SIZE 16 + +/* locals */ +static INS q_ins[Q_SIZE]; +static intptr_t q_rd; +static intptr_t q_wr; +static intptr_t q_nb; + +/* externs */ +extern intptr_t arg_stack_flag; + + +intptr_t cmp_operands (INS *p1, INS *p2) +{ +#ifdef DEBUG_OPTIMIZER + printf("cmp"); dump_ins(p1); dump_ins(p2); +#endif + if (p1->type != p2->type) + return (0); + + if (p1->type == T_SYMBOL) { + if (strcmp((char *)p1->data, (char *)p2->data) != 0) + return (0); + } + else { + if (p1->data != p2->data) + return (0); + } + return (1); +} + + +static int is_load (INS *i) +{ + return (i->code == I_LDB || + i->code == I_LDBP || + i->code == I_LDW || + i->code == I_LDWI || + i->code == I_LDWP || + i->code == I_LDUB || + i->code == I_LDUBP || + i->code == I_LDYB || + i->code == X_LDB || + i->code == X_LDB_S || + i->code == X_LDB_P || + i->code == X_LDW_S || + i->code == X_LDD_I || + i->code == X_LDD_S_B || + i->code == X_LDD_S_W || + i->code == X_LDUB || + i->code == X_LDUB_S || + i->code == X_LDUB_P); +} + +static int is_sprel (INS *i) +{ + return (i->code == X_LEA_S || + i->code == X_PEA_S || + i->code == X_LDB_S || + i->code == X_LDUB_S || + i->code == X_LDW_S || + i->code == X_LDD_S_B || + i->code == X_LDD_S_W || + i->code == X_STB_S || + i->code == X_STW_S || + i->code == X_INCW_S || + i->code == X_ADDW_S || + i->code == X_STBI_S || + i->code == X_ADDB_S || + i->code == X_ADDUB_S || + i->code == X_INCB_S || + i->code == X_STWI_S); +} + +/* ---- + * push_ins() + * ---- + * + */ +void push_ins (INS *ins) +{ +#ifdef DEBUG_OPTIMIZER + printf("push "); dump_ins(ins); +#endif + /* check queue size */ + if (q_nb == Q_SIZE) { + /* queue is full - flush the last instruction */ + if (arg_stack_flag) + arg_push_ins(&q_ins[q_rd]); + else + gen_code(&q_ins[q_rd]); + + /* advance queue read pointer */ + q_rd++; + q_nb--; + + if (q_rd == Q_SIZE) + q_rd = 0; + } + + /* push new instruction */ + q_wr++; + q_nb++; + + if (q_wr == Q_SIZE) + q_wr = 0; + + q_ins[q_wr] = *ins; + + /* optimization level 1 - simple peephole optimizer, + * replace known instruction patterns by highly + * optimized asm code + */ + if (optimize >= 1) { + INS *p[Q_SIZE]; + int i, j; + intptr_t nb; + +lv1_loop: + /* precalculate pointers to instructions */ + if (q_nb > 10) + nb = 10; + else + nb = q_nb; + for (i = 0, j = q_wr; i < nb; i++) { + /* save pointer */ + p[i] = &q_ins[j]; +#ifdef DEBUG_OPTIMIZER + printf("%d ", i); dump_ins(p[i]); +#endif + + /* next */ + j -= 1; + if (j < 0) + j += Q_SIZE; + } + + /* Convert intptr_t branches to near ones. + This currently assumes that no ten macroinsns in a row + will be larger than 128 bytes. */ + /* XXX: This is something the assembler should do, but + is currently incapable of. */ + { + int j; + for (j = 0; j < nb; j++) { + if (p[j]->code == I_LBNE || p[j]->code == I_LBEQ || + p[j]->code == I_LBRA) { + int i; + for (i = 0; i < nb; i++) { + if (p[i]->code == I_LABEL && + p[i]->data == p[j]->data) { + switch (p[j]->code) { + case I_LBNE: + p[j]->code = I_LBNEN; + break; + case I_LBEQ: + p[j]->code = I_LBEQN; + break; + case I_LBRA: + p[j]->code = I_LBRAN; + break; + } + break; + } + } + } + } + } + + /* LEVEL 1 - FUN STUFF STARTS HERE */ + nb = 0; + + /* 6-instruction patterns */ + if (q_nb >= 6) { + /* + * __ldwi p --> __ldw p + * __pushw __addwi i + * __stw __ptr __stw p + * __ldwp __ptr + * __addwi i + * __stwps + * + */ + if (p[0]->code == I_STWPS && + (p[1]->code == I_ADDWI || p[1]->code == I_SUBWI) && + p[2]->code == I_LDWP && p[2]->type == T_PTR && + p[3]->code == I_STW && p[3]->type == T_PTR && + p[4]->code == I_PUSHW && + p[5]->code == I_LDWI) { + *p[3] = *p[5]; + p[3]->code = I_STW; + *p[4] = *p[1]; + p[5]->code = I_LDW; + nb = 3; + } + + /* flush queue */ + if (nb) { + q_wr -= nb; + q_nb -= nb; + nb = 0; + + if (q_wr < 0) + q_wr += Q_SIZE; + + /* loop */ + goto lv1_loop; + } + } + + /* 5-instruction patterns */ + if (q_nb >= 5) { + /* Classical Base-offset array access: + * + * __ldwi label --> @_ldw_s n-2 + * __pushw __aslw + * @_ldw_s n __addwi label + * __aslw + * __addws + * + * ==== + * bytes : 4+23+ 8+ 4+24 = 63 --> 8+ 4+ 7 = 19 + * cycles : 4+49+20+ 8+41 =122 --> 20+ 8+10 = 38 + * + */ + if ((p[0]->code == I_ADDWS) && + (p[1]->code == I_ASLW) && + (p[2]->code == X_LDW_S) && + (p[3]->code == I_PUSHW) && + (p[4]->code == I_LDWI)) { + intptr_t tempdata; + + tempdata = p[2]->data; + + /* replace code */ + p[2]->code = I_ADDWI; + p[2]->type = p[4]->type; + p[2]->data = p[4]->data; + p[2]->sym = p[4]->sym; + p[3]->code = I_ASLW; + p[4]->code = X_LDW_S; + p[4]->data = tempdata - 2; + + nb = 2; + } + + /* Classical Base-offset array access: + * + * __ldwi label1 --> __ldw label2 + * __pushw __aslw + * __ldw label2 __addwi label1 + * __aslw + * __addws + * + * ==== + * bytes : 4+23+ 6+ 4+24 = 61 --> 6+ 4+ 7 = 17 + * cycles : 4+49+10+ 8+41 =112 --> 10+ 8+10 = 28 + * + */ + else + if ((p[0]->code == I_ADDWS) && + (p[1]->code == I_ASLW) && + (p[2]->code == I_LDW) && + (p[3]->code == I_PUSHW) && + (p[4]->code == I_LDWI)) { + intptr_t tempdata, temptype; + SYMBOL *tempsym; + + tempdata = p[2]->data; + tempsym = p[2]->sym; + temptype = p[2]->type; + + /* replace code */ + p[2]->code = I_ADDWI; + p[2]->type = p[4]->type; + p[2]->data = p[4]->data; + p[2]->sym = p[4]->sym; + p[3]->code = I_ASLW; + p[4]->code = I_LDW; + p[4]->data = tempdata; + p[4]->sym = tempsym; + p[4]->type = temptype; + + nb = 2; + } + + /* __ldwi a --> __ldyb i + * __pushw __ldby a + * __ldub i + * __addws + * __ldb_p + */ + else if (p[0]->code == X_LDB_P && + p[1]->code == I_ADDWS && + p[2]->code == I_LDUB && + p[3]->code == I_PUSHW && + p[4]->code == I_LDWI) { + *p[3] = *p[4]; + p[3]->code = I_LDBY; + *p[4] = *p[2]; + p[4]->code = I_LDYB; + nb = 3; + } + + /* flush queue */ + if (nb) { + q_wr -= nb; + q_nb -= nb; + nb = 0; + + if (q_wr < 0) + q_wr += Q_SIZE; + + /* loop */ + goto lv1_loop; + } + } + + /* 4-instruction patterns */ + if (q_nb >= 4) { + /* @_ldw/b/ub_s i --> @_ldw/b/ub_s i + * __addwi 1 @_incw/b_s i + * @_stw_s i + * __subwi 1 + * + */ + if ((p[0]->code == I_SUBWI) && + (p[1]->code == X_STW_S) && + (p[2]->code == I_ADDWI) && + (p[3]->code == X_LDW_S) && + + (p[0]->data == 1) && + (p[2]->data == 1) && + (p[1]->data == p[3]->data) && + (p[1]->data < 255)) { + /* replace code */ + p[2]->code = X_INCW_S; + p[2]->data = p[3]->data; + p[2]->sym = p[3]->sym; + nb = 2; + } + else if ((p[0]->code == I_SUBWI) && + (p[1]->code == X_STB_S) && + (p[2]->code == I_ADDWI) && + (p[3]->code == X_LDB_S || p[3]->code == X_LDUB_S) && + (p[0]->data == 1) && + (p[2]->data == 1) && + (p[1]->data == p[3]->data) && + (p[1]->data < 255)) { + /* replace code */ + p[2]->code = X_INCB_S; + p[2]->data = p[3]->data; + p[2]->sym = p[3]->sym; + nb = 2; + } + + /* @_ldwi i --> @_ldwi i * j + * __pushw + * __ldwi j + * jsr umul + */ + else if ((p[0]->code == I_JSR && p[0]->type == T_LIB && !strcmp((char *)p[0]->data, "umul")) && + (p[1]->code == I_LDWI && p[1]->type == T_VALUE) && + (p[2]->code == I_PUSHW) && + (p[3]->code == I_LDWI && p[3]->type == T_VALUE)) { + p[3]->data *= p[1]->data; + nb = 3; + } + + /* @_ldwi p --> __stwi p, i + * __pushw + * __ldwi i + * __st{b|w}ps + * + */ + else if ((p[0]->code == I_STWPS || p[0]->code == I_STBPS) && + (p[1]->code == I_LDWI) && + (p[2]->code == I_PUSHW) && + (p[3]->code == I_LDWI)) { + /* replace code */ + p[3]->code = p[0]->code == I_STWPS ? I_STWI : I_STBI; + p[3]->imm_type = p[1]->type; + p[3]->imm_data = p[1]->data; + nb = 3; + } + + /* __pushw --> addbi_p i + * __ldb_p + * __addwi i + * __stbps + */ + else if (p[0]->code == I_STBPS && + p[1]->code == I_ADDWI && + p[2]->code == X_LDB_P && + p[3]->code == I_PUSHW) { + *p[3] = *p[1]; + p[3]->code = I_ADDBI_P; + nb = 3; + } + + /* flush queue */ + if (nb) { + q_wr -= nb; + q_nb -= nb; + nb = 0; + + if (q_wr < 0) + q_wr += Q_SIZE; + + /* loop */ + goto lv1_loop; + } + } + + /* 3-instruction patterns */ + if (q_nb >= 3) { + /* __pushw --> __add[bw]i i + * __ldwi i + * __add[bw]s + * + * ==== + * bytes : 23+4+24 = 51 --> 7 + * cycles : 49+4+43 = 96 --> 12 + * + */ + if ((p[0]->code == I_ADDWS || p[0]->code == I_ADDBS) && + (p[1]->code == I_LDWI) && + (p[2]->code == I_PUSHW) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[2]->code = (p[0]->code == I_ADDWS) ? I_ADDWI : I_ADDBI; + p[2]->data = p[1]->data; + p[2]->type = T_VALUE; + nb = 2; + } + + /* __pushw --> __subwi i + * __ldwi i + * __subws + * + * ==== + * bytes : 23+4+31 = 58 --> 7 + * cycles : 49+4+65 =118 --> 12 + * + */ + else if ((p[0]->code == I_SUBWS) && + (p[1]->code == I_LDWI) && + (p[2]->code == I_PUSHW) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[2]->code = I_SUBWI; + p[2]->data = p[1]->data; + nb = 2; + } + + /* __pushw --> __andwi i + * __ldwi i + * __andws + * + * ==== + * bytes : 23+4+23 = 50 --> 6 + * cycles : 49+4+51 =104 --> 10 + * + */ + else if ((p[0]->code == I_ANDWS) && + (p[1]->code == I_LDWI) && + (p[2]->code == I_PUSHW) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[2]->code = I_ANDWI; + p[2]->data = p[1]->data; + nb = 2; + } + + /* __pushw --> __orwi i + * __ldwi i + * __orws + * + * ==== + * bytes : 23+4+23 = 50 --> 6 + * cycles : 49+4+51 =104 --> 10 + * + */ + else if ((p[0]->code == I_ORWS) && + (p[1]->code == I_LDWI) && + (p[2]->code == I_PUSHW) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[2]->code = I_ORWI; + p[2]->data = p[1]->data; + nb = 2; + } + + /* __pushw --> __st{b|w}ip i + * __ldwi i + * __st{b|w}ps + * + */ + else if ((p[0]->code == I_STWPS || p[0]->code == I_STBPS) && + (p[1]->code == I_LDWI) && + (p[2]->code == I_PUSHW) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[2]->code = p[0]->code == I_STWPS ? I_STWIP : I_STBIP; + p[2]->data = p[1]->data; + nb = 2; + } + + /* __pushw --> __asl/lsr/asrwi i + * __ldwi i + * jsr asl/lsr/asr + * + */ + else if (p[0]->code == I_JSR && + (!strcmp((char *)p[0]->data, "asl") || + !strcmp((char *)p[0]->data, "lsr") || + !strcmp((char *)p[0]->data, "asr")) && + (p[1]->code == I_LDWI) && + p[2]->code == I_PUSHW) { + /* replace code */ + if (!strcmp((char *)p[0]->data, "asl")) + p[2]->code = I_ASLWI; + else if (!strcmp((char *)p[0]->data, "lsr")) + p[2]->code = I_LSRWI; + else + p[2]->code = I_ASRWI; + p[2]->type = p[1]->type; + p[2]->data = p[1]->data; + nb = 2; + } + + /* __pushw --> __aslwi log2(i) + * __ldwi i or __mulwi i + * jsr {u|s}mul + * + */ + else if + (p[0]->code == I_JSR && + (!strcmp((char *)p[0]->data, "umul") || + !strcmp((char *)p[0]->data, "smul")) && + (p[1]->code == I_LDWI) && + (p[1]->type == T_VALUE) && + p[1]->data > 0 && p[1]->data < 0x8000 && + p[2]->code == I_PUSHW) { + p[2]->type = T_VALUE; + if (__builtin_popcount(p[1]->data) == 1) { + p[2]->code = I_ASLWI; + p[2]->data = __builtin_ctz(p[1]->data); + } + else { + p[2]->code = I_MULWI; + p[2]->data = p[1]->data; + } + nb = 2; + } + + /* __pushw --> __addb/w/ub/b_s/ub_s/w_s nnn + * __ldb/w/ub/b_s/ub_s/w_s nnn + * __addws + * + * ==== + * bytes : 23+ 6+24 = 53 --> 9 + * cycles : 49+10+43 =102 --> 18 + * + */ + else if ((p[0]->code == I_ADDWS) && + (p[1]->code == I_LDW || + p[1]->code == I_LDB || + p[1]->code == I_LDUB || + p[1]->code == X_LDB_S || + p[1]->code == X_LDUB_S || + p[1]->code == X_LDW_S) && + (p[2]->code == I_PUSHW)) { + /* replace code */ + switch (p[1]->code) { + case I_LDW: p[2]->code = I_ADDW; break; + case I_LDB: p[2]->code = I_ADDB; break; + case I_LDUB: p[2]->code = I_ADDUB; break; + case X_LDB_S: p[2]->code = X_ADDB_S; p[1]->data -= 2; break; + case X_LDUB_S: p[2]->code = X_ADDUB_S; p[1]->data -= 2; break; + case X_LDW_S: p[2]->code = X_ADDW_S; p[1]->data -= 2; break; + default: abort(); + } + p[2]->data = p[1]->data; + p[2]->type = p[1]->type; + nb = 2; + } + + /* __pushw --> __subw nnn + * __ldw nnn + * __subws + * + * ==== + * bytes : 23+ 6+31 = 60 --> 9 + * cycles : 49+10+65 =124 --> 18 + * + */ + else if ((p[0]->code == I_SUBWS) && + (p[1]->code == I_LDW) && + (p[2]->code == I_PUSHW)) { + /* replace code */ + p[2]->code = I_SUBW; + p[2]->data = p[1]->data; + p[2]->type = p[1]->type; + nb = 2; + } + + /* __pushw --> @_addw_s i-2 + * @_ldw_s i + * __addws + * + * ==== + * bytes : 23+ 8+24 = 55 --> 10 + * cycles : 49+20+43 = 112 --> 24 + * + */ + else if + ((p[0]->code == I_ADDWS) && + (p[1]->code == X_LDW_S) && + (p[2]->code == I_PUSHW)) { + /* replace code */ + p[2]->code = X_ADDW_S; + p[2]->data = p[1]->data - 2; + p[2]->sym = p[1]->sym; + nb = 2; + } + + /* @_pea_s j --> @_stbi_s i,j + * __ldwi i + * __stbps + * + * ==== + * bytes : 25+4+38 = 67 --> 9 + * cycles : 44+4+82 = 130 --> 15 + * + */ + else if + ((p[0]->code == I_STBPS) && + (p[1]->code == I_LDWI) && + (p[2]->code == X_PEA_S) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[2]->code = X_STBI_S; + p[2]->imm_type = p[1]->type; + p[2]->imm_data = p[1]->data; + nb = 2; + } + + /* @_pea_s j --> @_stwi_s i,j + * __ldwi i + * __stwps + * + * ==== + * bytes : 25+4+42 = 71 --> 12 + * cycles : 44+4+91 = 139 --> 24 + * + */ + else if + ((p[0]->code == I_STWPS) && + (p[1]->code == I_LDWI) && + (p[2]->code == X_PEA_S) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[2]->code = X_STWI_S; + p[2]->imm_type = p[1]->type; + p[2]->imm_data = p[1]->data; + nb = 2; + } + + /* @_pea_s i --> @_lea_s i+j + * __ldwi j + * __addws + * + * ==== + * bytes : 25+4+24 = 53 --> 10 + * cycles : 44+4+41 = 89 --> 16 + * + */ + else if + ((p[0]->code == I_ADDWS) && + (p[1]->code == I_LDWI) && + (p[2]->code == X_PEA_S) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[2]->code = X_LEA_S; + p[2]->data += p[1]->data; + nb = 2; + } + + /* @_lea_s i --> @_ldw_s i + * __stw __ptr + * __ldwp __ptr + * + * ==== + * bytes : 10+4+ 7 = 21 --> 8 + * cycles : 16+8+18 = 42 --> 20 + * + */ + else if + ((p[0]->code == I_LDWP) && + (p[1]->code == I_STW) && + (p[2]->code == X_LEA_S) && + + (p[0]->type == T_PTR) && + (p[1]->type == T_PTR)) { + /* replace code */ + p[2]->code = X_LDW_S; + nb = 2; + } + + /* @_ldwi i --> @_ldw/_ldub i + * __stw __ptr + * __ldwp/__ldubp __ptr + */ + else if + ((p[0]->code == I_LDWP || p[0]->code == I_LDUBP) && + (p[1]->code == I_STW) && + (p[2]->code == I_LDWI) && + + (p[0]->type == T_PTR) && + (p[1]->type == T_PTR)) { + /* replace code */ + if (p[0]->code == I_LDWP) + p[2]->code = I_LDW; + else + p[2]->code = I_LDUB; + nb = 2; + } + + /* @_pea_s i --> @_pea_s i + * __stw __ptr @_ldw_s i+2 + * __ldwp __ptr + * + * ==== + * bytes : 25+4+ 7 = 36 --> 25+ 8 = 33 + * cycles : 44+8+18 = 70 --> 44+20 = 64 + * + */ + else if + ((p[0]->code == I_LDWP) && + (p[1]->code == I_STW) && + (p[2]->code == X_PEA_S) && + + (p[0]->type == T_PTR) && + (p[1]->type == T_PTR) && + + (optimize >= 2)) { + /* replace code */ + p[1]->code = X_LDW_S; + p[1]->data = p[2]->data + 2; + p[1]->sym = p[2]->sym; + nb = 1; + } + + /* __pushw --> __stw <__temp + * __ldw(i) n / __ldw_s n __ldw(i) n / __ldw_s n-2 + * jsr eq/ne (etc.) jsr eqzp/nezp (etc.) + * + * ==== + * bytes : ? --> ? + * cycles : ? --> ? + * + */ + else if + ((p[0]->code == I_JSR) && + (p[1]->code == I_LDWI || + p[1]->code == I_LDW || + p[1]->code == X_LDW_S || + p[1]->code == I_LDB || + p[1]->code == X_LDB_S) && + (p[2]->code == I_PUSHW) && + ((strcmp((char *)p[0]->data, "eq") == 0) || + (strcmp((char *)p[0]->data, "eqb") == 0) || + (strcmp((char *)p[0]->data, "ne") == 0) || + (strcmp((char *)p[0]->data, "neb") == 0) || + (strcmp((char *)p[0]->data, "lt") == 0) || + (strcmp((char *)p[0]->data, "ltb") == 0) || + (strcmp((char *)p[0]->data, "ult") == 0) || + (strcmp((char *)p[0]->data, "ublt") == 0) || + (strcmp((char *)p[0]->data, "gt") == 0) || + (strcmp((char *)p[0]->data, "gtb") == 0) || + (strcmp((char *)p[0]->data, "ugt") == 0) || + (strcmp((char *)p[0]->data, "ubgt") == 0) || + (strcmp((char *)p[0]->data, "ge") == 0) || + (strcmp((char *)p[0]->data, "geb") == 0) || + (strcmp((char *)p[0]->data, "uge") == 0) || + (strcmp((char *)p[0]->data, "ubge") == 0) || + (strcmp((char *)p[0]->data, "le") == 0) || + (strcmp((char *)p[0]->data, "leb") == 0) || + (strcmp((char *)p[0]->data, "ule") == 0) || + (strcmp((char *)p[0]->data, "uble") == 0))) { + if (p[1]->code == X_LDW_S || p[1]->code == X_LDB_S) + p[1]->data -= 2; + /* replace code */ + p[2]->code = I_STW; + p[2]->type = T_SYMBOL; + p[2]->data = (intptr_t)"_temp"; + if (strcmp((char *)p[0]->data, "eq") == 0) + p[0]->data = (intptr_t)"eqzp"; + else if (strcmp((char *)p[0]->data, "eqb") == 0) + p[0]->data = (intptr_t)"eqbzp"; + else if (strcmp((char *)p[0]->data, "ne") == 0) + p[0]->data = (intptr_t)"nezp"; + else if (strcmp((char *)p[0]->data, "neb") == 0) + p[0]->data = (intptr_t)"nebzp"; + else if (strcmp((char *)p[0]->data, "lt") == 0) + p[0]->data = (intptr_t)"ltzp"; + else if (strcmp((char *)p[0]->data, "ltb") == 0) + p[0]->data = (intptr_t)"ltbzp"; + else if (strcmp((char *)p[0]->data, "ult") == 0) + p[0]->data = (intptr_t)"ultzp"; + else if (strcmp((char *)p[0]->data, "ublt") == 0) + p[0]->data = (intptr_t)"ubltzp"; + else if (strcmp((char *)p[0]->data, "gt") == 0) + p[0]->data = (intptr_t)"gtzp"; + else if (strcmp((char *)p[0]->data, "gtb") == 0) + p[0]->data = (intptr_t)"gtbzp"; + else if (strcmp((char *)p[0]->data, "ugt") == 0) + p[0]->data = (intptr_t)"ugtzp"; + else if (strcmp((char *)p[0]->data, "ubgt") == 0) + p[0]->data = (intptr_t)"ubgtzp"; + else if (strcmp((char *)p[0]->data, "le") == 0) + p[0]->data = (intptr_t)"lezp"; + else if (strcmp((char *)p[0]->data, "leb") == 0) + p[0]->data = (intptr_t)"lebzp"; + else if (strcmp((char *)p[0]->data, "ule") == 0) + p[0]->data = (intptr_t)"ulezp"; + else if (strcmp((char *)p[0]->data, "uble") == 0) + p[0]->data = (intptr_t)"ublezp"; + else if (strcmp((char *)p[0]->data, "ge") == 0) + p[0]->data = (intptr_t)"gezp"; + else if (strcmp((char *)p[0]->data, "geb") == 0) + p[0]->data = (intptr_t)"gebzp"; + else if (strcmp((char *)p[0]->data, "uge") == 0) + p[0]->data = (intptr_t)"ugezp"; + else if (strcmp((char *)p[0]->data, "ubge") == 0) + p[0]->data = (intptr_t)"ubgezp"; + /* loop */ + goto lv1_loop; + } + + else if (p[0]->code == I_JSR && + (!strcmp((char *)p[0]->data, "eqzp") || + !strcmp((char *)p[0]->data, "nezp")) && + p[1]->code == I_LDWI && + p[2]->code == I_STW && + p[2]->type == T_SYMBOL && + !strcmp((char *)p[2]->data, "_temp")) { + *p[2] = *p[1]; + if (!strcmp((char *)p[0]->data, "eqzp")) + p[2]->code = I_CMPWI_EQ; + else + p[2]->code = I_CMPWI_NE; + nb = 2; + } + + /* __ldw/b/ub n --> incw/b n + * __addwi 1 __ldw/b/ub n + * __stw/b/ub n + * + * ==== + * bytes : 6+ 7+ 6=19 --> 8 + 6=14 + * cycles : 10+12+10=32 --> (11->16)+10=(21->26) + * + */ + else if + ((p[0]->code == I_STW || p[0]->code == I_STB) && + (p[2]->code == I_LDW || p[2]->code == I_LDUB || p[2]->code == I_LDB) && + ((p[1]->code == I_ADDWI) && + (p[1]->type == T_VALUE) && + (p[1]->data == 1)) && + (cmp_operands(p[0], p[2]) == 1)) { + /* replace code */ + p[1]->code = p[2]->code; + p[1]->type = p[2]->type; + p[1]->data = p[2]->data; + p[2]->code = (p[0]->code == I_STW) ? I_INCW : I_INCB; + nb = 1; + } + + /* incw/b n --> __ldw/b/ub n + * __ldw/b/ub n incw/b n + * __subwi 1 + * + */ + else if + (((p[0]->code == I_SUBWI) && + (p[0]->type == T_VALUE) && + (p[0]->data == 1)) && + + (p[1]->code == I_LDW) && + (p[2]->code == I_INCW) && + (cmp_operands(p[1], p[2]) == 1)) { + /* replace code */ + p[2]->code = p[1]->code; + p[2]->type = p[1]->type; + p[2]->data = p[1]->data; + p[1]->code = I_INCW; + nb = 1; + } + else if + (((p[0]->code == I_SUBWI) && + (p[0]->type == T_VALUE) && + (p[0]->data == 1)) && + + (p[1]->code == I_LDB || p[1]->code == I_LDUB) && + (p[2]->code == I_INCB) && + (cmp_operands(p[1], p[2]) == 1)) { + /* replace code */ + p[2]->code = p[1]->code; + p[2]->type = p[1]->type; + p[2]->data = p[1]->data; + p[1]->code = I_INCB; + nb = 1; + } + + /* flush queue */ + if (nb) { + q_wr -= nb; + q_nb -= nb; + nb = 0; + + if (q_wr < 0) + q_wr += Q_SIZE; + + /* loop */ + goto lv1_loop; + } + } + + /* 2-instruction patterns */ + if (q_nb >= 2) { + if (p[0]->code == I_LABEL && + (p[1]->code == I_LBRA || p[1]->code == I_LBRAN) && + p[1]->type == T_LABEL && + p[0]->data == p[1]->data) { + *p[1] = *p[0]; + nb = 1; + } + + /* __addmi i,__stack --> __addmi i+j,__stack + * __addmi j,__stack + * + * ==== + * bytes : 15+15 = 30 --> 15 + * cycles : 29+29 = 58 --> 29 + * + */ + else if ((p[0]->code == I_ADDMI) && + (p[1]->code == I_ADDMI) && + + (p[0]->type == T_STACK) && + (p[1]->type == T_STACK)) { + /* replace code */ + p[1]->data += p[0]->data; + nb = 1; + } + + /* __addwi i --> __addwi i+j + * __addwi j + * + * ==== + * bytes : 7+ 7 = 14 --> 7 + * cycles : 12+12 = 24 --> 12 + * + */ + else if + ((p[0]->code == I_ADDWI && p[0]->type == T_VALUE) && + (p[1]->code == I_ADDWI && p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data += p[0]->data; + nb = 1; + } + + /* __ldwi i --> __ldwi i+j + * __add[bw]i j + * + * ==== + * bytes : 4+ 7 = 11 --> 4 + * cycles : 4+12 = 16 --> 4 + * + */ + else if + ((p[0]->code == I_ADDWI || p[0]->code == I_ADDBI) && + (p[1]->code == I_LDWI) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data += p[0]->data; + nb = 1; + } + + /* __ldwi sym --> __ldwi sym+j + * __add[bw]i j + * + */ + else if + ((p[0]->code == I_ADDWI || p[0]->code == I_ADDBI) && + (p[1]->code == I_LDWI) && + (p[1]->type == T_SYMBOL)) { + /* replace code */ + if (p[0]->data != 0) { + SYMBOL * oldsym = (SYMBOL *)p[1]->data; + SYMBOL * newsym = copysym(oldsym); + if (NAMEALLOC <= + snprintf(newsym->name, NAMEALLOC, "%s+%ld", oldsym->name, (long) p[0]->data)) + error("optimized symbol+offset name too intptr_t"); + p[1]->data = (intptr_t)newsym; + } + nb = 1; + } + + /* __ldwi i --> __ldwi (i-j) + * __subwi j + * + * ==== + * bytes : 4+ 7 = 11 --> 4 + * cycles : 4+12 = 16 --> 4 + * + */ + else if + ((p[0]->code == I_SUBWI) && + (p[1]->code == I_LDWI) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data -= p[0]->data; + nb = 1; + } + + /* __ldwi i --> __ldwi (i&j) + * __andwi j + * + * ==== + * bytes : 4+ 6 = 10 --> 4 + * cycles : 4+10 = 14 --> 4 + * + */ + else if + ((p[0]->code == I_ANDWI) && + (p[1]->code == I_LDWI) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data &= p[0]->data; + nb = 1; + } + + /* __ldwi i --> __ldwi (i|j) + * __orwi j + * + * ==== + * bytes : 4+ 6 = 10 --> 4 + * cycles : 4+10 = 14 --> 4 + * + */ + else if + ((p[0]->code == I_ORWI) && + (p[1]->code == I_LDWI) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data |= p[0]->data; + nb = 1; + } + + /* __ldwi i --> __ldwi (i*j) + * __mulwi j + * + */ + else if + ((p[0]->code == I_MULWI) && + (p[1]->code == I_LDWI) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data *= p[0]->data; + nb = 1; + } + + /* __ldwi i --> __ldwi i+i + * __aslw + * + * ==== + * bytes : 4+4 = 8 --> 4 + * cycles : 4+8 = 12 --> 4 + * + */ + else if + ((p[0]->code == I_ASLW) && + (p[1]->code == I_LDWI) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data += p[1]->data; + nb = 1; + } + + /* __ldwi i --> __ldwi i ^ 0xffff + * __comw + * + * ==== + * bytes : 4+4 = 8 --> 4 + * cycles : 4+8 = 12 --> 4 + * + */ + else if + ((p[0]->code == I_COMW) && + (p[1]->code == I_LDWI) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data = p[1]->data ^ 0xffff; + nb = 1; + } + + /* __ldwi i --> __ldwi i ^ 0xffff + * __negw + * + * ==== + * bytes : 4+4 = 8 --> 4 + * cycles : 4+8 = 12 --> 4 + * + */ + else if + ((p[0]->code == I_NEGW) && + (p[1]->code == I_LDWI) && + + (p[1]->type == T_VALUE)) { + /* replace code */ + p[1]->data = -p[1]->data; + nb = 1; + } + + /* __ldwi --> __ldwi + * jsr {u|s}mul --> jsr asl + * + */ + else if + (p[0]->code == I_JSR && + (!strcmp((char *)p[0]->data, "umul") || + !strcmp((char *)p[0]->data, "smul")) && + (p[1]->code == I_LDWI) && + (p[1]->type == T_VALUE) && + __builtin_popcount(p[1]->data) == 1 && + p[1]->data > 0 && p[1]->data < 0x8000) { + p[0]->data = (intptr_t)"asl"; + p[1]->data = __builtin_ctz(p[1]->data); + nb = 0; + } + + /* __ldw __stack --> @_pea_s 0 + * __pushw + * + * ==== + * bytes : 4+23 = 27 --> 25 + * cycles : 8+49 = 57 --> 44 + * + */ +// else if +// ((p[0]->code == I_PUSHW) && +// (p[1]->code == I_LDW) && +// +// (p[1]->type == T_STACK)) +// { +// /* replace code */ +// p[1]->code = X_PEA_S; +// p[1]->data = 0; +// nb = 1; +// } + + /* __ldw __stack --> @_lea_s i + * __addwi i + * + * ==== + * bytes : 4+ 7 = 11 --> 10 + * cycles : 8+12 = 20 --> 16 + * + */ +// else if +// ((p[0]->code == I_ADDWI) && +// (p[1]->code == I_LDW) && +// +// (p[1]->type == T_STACK)) +// { +// /* replace code */ +// p[1]->code = X_LEA_S; +// p[1]->data = p[0]->data; +// nb = 1; +// } + + /* __stw a --> __stw a + * __ldw a + * + */ + else if + ((p[0]->code == I_LDW) && + (p[1]->code == I_STW) && + (cmp_operands(p[0], p[1]) == 1)) { + /* remove code */ + nb = 1; + } + + /* __ldw a (or __ldwi a) --> __ldw b (or __ldwi b) + * __ldw b (or __ldwi b) + * + * ==== + * bytes : ? --> ? + * cycles : ? --> ? + * + */ + else if + ((p[0]->code == I_LDW || + p[0]->code == I_LDWI || + p[0]->code == X_LDW_S || + p[0]->code == X_LEA_S || + p[0]->code == I_LDB || + p[0]->code == I_LDBP || + p[0]->code == I_LDBY || + p[0]->code == X_LDB || + p[0]->code == X_LDB_S || + p[0]->code == I_LDUB || + p[0]->code == I_LDUBP || + p[0]->code == X_LDUB || + p[0]->code == X_LDUB_S) && + (p[1]->code == I_LDW || + p[1]->code == I_LDWI || + p[1]->code == X_LDW_S || + p[1]->code == X_LEA_S || + p[1]->code == I_LDB || + p[1]->code == I_LDBP || + p[1]->code == I_LDBY || + p[1]->code == X_LDB || + p[1]->code == X_LDB_S || + p[1]->code == I_LDUB || + p[1]->code == I_LDUBP || + p[1]->code == X_LDUB || + p[1]->code == X_LDUB_S) + ) { + /* remove code */ + *p[1] = *p[0]; + nb = 1; + } + + /* ... --> ... + * __addwi etc. 0 + * + * ==== + * bytes : x+ 7 --> x + * cycles : y+12 --> y + * + */ + else if + ((p[0]->code == I_ADDWI || p[0]->code == I_ASLWI || + p[0]->code == I_LSRWI || p[0]->code == I_ASRWI || + p[0]->code == I_SUBWI) && + p[0]->data == 0 && p[0]->type == T_VALUE) { + /* remove code */ + nb = 1; + } + + /* @_stw_s i --> @_stw_s i + * @_ldw_s i + * + * ==== + * bytes : 9+ 8 = 17 --> 9 + * cycles : 22+20 = 42 --> 22 + * + */ + else if + ((p[0]->code == X_LDW_S) && + (p[1]->code == X_STW_S) && + + (p[0]->data == p[1]->data)) { + /* remove code */ + nb = 1; + } + + /* @_stb_s i --> @_stb_s i + * @_ldb_s i + * + * ==== + * bytes : 6+ 9 = 15 --> 6 + * cycles : 13+17 = 30 --> 13 + * + */ + else if + ((p[0]->code == X_LDB_S || p[0]->code == X_LDUB_S) && + (p[1]->code == X_STB_S) && + + (p[0]->data == p[1]->data)) { + if (p[0]->code == X_LDB_S) + p[0]->code = I_EXTW; + else + p[0]->code = I_EXTUW; + p[0]->type = p[0]->data = 0; + } + + /* @_lea_s i --> @_pea_s i + * __pushw + * + * ==== + * bytes : 10+23 = 33 --> 25 + * cycles : 16+49 = 65 --> 44 + * + */ + else if + ((p[0]->code == I_PUSHW) && + (p[1]->code == X_LEA_S)) { + /* replace code */ + p[1]->code = X_PEA_S; + nb = 1; + } + + /* __stw __ptr --> @_ldb_p + * __ldbp __ptr + * + * ==== + * bytes : 4+10 = 14 --> 11 + * cycles : 8+19 = 27 --> 23 + * + */ + else if + ((p[0]->code == I_LDBP) && + (p[1]->code == I_STW) && + + (p[1]->type == T_PTR)) { + /* replace code */ + p[1]->code = X_LDB_P; + nb = 1; + } + else if + ((p[0]->code == I_LDUBP) && + (p[1]->code == I_STW) && + + (p[1]->type == T_PTR)) { + /* replace code */ + p[1]->code = X_LDUB_P; + nb = 1; + } + + /* @_lea_s i --> @_ld(u)b_s i + * @_ld(u)b_p + * + * ==== + * bytes : 10+11 = 21 --> 9 + * cycles : 16+23 = 39 --> 17 + * + */ + else if + ((p[0]->code == X_LDB_P) && + (p[1]->code == X_LEA_S)) { + /* replace code */ + p[1]->code = X_LDB_S; + nb = 1; + } + else if + ((p[0]->code == X_LDUB_P) && + (p[1]->code == X_LEA_S)) { + /* replace code */ + p[1]->code = X_LDUB_S; + nb = 1; + } + + /* @_ldwi i --> @_ld(u)b i + * @_ld(u)b_p + * + */ + else if + ((p[0]->code == X_LDB_P) && + (p[1]->code == I_LDWI)) { + /* replace code */ + p[1]->code = I_LDB; + nb = 1; + } + else if + ((p[0]->code == X_LDUB_P) && + (p[1]->code == I_LDWI)) { + /* replace code */ + p[1]->code = I_LDUB; + nb = 1; + } + + /* @_pea_s i --> @_pea_s i + * @_ldb_p @_ldb_s i+2 + * + * ==== + * bytes : 25+11 = 36 --> 25+ 9 = 34 + * cycles : 44+23 = 67 --> 44+17 = 61 + * + */ + else if + ((p[0]->code == X_LDB_P) && + (p[1]->code == X_PEA_S) && + + (optimize >= 2)) { + /* replace code */ + p[0]->code = X_LDB_S; + p[0]->data = p[1]->data + 2; + p[0]->sym = p[1]->sym; + + /* loop */ + goto lv1_loop; + } + else if + ((p[0]->code == X_LDUB_P) && + (p[1]->code == X_PEA_S) && + + (optimize >= 2)) { + /* replace code */ + p[0]->code = X_LDUB_S; + p[0]->data = p[1]->data + 2; + p[0]->sym = p[1]->sym; + + /* loop */ + goto lv1_loop; + } + + /* ldwi i; stwip j --> stwi i, j */ + else if (p[0]->code == I_STWIP && + p[1]->code == I_LDWI) { + p[1]->code = I_STWI; + p[1]->imm_type = p[0]->type; + p[1]->imm_data = p[0]->data; + nb = 1; + } + /* ldwi i; stbip j --> stbi i, j */ + else if (p[0]->code == I_STBIP && + p[1]->code == I_LDWI) { + p[1]->code = I_STBI; + p[1]->imm_type = p[0]->type; + p[1]->imm_data = p[0]->data; + nb = 1; + } + + /* ldwi i; stw const --> stwi const, i */ + /* XXX: This doesn't really do anything... */ + else if ((p[0]->code == I_STW || p[0]->code == I_STB) && + p[0]->type == T_VALUE && + p[1]->code == I_LDWI) { + p[1]->code = (p[0]->code == I_STW) ? I_STWI : I_STBI; + p[1]->imm_type = p[1]->type; + p[1]->imm_data = p[1]->data; + p[1]->type = p[0]->type; + p[1]->data = p[0]->data; + nb = 1; + } + + /* subwi/addwi i; ldw j --> ldw j + This is a frequent case in which the result + of a post-increment or decrement is not used. */ + else if ((p[0]->code == I_LDW || + p[0]->code == I_LDWI || + p[0]->code == X_LDW_S) && + (p[1]->code == I_SUBWI || + p[1]->code == I_ADDWI)) { + *p[1] = *p[0]; + nb = 1; + } + + /* jsr eq/ne/eqzp/nezp --> jsr eq/ne/eqzp/nezp + * __tstw + * + * ==== + * bytes : x+4 --> x + * cycles : y+8 --> y + * + */ + else if + ((p[0]->code == I_TSTW) && + (p[1]->code == I_JSR) && + ((strcmp((char *)p[1]->data, "eq") == 0) || + (strcmp((char *)p[1]->data, "eqb") == 0) || + (strcmp((char *)p[1]->data, "ne") == 0) || + (strcmp((char *)p[1]->data, "neb") == 0) || + (strcmp((char *)p[1]->data, "ge") == 0) || + (strcmp((char *)p[1]->data, "geb") == 0) || + (strcmp((char *)p[1]->data, "uge") == 0) || + (strcmp((char *)p[1]->data, "ubge") == 0) || + (strcmp((char *)p[1]->data, "gt") == 0) || + (strcmp((char *)p[1]->data, "gtb") == 0) || + (strcmp((char *)p[1]->data, "ugt") == 0) || + (strcmp((char *)p[1]->data, "ubgt") == 0) || + (strcmp((char *)p[1]->data, "le") == 0) || + (strcmp((char *)p[1]->data, "leb") == 0) || + (strcmp((char *)p[1]->data, "ule") == 0) || + (strcmp((char *)p[1]->data, "uble") == 0) || + (strcmp((char *)p[1]->data, "lt") == 0) || + (strcmp((char *)p[1]->data, "ltb") == 0) || + (strcmp((char *)p[1]->data, "ult") == 0) || + (strcmp((char *)p[1]->data, "ublt") == 0) || + (strcmp((char *)p[1]->data, "eqzp") == 0) || + (strcmp((char *)p[1]->data, "eqbzp") == 0) || + (strcmp((char *)p[1]->data, "nezp") == 0) || + (strcmp((char *)p[1]->data, "nebzp") == 0) || + (strcmp((char *)p[1]->data, "gezp") == 0) || + (strcmp((char *)p[1]->data, "gebzp") == 0) || + (strcmp((char *)p[1]->data, "ugezp") == 0) || + (strcmp((char *)p[1]->data, "ubgezp") == 0) || + (strcmp((char *)p[1]->data, "gtzp") == 0) || + (strcmp((char *)p[1]->data, "gtbzp") == 0) || + (strcmp((char *)p[1]->data, "ugtzp") == 0) || + (strcmp((char *)p[1]->data, "ubgtzp") == 0) || + (strcmp((char *)p[1]->data, "lezp") == 0) || + (strcmp((char *)p[1]->data, "lebzp") == 0) || + (strcmp((char *)p[1]->data, "ulezp") == 0) || + (strcmp((char *)p[1]->data, "ublezp") == 0) || + (strcmp((char *)p[1]->data, "ltzp") == 0) || + (strcmp((char *)p[1]->data, "ltbzp") == 0) || + (strcmp((char *)p[1]->data, "ultzp") == 0) || + (strcmp((char *)p[1]->data, "ubltzp") == 0))) + nb = 1; + + /* __boolw --> __tstw + * __tstw + * + */ + else if ((p[0]->code == I_TSTW) && + (p[1]->code == I_BOOLW)) { + p[1]->code = I_TSTW; + nb = 1; + } + + /* __notw --> __notw + * __tstw + * + */ + else if ((p[0]->code == I_TSTW) && + (p[1]->code == I_NOTW)) + nb = 1; + + /* __cmpwi_* --> __cmpwi_* + * __tstw + * + */ + else if ((p[0]->code == I_TSTW) && + (p[1]->code == I_CMPWI_EQ || + p[1]->code == I_CMPWI_NE)) + nb = 1; + + else if (p[1]->code == I_STWI && + p[1]->imm_type == T_VALUE && + p[1]->imm_data == 0 && + is_load(p[0]) && + p[0]->code != X_LDB_P && + p[0]->code != X_LDUB_P) + p[1]->code = I_STWZ; + else if (p[1]->code == I_STBI && + p[1]->imm_type == T_VALUE && + p[1]->imm_data == 0 && + is_load(p[0]) && + p[0]->code != X_LDB_P && + p[0]->code != X_LDUB_P) + p[1]->code = I_STBZ; + + /* flush queue */ + if (nb) { + q_wr -= nb; + q_nb -= nb; + nb = 0; + + if (q_wr < 0) + q_wr += Q_SIZE; + + /* loop */ + goto lv1_loop; + } + } + } + + /* optimization level 2 - instruction re-scheduler, + * change instruction order to allow direct assignments + * rather than stack based assignments : + * + * @_pea_s i --> ... + * ... @_stw_s i + * __stwps + * + * ==== + * bytes : 25+??+42 = ??+ 67 --> ??+ 9 = ??+ 9 + * cycles : 44+??+91 = ??+135 --> ??+22 = ??+22 + * + */ + if (optimize >= 2) { + intptr_t offset; + intptr_t i, j; + intptr_t t; + intptr_t jp; + + /* check last instruction */ + if (q_nb > 1 && + (q_ins[q_wr].code == I_STWPS || + q_ins[q_wr].code == I_STBPS || + q_ins[q_wr].code == I_CALLS || + q_ins[q_wr].code == I_ADDWS || + q_ins[q_wr].code == I_ORWS || + q_ins[q_wr].code == I_EORWS || + q_ins[q_wr].code == I_ANDWS)) { + /* browse back the instruction list and + * etablish a stack history + */ + offset = 2; + + for (i = 1, j = q_wr; i < q_nb; i++) { + j -= 1; + + if (j < 0) + j += Q_SIZE; + + /* Index of insn precdeing j. */ + jp = j - 1; + if (jp < 0) + jp += Q_SIZE; + + /* check instruction */ + switch (q_ins[j].code) { + case I_JSR: + if (q_ins[j].type == T_LIB) + offset += 2; + break; + + case I_ADDMI: + if ((q_ins[j].type == T_STACK) || + (q_ins[j].type == T_NOP)) + offset += q_ins[j].data; + break; + + case I_CALLS: + case I_ADDBS: + case I_ADDWS: + case I_SUBWS: + case I_ORWS: + case I_EORWS: + case I_ANDWS: + case I_POPW: + case I_STWPS: + case I_STBPS: + offset += 2; + break; + + case I_PUSHW: + case X_PEA_S: + case X_PUSHW_A: + offset -= 2; + break; + } + + /* check offset */ + if (offset == 0) { + /* good! */ + if (i == 1) { + /* hmm, may be not... + * there should be at least one instruction + * between pea_s and stwps. + * this case should never happen, though, + * but better skipping it + */ + if (q_ins[q_wr].code != I_CALLS) + break; + } + + /* check the first instruction + */ + if (q_ins[q_wr].code == I_CALLS) { + if (q_ins[j].code != X_PUSHW_A) + break; + } + else { + /* Only handle sequences that start with + pea_s or ldwi/pushw. */ + if (q_ins[j].code != X_PEA_S && + (q_ins[j].code != I_PUSHW || q_ins[jp].code != I_LDWI) + ) + break; + + if (q_ins[j].code == X_PEA_S && + q_ins[q_wr].code != I_STBPS && + q_ins[q_wr].code != I_STWPS) + break; + + /* change stwps into stw_s/stw */ + if (q_ins[j].code == X_PEA_S) { + if (q_ins[q_wr].code == I_STBPS) + q_ins[q_wr].code = X_STB_S; + else + q_ins[q_wr].code = X_STW_S; + q_ins[q_wr].data = q_ins[j].data; + } + else { + switch (q_ins[q_wr].code) { + case I_STBPS: + q_ins[q_wr].code = I_STB; + break; + case I_STWPS: + q_ins[q_wr].code = I_STW; + break; + case I_ADDWS: + q_ins[q_wr].code = I_ADDWI; + break; + case I_ORWS: + q_ins[q_wr].code = I_ORWI; + break; + case I_EORWS: + q_ins[q_wr].code = I_EORWI; + break; + case I_ANDWS: + q_ins[q_wr].code = I_ANDWI; + break; + default: + abort(); + } + /* Use data from the preceding ldwi. */ + q_ins[q_wr].type = q_ins[jp].type; + q_ins[q_wr].data = q_ins[jp].data; + } + } + + /* adjust stack references; + * because of the removal of pea_s + */ + for (t = i; t > 1; t--) { + j += 1; + if (j >= Q_SIZE) + j -= Q_SIZE; + + /* check instruction */ + if (is_sprel(&q_ins[j])) { + /* adjust stack offset */ + q_ins[j].data -= 2; + } + } + + /* remove all the instructions... */ + q_wr -= (i + 1); + q_nb -= (i + 1); + j -= (i - 1); + + if (q_wr < 0) + q_wr += Q_SIZE; + if (j < 0) + j += Q_SIZE; + + /* ... and re-insert them one by one + * in the queue (for further optimizations) + */ + for (; i > 0; i--) { + j += 1; + if (j >= Q_SIZE) + j -= Q_SIZE; + + ODEBUG("re"); + push_ins(&q_ins[j]); + } + break; + } + } + } + + if (q_nb >= 3) { + /* pushw//st*ps --> stw __ptr//st*p __ptr */ + /* This cannot be done earlier because it screws up + the reordering optimization above. */ + if ((q_ins[q_wr].code == I_STBPS || + q_ins[q_wr].code == I_STWPS) && + is_load(&q_ins[q_wr - 1]) && + q_ins[q_wr - 2].code == I_PUSHW) { + q_ins[q_wr - 2].code = I_STW; + q_ins[q_wr - 2].type = T_PTR; + /* We just removed a push, adjust SP-relative + addresses. */ + if (is_sprel(&q_ins[q_wr - 1])) + q_ins[q_wr - 1].data -= 2; + if (q_ins[q_wr].code == I_STBPS) + q_ins[q_wr].code = I_STBP; + else + q_ins[q_wr].code = I_STWP; + q_ins[q_wr].type = T_PTR; + } + } + } +} + + +/* ---- + * flush_ins_label(int nextlabel) + * ---- + * flush instruction queue, eliminating redundant trailing branches to a + * label following immediately + * + */ +void flush_ins_label (int nextlabel) +{ + while (q_nb) { + /* skip last op if it's a branch to nextlabel */ + if (q_nb > 1 || nextlabel == -1 || + (q_ins[q_rd].code != I_LBRA && q_ins[q_rd].code != I_LBRAN) || + q_ins[q_rd].data != nextlabel) { + /* gen code */ + if (arg_stack_flag) + arg_push_ins(&q_ins[q_rd]); + else + gen_code(&q_ins[q_rd]); + } + + /* advance and wrap queue read pointer */ + q_rd++; + q_nb--; + + if (q_rd == Q_SIZE) + q_rd = 0; + } + + /* reset queue */ + q_rd = 0; + q_wr = Q_SIZE - 1; + q_nb = 0; +} + +/* ---- + * flush_ins() + * ---- + * flush instruction queue + * + */ +void flush_ins (void) +{ + flush_ins_label(-1); +} + +/* ---- + * gen_asm() + * ---- + * generate optimizer asm code + * + */ +void gen_asm (INS *inst) +{ + switch (inst->code) { + case X_LDB_P: + ol("__ldb_p"); + break; + + case X_LDUB_P: + ol("__ldub_p"); + break; + + case X_LDB_S: + ot("__ldb_s\t"); + outdec(inst->data); + nl(); + break; + + case X_LDUB_S: + ot("__ldub_s\t"); + outdec(inst->data); + nl(); + break; + + case X_LDW_S: + ot("__ldw_s\t"); + outdec(inst->data); + nl(); + break; + + case X_LDD_I: + ot("__ldd_i\t"); + outdec(inst->data); + outstr(","); + outsymbol(inst->arg[0]); + outstr(","); + outsymbol(inst->arg[1]); + nl(); + break; + + case X_LDD_B: + ot("__ldd_b\t"); + outsymbol((char *)inst->data); + outstr(","); + outsymbol(inst->arg[0]); + outstr(","); + outsymbol(inst->arg[1]); + nl(); + break; + + case X_LDD_W: + ot("__ldd_w\t"); + outsymbol((char *)inst->data); + outstr(","); + outsymbol(inst->arg[0]); + outstr(","); + outsymbol(inst->arg[1]); + nl(); + break; + + case X_LDD_S_B: + ot("__ldd_s_b\t"); + outdec(inst->data); + outstr(","); + outsymbol(inst->arg[0]); + outstr(","); + outsymbol(inst->arg[1]); + nl(); + break; + + case X_LDD_S_W: + ot("__ldd_s_w\t"); + outdec(inst->data); + outstr(","); + outsymbol(inst->arg[0]); + outstr(","); + outsymbol(inst->arg[1]); + nl(); + break; + + case X_LEA_S: + ot("__lea_s\t"); + outdec(inst->data); + nl(); + break; + + case X_PEA_S: + ot("__pea_s\t"); + outdec(inst->data); + nl(); + break; + + case X_STBI_S: + ot("__stbi_s\t"); + outdec(inst->imm_data); + outstr(","); + outdec(inst->data); + nl(); + break; + + case X_STWI_S: + ot("__stwi_s\t"); + outdec(inst->imm_data); + outstr(","); + outdec(inst->data); + nl(); + break; + + case X_STW_S: + ot("__stw_s\t"); + outdec(inst->data); + nl(); + break; + + case X_STB_S: + ot("__stb_s\t"); + outdec(inst->data); + nl(); + break; + + case X_INCW_S: + ot("__incw_s\t"); + outdec(inst->data); + nl(); + break; + + case X_INCB_S: + ot("__incb_s\t"); + outdec(inst->data); + nl(); + break; + + case X_ADDW_S: + ot("__addw_s\t"); + outdec(inst->data); + nl(); + break; + case X_ADDB_S: + ot("__addb_s\t"); + outdec(inst->data); + nl(); + break; + case X_ADDUB_S: + ot("__addub_s\t"); + outdec(inst->data); + nl(); + break; + default: + error("internal error: invalid instruction"); + break; + } +} diff --git a/src/huc/optimize.h b/src/huc/optimize.h new file mode 100644 index 00000000..ca6a1943 --- /dev/null +++ b/src/huc/optimize.h @@ -0,0 +1,14 @@ +/* File opt.c: 2.1 (83/03/20,16:02:09) */ +/*% cc -O -c % + * + */ + +#ifndef _OPTIMIZE_H +#define _OPTIMIZE_H + +void push_ins (INS *ins); +void flush_ins (void); +void flush_ins_label (int nextlabel); +void gen_asm (INS *inst); + +#endif diff --git a/src/huc/pragma.c b/src/huc/pragma.c new file mode 100644 index 00000000..4bba2692 --- /dev/null +++ b/src/huc/pragma.c @@ -0,0 +1,539 @@ +/* File pragma.c: 2.1 (00/08/09,04:59:24) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "error.h" +#include "io.h" +#include "lex.h" +#include "pragma.h" +#include "sym.h" +#include "fastcall.h" + +/* locals */ +struct fastcall ftemp; +struct fastcall *fastcall_tbl[256]; +static char cmd[LINESIZE]; +static char *cmdptr; + +/* default pragma's */ +static char *pragma_init[] = { + /* far pointer support funcs */ + "fastcall farpeekb(farptr __fbank:__fptr)", + "fastcall farpeekw(farptr __fbank:__fptr)", + "fastcall farmemget(word __bx, farptr __fbank:__fptr, word acc)", + /* asm-lib wrappers */ + "fastcall load_palette(byte __al, farptr __bl:__si, byte __cl)", + "fastcall load_bat(word __di, farptr __bl:__si, byte __cl, byte __ch)", + "fastcall load_vram(word __di, farptr __bl:__si, word __cx)", + "fastcall load_vram2(word __di, word __si, byte __bl, word __cx)", + "fastcall snd_trkreg(byte __al, farptr __bl:__si)", + /* text funcs */ + "fastcall cls(word __dx)", + "fastcall set_xres(word __ax)", + "fastcall set_xres(word __ax, byte __cl)", + "fastcall set_font_color(byte __al, byte acc)", + "fastcall load_font(farptr __bl:__si, byte __cl)", + "fastcall load_font(farptr __bl:__si, byte __cl, word __di)", + "fastcall load_default_font(byte __dl)", + "fastcall load_default_font(byte __dl, word __di)", + "fastcall put_digit(byte __dl, word acc)", + "fastcall put_digit(byte __dl, byte __cl, byte acc)", + "fastcall put_char(byte __dl, word acc)", + "fastcall put_char(byte __dl, byte __cl, byte acc)", + "fastcall put_raw(word __dx, word acc)", + "fastcall put_raw(word __dx, byte __cl, byte acc)", + "fastcall put_number(word __dx, byte __cl, word acc)", + "fastcall put_number(word __dx, byte __cl, byte __bl, byte acc)", + "fastcall put_hex(word __dx, byte __cl, word acc)", + "fastcall put_hex(word __dx, byte __cl, byte __bl, byte acc)", + "fastcall put_string(word __si, word acc)", + "fastcall put_string(word __si, byte __bl, byte acc)", + /* gfx lib funcs */ + "fastcall gfx_plot(word __bx, word __cx, word acc)", + "fastcall gfx_point(word __bx, word __cx)", + "fastcall gfx_line(word __bx, word __cx, word __si, word __bp, word acc)", + + "fastcall vram_addr(byte __al, byte acc)", + "fastcall spr_ctrl(byte __al, byte acc)", + "fastcall get_color(word color_reg)", + "fastcall set_color(word color_reg, word color_data) nop", + "fastcall set_color_rgb(word color_reg, byte __al, byte __ah, byte acc)", + "fastcall fade_color(word __ax, byte acc)", + "fastcall fade_color(word color_reg, word __ax, byte acc)", + /* map lib funcs */ + "fastcall scan_map_table(word __si, word __ax, word __cx)", + "fastcall load_map(byte __al, byte __ah, word __di, word __bx, byte __dl, byte __dh)", + "fastcall set_map_data(word acc)", + "fastcall set_map_data(farptr __bl:__si, word __ax, word acc)", + "fastcall set_map_data(farptr __bl:__si, word __ax, word __dx, byte acc)", + "fastcall set_tile_data(word __di)", + "fastcall set_tile_data(farptr __bl:__si, word __cx, farptr __al:__dx, byte __ah)", + "fastcall put_tile(word __dx, word acc)", + "fastcall put_tile(word __dx, byte __al, byte acc)", + "fastcall map_get_tile(byte __dl, byte acc)", + "fastcall map_put_tile(byte __dl, byte __dh, byte acc)", + /* misc funcs */ + "fastcall get_joy_events(byte acc)", + "fastcall get_joy_events(byte __al, byte acc)", + "fastcall set_joy_callback(byte __dl, byte __al, byte __ah, farptr __bl:__si)", + "fastcall poke(word __bx, word acc)", + "fastcall pokew(word __bx, word acc)", + "fastcall srand32(word __dx, word __cx)", + /* 32-bit math funcs */ + "fastcall mov32(word __di, dword acc:__ax|__bx)", + "fastcall add32(word __di, dword acc:__ax|__bx)", + "fastcall sub32(word __di, dword acc:__ax|__bx)", + "fastcall mul32(word __bp, dword acc:__ax|__bx)", + "fastcall div32(word __bp, dword acc:__ax|__bx)", + "fastcall cmp32(word __di, dword acc:__ax|__bx)", + "fastcall com32(word __di)", + /* bcd math funcs */ + "fastcall bcd_init(word __bx, word acc)", + "fastcall bcd_set(word __bx, word acc)", + "fastcall bcd_mov(word __bx, word acc)", + "fastcall bcd_add(word __di, word acc)", + /* bram funcs */ + "fastcall bm_rawwrite(word __bx, word acc)", + "fastcall bm_read(word __di, word __bx, word __bp, word acc)", + "fastcall bm_write(word __di, word __bx, word __bp, word acc)", + "fastcall bm_create(word __bx, word acc)", + "fastcall bm_getptr(word __bp, word acc)", + /* string funcs */ + "fastcall strcpy(word __di, word __si)", + "fastcall strncpy(word __di, word __si, word acc)", + "fastcall strcat(word __di, word __si)", + "fastcall strncat(word __di, word __si, word acc)", + "fastcall strcmp(word __di, word __si)", + "fastcall strncmp(word __di, word __si, word acc)", + "fastcall strlen(word __si)", + "fastcall memcpy(word __di, word __si, word acc)", + "fastcall mempcpy(word __di, word __si, word acc)", + "fastcall memcmp(word __di, word __si, word acc)", + "fastcall memset(word __di, word __bx, word acc)", + /* CDROM funcs */ + "fastcall cd_trkinfo(word __ax, word __cx, word __dx, word __bp)", + "fastcall cd_playtrk(word __bx, word __cx, word acc)", + "fastcall cd_playmsf(byte __al, byte __ah, byte __bl, byte __cl, byte __ch, byte __dl, word acc)", + "fastcall cd_loadvram(word __di, word __si, word __bx, word acc)", + "fastcall cd_loaddata(word __di, word __si, farptr __bl:__bp, word acc)", + /* ADPCM funcs */ + "fastcall ad_trans(word __di, word __si, byte __al, word __bx)", + "fastcall ad_read(word __cx, byte __dh, word __bx, word __ax)", + "fastcall ad_write(word __cx, byte __dh, word __bx, word __ax)", + "fastcall ad_play(word __bx, word __ax, byte __dh, byte __dl)", + + "fastcall __builtin_ffs(word acc)", + NULL +}; + +/* protos */ +intptr_t fastcall_look (const char *fname, intptr_t nargs, struct fastcall **p); + + +/* ---- + * dopragma() + * ---- + * handle pragma directive + * + */ +void dopragma (void) +{ + intptr_t i; + + /* make a local copy of the pragma command line */ + for (i = 0;; i++) { + if (ch() == 0) + break; + cmd[i] = gch(); + } + cmd[i] = 0; + + /* parse */ + parse_pragma(); +} + + +/* ---- + * defpragma() + * ---- + * default pragmas + * + */ +void defpragma (void) +{ + intptr_t i; + + for (i = 0;; i++) { + if (pragma_init[i] == NULL) + break; + strcpy(cmd, pragma_init[i]); + parse_pragma(); + } +} + + +/* ---- + * parse_pragma() + * ---- + * parse pragma command line + * + */ +void parse_pragma (void) +{ + char sname[NAMESIZE]; + + /* get command */ + cmdptr = cmd; + + if (!symget(sname)) { + error("illegal symbol name"); + return; + } + + /* fastcall */ + if (strcmp(sname, "fastcall") == 0) + new_fastcall(); +/* new_fastcall(sname); */ + else if (!strcmp(sname, "no_recursive")) + norecurse = 1; + else if (!strcmp(sname, "recursive")) + norecurse = 0; + /* others */ + else + error("unknown pragma"); +} + + +/* ---- + * new_fastcall() + * ---- + * setup a new fastcall + * + * ie. #pragma fastcall func(word __dx, byte __al, byte __ah) + * + */ +void new_fastcall (void) +{ + struct fastcall *ptr; + char fname[NAMESIZE]; + char sname[NAMESIZE]; + intptr_t hash; + intptr_t cnt; + intptr_t i; + + ptr = &ftemp; + cnt = 0; + ptr->nargs = 0; + ptr->flags = 0; + + /* get func name */ + if (!symget(fname)) { + error("illegal symbol name"); + return; + } + + /* open */ + if (!strmatch("(")) { + error("missing bracket"); + return; + } + + /* extract args (max. 8) */ + for (i = 0; i < 8; i++) { + /* get type */ + if (!symget(sname)) { + if (*cmdptr == ')') + break; + error("syntax error"); + return; + } + if (strcmp(sname, "byte") == 0) + ptr->argtype[i] = TYPE_BYTE; + else if (strcmp(sname, "word") == 0) + ptr->argtype[i] = TYPE_WORD; + else if (strcmp(sname, "farptr") == 0) + ptr->argtype[i] = TYPE_FARPTR; + else if (strcmp(sname, "dword") == 0) + ptr->argtype[i] = TYPE_DWORD; + else { + error("fastcall unknown type"); + return; + } + + /* get name */ + if (!symget(sname)) { + /* auto */ + if (*cmdptr != ',') + ptr->argtype[i] = TYPE_ACC; + else { + error("fastcall register missing"); + return; + } + } + else { + /* dword */ + if (ptr->argtype[i] == TYPE_DWORD) { + /* ptr */ + if (strcmp(sname, "acc") == 0) + strcpy(ptr->argname[i++], "#acc"); + else + strcpy(ptr->argname[i++], sname); + + /* low word */ + if (*cmdptr++ != ':') { + error("syntax error"); + return; + } + if (!symget(sname)) { + error("illegal symbol name"); + return; + } + + /* copy */ + strcpy(ptr->argname[i++], sname); + + /* high word */ + if (*cmdptr++ != '|') { + error("syntax error"); + return; + } + if (!symget(sname)) { + error("illegal symbol name"); + return; + } + + /* copy */ + strcpy(ptr->argname[i], sname); + cnt++; + } + + /* far ptr */ + else if (ptr->argtype[i] == TYPE_FARPTR) { + /* bank */ + strcpy(ptr->argname[i++], sname); + ptr->argtype[i] = TYPE_WORD; + + /* addr */ + if (*cmdptr++ != ':') { + error("syntax error"); + return; + } + if (!symget(sname)) { + error("illegal symbol name"); + return; + } + + /* copy */ + strcpy(ptr->argname[i], sname); + cnt++; + } + + /* other */ + else { + if (strcmp(sname, "acc") == 0) { + /* accumulator */ + ptr->argtype[i] = TYPE_ACC; + } + else { + /* variable */ + strcpy(ptr->argname[i], sname); + cnt++; + } + } + } + + /* increment arg counter */ + ptr->nargs++; + + /* next */ + if (!strmatch(",")) + break; + } + + /* close */ + if (!strmatch(")")) { + error("missing bracket"); + return; + } + + /* extra infos */ + if (cnt) { + if (ptr->nargs > 1) + ptr->flags |= 0x02; + } + if (symget(sname)) { + if (strcmp(sname, "nop") == 0) + ptr->flags |= FASTCALL_NOP; + if (strcmp(sname, "macro") == 0) + ptr->flags |= FASTCALL_MACRO; + } + + /* check arg number */ + if (ptr->nargs == 0) + return; + + /* copy func name */ + strcpy(ptr->fname, fname); + + /* search for multi-decl */ + if (fastcall_look(fname, ptr->nargs, NULL)) { + error("already defined"); + return; + } + + /* ok */ + ptr = (void *)malloc(sizeof(struct fastcall)); + + if (ptr == NULL) + error("out of memory"); + else { + /* dup struct */ + *ptr = ftemp; + + /* add to hash table */ + hash = symhash(fname); + ptr->next = fastcall_tbl[hash]; + fastcall_tbl[hash] = ptr; + } +} + + +/* ---- + * fastcall_look() + * ---- + * search a fastcall function + * + */ +intptr_t fastcall_look (const char *fname, intptr_t nargs, struct fastcall **p) +{ + struct fastcall *ptr; + struct fastcall *ref; + intptr_t hash; + intptr_t nb; + + /* search */ + hash = symhash(fname); + ptr = fastcall_tbl[hash]; + ref = NULL; + nb = 0; + while (ptr) { + if (strcmp(ptr->fname, fname) == 0) { + nb++; + if (nargs != -1) { + if (ptr->nargs == nargs) + ref = ptr; + } + } + ptr = ptr->next; + } + if (nargs != -1) { + if (!ref) + nb = 0; + } + + /* return result */ + if (p) + *p = ref; + return (nb); +} + + +/* ---- + * symhash() + * ---- + * calculate the hash value of a symbol + * + */ +intptr_t symhash (const char *sym) +{ + intptr_t i; + char c; + intptr_t hash = 0; + + /* calc hash value */ + for (i = 0;; i++) { + c = sym[i]; + if (c == 0) + break; + hash += c; + hash = (hash << 3) + (hash >> 5) + c; + } + + /* ok */ + return (hash & 0xFF); +} + + +/* ---- + * symget() + * ---- + * extract a symbol name + * + */ +intptr_t symget (char *sname) +{ + intptr_t i; + + skip_blanks(); + + /* first char must be alpha */ + if (!alpha(*cmdptr)) + return (0); + + /* extract symbol name (stops at first non-alphanum char) */ + for (i = 0;; i++) { + if (!an(*cmdptr)) + break; + sname[i] = *cmdptr++; + } + sname[i] = 0; + + /* ok */ + return (1); +} + + +/* ---- + * strmatch() + * ---- + * test if next input string is legal symbol name + * + */ +intptr_t strmatch (char *lit) +{ + intptr_t i; + + skip_blanks(); + + /* compare */ + i = streq(cmdptr, lit); + + if (i) { + /* match */ + cmdptr += i; + return (1); + } + + /* different */ + return (0); +} + + +/* ---- + * skip_blanks() + * ---- + * skips blank chars (stops at end of input line) + * + */ +void skip_blanks (void) +{ + while ((*cmdptr == ' ') || (*cmdptr == '\t')) + cmdptr++; +} diff --git a/src/huc/pragma.h b/src/huc/pragma.h new file mode 100644 index 00000000..c7b92aa1 --- /dev/null +++ b/src/huc/pragma.h @@ -0,0 +1,21 @@ +/* File pragma.c: 2.1 (00/08/09,04:59:24) */ +/*% cc -O -c % + * + */ + +#ifndef _PRAGMA_H +#define _PRAGMA_H + +void dopragma (void); +void defpragma (void); +void parse_pragma (void); +void new_fastcall (void); +intptr_t fastcall_look (const char *fname, intptr_t nargs, struct fastcall **p); +intptr_t symhash (const char *sym); +intptr_t symget (char *sname); +intptr_t strmatch (char *lit); +void skip_blanks (void); + +extern struct fastcall *fastcall_tbl[256]; + +#endif diff --git a/src/huc/preproc.c b/src/huc/preproc.c new file mode 100644 index 00000000..767e07ac --- /dev/null +++ b/src/huc/preproc.c @@ -0,0 +1,807 @@ +/* File preproc.c: 2.3 (84/11/27,11:47:40) */ +/*% cc -O -c % + * + */ + +// #define DEBUG_PREPROC + +#include +#include +#include +#include +#include +#include "code.h" +#include "defs.h" +#include "data.h" +#include "error.h" +#include "io.h" +#include "lex.h" +#include "optimize.h" +#include "pragma.h" +#include "preproc.h" +#include "primary.h" +#include "sym.h" + +/* path separator */ +#if defined(WIN32) +#define PATH_SEPARATOR '\\' +#define PATH_SEPARATOR_STRING "\\" +#define DEFAULT_DIRS "c:\\huc\\include\\huc" +#else +#define PATH_SEPARATOR '/' +#define PATH_SEPARATOR_STRING "/" +#define DEFAULT_DIRS "/usr/local/lib/huc/include/huc;" \ + "/usr/local/huc/include/huc;" \ + "/usr/local/share/huc/include/huc;" \ + "/usr/local/include/huc;" \ + "/usr/lib/huc/include/huc;" \ + "/usr/share/huc/include/huc;" \ + "/usr/include/huc" +#endif + +/* locals */ +static char *incpath[10]; + +static const char *include_path (void) +{ + const char *p; + + p = getenv("PCE_INCLUDE"); + if (!p) + p = DEFAULT_DIRS; + return (p); +} + +char **include_dirs (void) +{ + return (incpath); +} + +/* + * init the include paths + */ +void init_path (void) +{ + const char *p, *pl; + intptr_t i, l; + + p = include_path(); + + for (i = 0; i < 10; i++) { + pl = strchr(p, ';'); + + if (pl == NULL) + l = strlen(p); + else + l = pl - p; + if (l) { + incpath[i] = (char *)malloc(l + 2); + strncpy(incpath[i], p, l); + p += l; + while (*p == ';') + p++; + incpath[i][l] = '\0'; + if (incpath[i][l - 1] != PATH_SEPARATOR) + strcat(incpath[i], PATH_SEPARATOR_STRING); +#ifdef DEBUG_PREPROC + printf("incpath %s\n", incpath[i]); +#endif + } + else { + if (incpath[i]) + free(incpath[i]); + incpath[i] = 0; + } + } +} + +/* + * open a file - browse paths + */ +FILE *file_open (char *name, char *mode) +{ + FILE *fp = NULL; + char testname[256]; + intptr_t i; + + for (i = 0; i < 10; i++) { + if (incpath[i] && strlen(incpath[i])) { + strcpy(testname, incpath[i]); + strcat(testname, name); + strcpy(inclstk_name[inclsp], testname); + fp = fopen(testname, mode); + if (fp != NULL) break; + } + } + + return (fp); +} + +/* + * open an include file + */ +void doinclude (void) +{ + FILE *inp2; + + blanks(); + inp2 = fixiname(); + if (inp2) { + if (inclsp < INCLSIZ) { + inclstk_line[inclsp] = line_number; + line_number = 0; + inclstk[inclsp++] = input2; + input2 = inp2; + } + else { + fclose(inp2); + error("too many nested includes"); + } + } + else + error("Could not open include file"); + kill(); +} + +void incl_globals (void) +{ + FILE *inp2; + + /* open the globals.h file to include those variables */ + /* but if we can't open it, it's no problem */ + + inp2 = fopen("globals.h", "r"); + + if (inp2) { + if (inclsp < INCLSIZ) { + inclstk_line[inclsp] = line_number; + line_number = 0; + strcpy(inclstk_name[inclsp], "globals.h"); + inclstk[inclsp++] = input2; + input2 = inp2; + globals_h_in_process = 1; + } + else { + fclose(inp2); + error("too many nested includes"); + } + } +} + + +/* + * fixiname - remove "brackets" around include file name + */ +FILE *fixiname (void) +{ + char c1, c2, *p, *ibp; + char buf[LINESIZE]; + FILE *fp; + + ibp = &buf[0]; + c1 = gch(); + c2 = (c1 == '"') ? '"' : '>'; + if ((c1 != '"') && (c1 != '<')) { + error("incorrect file name delimiter"); + return (NULL); + } + for (p = line + lptr; *p;) { + if (*p == c2) + break; + if ((*p == '\\') && (p[1] == '\\')) + p++; + *ibp++ = *p++; + } + if (*p != c2) { + error("file name delimiter missing"); + return (NULL); + } + *ibp = 0; + fp = NULL; + strcpy(inclstk_name[inclsp], buf); + if ((c1 == '<') || ((fp = fopen(buf, "r")) == NULL)) + fp = file_open(buf, "r"); + return (fp); +} + +/* + * "asm" pseudo-statement + * + * enters mode where assembly language statements are passed + * intact through parser + * + */ +void doasm (void) +{ + flush_ins(); /* David - optimize.c related */ + cmode = 0; + FOREVER { + readline(); + if (match("#endasm")) + break; + if (feof(input)) + break; + outstr(line); + nl(); + } + kill(); + cmode = 1; +} + +void doasmdef (void) +{ + char sname[100]; + char sval[100]; + intptr_t i = 0; + + symname(sname); + while ((ch() == ' ') || (ch() == 9)) + gch(); + + while (ch()) { + sval[i++] = ch(); + gch(); + } + sval[i++] = '\0'; + + outstr(sname); + outstr("\t= "); + outstr(sval); + nl(); +} + +void dodefine (void) +{ + addmac(); +} + +void doundef (void) +{ + struct macro *mp; + char sname[NAMESIZE]; + + if (!symname(sname)) { + illname(); + kill(); + return; + } + + mp = findmac(sname); + if (mp) + delmac(mp); + kill(); +} + +void preprocess (void) +{ + if (ifline()) return; + + while (cpp(NO)) ; +} + +static int max_if_depth = 0; +static int *had_good_elif = 0; + +static void bump_iflevel (void) +{ + ++iflevel; + if (iflevel >= max_if_depth) { + max_if_depth = (max_if_depth + 1) * 2; + had_good_elif = realloc(had_good_elif, max_if_depth * sizeof(int)); + } +} + +void doifdef (intptr_t ifdef) +{ + char sname[NAMESIZE]; + intptr_t k; + + blanks(); + bump_iflevel(); + had_good_elif[iflevel] = 0; + if (skiplevel) return; + + k = symname(sname) && findmac(sname); + if (k != ifdef) skiplevel = iflevel; +} + +static void doif (void) +{ + intptr_t num; + + blanks(); + bump_iflevel(); + had_good_elif[iflevel] = 0; + if (skiplevel) return; + + lex_stop_at_eol = 1; + const_expr(&num, NULL, NULL); + lex_stop_at_eol = 0; + if (!num) + skiplevel = iflevel; +} + +static void doelif (void) +{ + intptr_t num; + + blanks(); + if (skiplevel && skiplevel < iflevel) + return; + + if (!skiplevel || had_good_elif[iflevel]) { + /* previous section was good, so we are not */ + skiplevel = iflevel; + return; + } + lex_stop_at_eol = 1; + const_expr(&num, NULL, NULL); + lex_stop_at_eol = 0; + if (!num) + skiplevel = iflevel; + else { + had_good_elif[iflevel] = 1; + skiplevel = 0; + } +} + +intptr_t ifline (void) +{ + FOREVER { + readline(); +cont_no_read: + if (!input || feof(input)) return (1); + + if (match("#ifdef")) { + doifdef(YES); + continue; + } + else if (match("#ifndef")) { + doifdef(NO); + continue; + } + else if (match("#if")) { + /* need to preprocess the argument because it may + contain macros */ + cpp(YES); + doif(); + /* const_expr() already read the next line */ + goto cont_no_read; + } + else if (match("#elif")) { + /* need to preprocess the argument because it may + contain macros */ + cpp(YES); + doelif(); + /* const_expr() already read the next line */ + goto cont_no_read; + } + else if (match("#else")) { + if (iflevel) { + if (skiplevel == iflevel && !had_good_elif[iflevel]) + skiplevel = 0; + else if (skiplevel == 0) + skiplevel = iflevel; + } + else noiferr(); + continue; + } + else if (match("#endif")) { + if (iflevel) { + if (skiplevel == iflevel) skiplevel = 0; + --iflevel; + } + else noiferr(); + continue; + } + else if (!skiplevel) { + if (match("#define")) { + dodefine(); + continue; + } + else if (match("#undef")) { + doundef(); + continue; + } + else if (match("#pragma")) { + dopragma(); + continue; + } + } + if (!skiplevel) return (0); + } +} + +/* + * noiferr + * Input : nothing + * Output : nothing + * + * Called when a #if statement is lacking + * + */ +void noiferr (void) +{ + error("no matching #if..."); +} + + +intptr_t cpp (int subline) +{ + intptr_t k; + char c, sname[NAMESIZE]; + intptr_t tog; + intptr_t cpped; /* non-zero if something expanded */ + intptr_t llptr; + + cpped = 0; + /* don't expand lines with preprocessor commands in them */ + if (!subline && (!cmode || line[0] == '#')) { + if (sstreq("#include")) + return (0); + + /* except #inc/#def commands */ + if (!match("#inc") && !match("#def")) + return (0); + } + + mptr = 0; + if (subline) + llptr = lptr; /* start wherever we are right now */ + else + llptr = lptr = 0; /* do the whole line */ + + while (ch()) { + if ((ch() == ' ') || (ch() == 9)) { + keepch(' '); + while ((ch() == ' ') || (ch() == 9)) + gch(); + } + else if (ch() == '"') { + keepch(ch()); + gch(); + while (ch() != '"') { + if (ch() == 0) { + error("missing quote"); + break; + } + if (ch() == '\\') keepch(gch()); + keepch(gch()); + } + gch(); + keepch('"'); + } + else if (ch() == '\'') { + keepch('\''); + gch(); + while (ch() != '\'') { + if (ch() == 0) { + error("missing apostrophe"); + break; + } + if (ch() == '\\') keepch(gch()); + keepch(gch()); + } + gch(); + keepch('\''); + } + else if ((ch() == '/') && (nch() == '*')) { + inchar(); + inchar(); + while ((((c = ch()) == '*') && (nch() == '/')) == 0) + if (c == '$') { + inchar(); + tog = TRUE; + if (ch() == '-') { + tog = FALSE; + inchar(); + } + if (alpha(c = ch())) { + inchar(); + toggle(c, tog); + } + } + else { + if (ch() == 0) + readline(); + else + inchar(); + if (feof(input)) + break; + } + inchar(); + inchar(); + } + else if (ch() == '/' && nch() == '/') { + while (ch()) + inchar(); + } + else if (an(ch())) { + k = 0; + while (an(ch())) { + if (k < NAMEMAX) + sname[k++] = ch(); + gch(); + } + sname[k] = 0; + struct macro *mp; + mp = findmac(sname); + if (mp) { + char args[40][256]; + int argc = 0; + int haveargs = 0; + int nest = 0; + /* If the macro wants arguments, substitute them. + Unlike at the time of definition, here whitespace + is permissible between the macro identifier and + the opening parenthesis. */ + if (mp->argc && match("(")) { + if (mp->argc == -1) { + if (!match(")")) { + error("missing closing paren"); + return (0); + } + } + else { + haveargs = 1; + for (;;) { + char * parg = args[argc]; + char * pend = args[argc] + 255; + parg[0] = '\0'; + while (ch() != ',' || nest > 0) { + char c = gch(); + if (c == '(') + nest++; + if (!c) { + error("missing closing paren"); + return (0); + } + parg[0] = c; + parg[1] = '\0'; + if (++parg >= pend) { + error("macro argument too intptr_t"); + return (0); + } + if (ch() == ')') { + if (nest) + nest--; + else + break; + } + } +#ifdef DEBUG_PREPROC + printf("macro arg %s\n", args[argc]); +#endif + argc++; + if (ch() == ')') { + gch(); + break; + } + gch(); + } + } + } + if (mp->argc != -1 && argc != mp->argc) { + error("wrong number of macro arguments"); + return (0); + } + + cpped = 1; + k = 0; + if (haveargs) { + int i; + char *buf = malloc(1); + buf[0] = 0; + char *dp = mp->def; + buf[0] = 0; + for (i = 0; mp->argpos[i].arg != -1; i++) { + buf = realloc(buf, strlen(buf) + + mp->argpos[i].pos - (dp - mp->def) + + strlen(args[mp->argpos[i].arg]) + 1); + strncat(buf, dp, mp->argpos[i].pos - (dp - mp->def)); + strcat(buf, args[mp->argpos[i].arg]); + dp = mp->def + mp->argpos[i].pos + strlen(mp->args[mp->argpos[i].arg]); + } + buf = realloc(buf, strlen(buf) + strlen(dp) + 1); + strcat(buf, dp); +#ifdef DEBUG_PREPROC + printf("postproc %s\n", buf); +#endif + for (i = 0; buf[i]; i++) + keepch(buf[i]); + free(buf); + } + else { + while ((c = mp->def[k++])) + keepch(c); + keepch(' '); + } + } + else { + k = 0; + while ((c = sname[k++])) + keepch(c); + } + } + else + keepch(gch()); + } + keepch(0); + if (mptr >= MPMAX) + error("line too intptr_t"); + /* copy cooked input back to where we got the raw input from */ + strcpy(&line[llptr], mline); + /* ...and continue processing at that point */ + lptr = llptr; + return (cpped); +} + +intptr_t keepch (char c) +{ + mline[mptr] = c; + if (mptr < MPMAX) + mptr++; + return (c); +} + +void defmac (char *s) +{ + kill(); + strcpy(line, s); + addmac(); +} + +void addmac (void) +{ + char sname[NAMESIZE]; + struct macro *mp; + + if (!symname(sname)) { + illname(); + kill(); + return; + } + mp = findmac(sname); + if (mp) { + error("Duplicate define"); + delmac(mp); + } + else + mp = &macq[macptr++]; + + mp->name = strdup(sname); + + int argc = 0; + mp->args = malloc(sizeof(char *) * 1); + mp->args[0] = 0; + mp->argpos = malloc(sizeof(*mp->argpos) * 1); + mp->argpos[0].arg = -1; + /* Stuff within parentheses is only considered a list of arguments + if there is no whitespace between the identifier and the opening + paren. */ + if (ch() == '(') { + gch(); + if (match(")")) + argc = -1; + else { + for (;;) { + if (!symname(sname)) { + error("invalid macro argument"); + delmac(mp); + return; + } +#ifdef DEBUG_PREPROC + printf("arg %d %s\n", argc, sname); +#endif + mp->args = realloc(mp->args, sizeof(char *) * (argc + 2)); + mp->args[argc++] = strdup(sname); + if (argc >= 40) { + error("too many arguments"); + delmac(mp); + return; + } + mp->args[argc] = 0; + if (match(")")) + break; + if (!match(",")) { + error("expected comma"); + delmac(mp); + return; + } + } + } + } + mp->argc = argc; + + while ((ch() == ' ') || (ch() == 9)) + gch(); + char c; + mp->def = malloc(1); + mp->def[0] = 0; + int pos = 0; + int count = 0; + for (;;) { + int found = 0; + int i; + if (ch() == '/' && nch() == '/') { + kill(); + break; + } + for (i = 0; i < argc; i++) { + if (an(ch()) && amatch(mp->args[i], strlen(mp->args[i]))) { +#ifdef DEBUG_PREPROC + printf("arg %d at offset %d\n", i, pos); +#endif + mp->def = realloc(mp->def, strlen(mp->def) + strlen(mp->args[i]) + 1); + strcat(mp->def, mp->args[i]); + mp->argpos = realloc(mp->argpos, sizeof(*mp->argpos) * (count + 2)); + mp->argpos[count].arg = i; + mp->argpos[count++].pos = pos; + mp->argpos[count].arg = -1; + mp->argpos[count].pos = -1; + pos += strlen(mp->args[i]); + found = 1; + break; + } + } + if (!found) { + c = gch(); + if (c == '\\') { + c = gch(); + if (!c) { + readline(); + c = gch(); + } + } + if (!c) + break; + mp->def = realloc(mp->def, strlen(mp->def) + 2); + strncat(mp->def, &c, 1); + pos++; + } + } +#ifdef DEBUG_PREPROC + printf("macdef %s\n", mp->def); +#endif + if (macptr >= MACMAX) + error("macro table full"); +} + +void delmac (struct macro *mp) +{ + if (mp->name) + free(mp->name); + mp->name = 0; + if (mp->def) + free(mp->def); + mp->def = 0; + if (mp->args) + free(mp->args); + mp->args = 0; + if (mp->argpos) + free(mp->argpos); + mp->argpos = 0; +} + +struct macro *findmac (char *sname) +{ + intptr_t k; + + k = 0; + while (k < macptr) { + if (macq[k].name && astreq(sname, macq[k].name, NAMEMAX)) + return (&macq[k]); + + k++; + } + return (0); +} + +void toggle (char name, intptr_t onoff) +{ + switch (name) { + case 'C': + ctext = onoff; + break; + } +} diff --git a/src/huc/preproc.h b/src/huc/preproc.h new file mode 100644 index 00000000..8f23e5e4 --- /dev/null +++ b/src/huc/preproc.h @@ -0,0 +1,44 @@ +#ifndef _INCLUDE_PREPROC_H +#define _INCLUDE_PREPROC_H + +void doinclude (void); + +void incl_globals (void); + +FILE *fixiname (void); + +void init_path (void); + +void doasmdef (void); + +void doasm (void); + +void dodefine (void); + +void doundef (void); + +void preprocess (void); + +void doifdef (intptr_t ifdef); + +intptr_t ifline (void); + +void noiferr (void); + +intptr_t cpp (int); + +intptr_t keepch (char c); + +void defmac (char *s); + +void addmac (void); + +void delmac (struct macro *mp); + +struct macro *findmac (char *sname); + +void toggle (char name, intptr_t onoff); + +char **include_dirs (void); + +#endif diff --git a/src/huc/primary.c b/src/huc/primary.c new file mode 100644 index 00000000..0cab47d9 --- /dev/null +++ b/src/huc/primary.c @@ -0,0 +1,867 @@ +/* File primary.c: 2.4 (84/11/27,16:26:07) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "enum.h" +#include "error.h" +#include "expr.h" +#include "gen.h" +#include "io.h" +#include "lex.h" +#include "primary.h" +#include "sym.h" +#include "struct.h" + +extern char current_fn[]; + +int match_type (struct type *t, int do_ptr, int allow_unk_compound) +{ + char n[NAMESIZE]; + int have_sign = 0; + int sflag; + int i; + static int anon_struct_cnt = 0; + + t->type = 0; + t->flags = 0; + t->otag = -1; + + for (i = 0; i < typedef_ptr; i++) { + if (amatch(typedefs[i].sname, strlen(typedefs[i].sname))) { + *t = typedefs[i]; + goto ret_do_ptr; + } + } + + if (amatch("register", 8)) + t->flags |= F_REGISTER; + if (amatch("volatile", 8)) + t->flags |= F_VOLATILE; + if (amatch("const", 5)) + t->flags |= F_CONST; + + if ((sflag = amatch("struct", 6)) || amatch("union", 5)) { + /* compound */ + if (symname(n)) { + t->otag = find_tag(n); + if (t->otag < 0 && !allow_unk_compound) { + error("unknown struct name"); + junk(); + return (0); + } + t->type = CSTRUCT; + if (sflag) + t->flags |= F_STRUCT; + strcpy(t->sname, n); + } + else { + blanks(); + if (ch() == '{') { + sprintf(t->sname, "__anon_struct%d", anon_struct_cnt++); + t->otag = define_struct(t->sname, DEFAUTO, sflag); + t->type = CSTRUCT; + if (sflag) + t->flags |= F_STRUCT; + } + else { + error("illegal struct name"); + junk(); + return (0); + } + } + } + else if (amatch("enum", 4)) { + t->type = CENUM; + if (symname(n)) { + /* This may or may not find an enum type, but if + it doesn't it's not necessarily an error. */ + t->otag = find_enum_type(n); + strcpy(t->sname, n); + } + else { + blanks(); + if (ch() == '{') { + /* anonymous enum */ + t->otag = define_enum(NULL, DEFAUTO); + t->sname[0] = 0; + } + else { + illname(); + junk(); + return (0); + } + } + } + else { + /* scalar */ + if (amatch("unsigned", 8)) { + t->type |= CUNSIGNED; + have_sign = 1; + } + else if (amatch("signed", 6)) + have_sign = 1; + + if (amatch("char", 4)) { + t->type |= CCHAR; + if ((have_sign == 0) && (user_signed_char == 0)) + t->type |= CUNSIGNED; + } + else if (amatch("int", 3)) + t->type |= CINT; + else if (amatch("short", 5)) { + amatch("int", 3); + t->type |= CINT; + } + else if (amatch("void", 4)) { + if (have_sign) + goto invalid_cast; + t->type |= CVOID; + } + else { + if (have_sign) + t->type |= CINT; + else /* not a cast */ + return (0); + } + } + + t->ident = VARIABLE; + t->ptr_order = 0; + +ret_do_ptr: + if (do_ptr) + while (match("*")) { + t->ident = POINTER; + t->ptr_order++; + } + + return (1); + +invalid_cast: + error("invalid type cast"); + return (0); +} + +intptr_t primary (LVALUE *lval, int comma) +{ + SYMBOL *ptr; + char sname[NAMESIZE]; + intptr_t num[1]; + intptr_t k; + + lval->ptr_type = 0; /* clear pointer/array type */ + lval->ptr_order = 0; + lval->symbol2 = 0; + if (match("(")) { + struct type t; + if (match_type(&t, YES, NO)) { + needbrack(")"); + k = heir10(lval, comma); + if (k) + rvalue(lval); + if (t.ident != POINTER) { + gcast(t.type); + lval->ptr_type = 0; + } + else + lval->ptr_type = t.type; + lval->type = t.type; + lval->ptr_order = t.ptr_order; + return (0); + } + else { + indflg = 0; + /* need to use expression_ex() (not heir1()), otherwise + the comma operator is not handled */ + k = expression_ex(lval, comma, YES); + needbrack(")"); + return (k); + } + } + if (amatch("sizeof", 6)) { + int have_paren; + struct type t; + indflg = 0; + have_paren = match("("); + if (match_type(&t, YES, NO)) { + if (t.ident == POINTER) + immed(T_VALUE, INTSIZE); + else if (t.type == CSTRUCT) + immed(T_VALUE, tag_table[t.otag].size); + else if (t.type == CINT || t.type == CUINT) + immed(T_VALUE, INTSIZE); + else if (t.type == CCHAR || t.type == CUCHAR) + immed(T_VALUE, 1); + else { + error("internal error: sizeof type unknown"); + return (0); + } + } + else if (symname(sname)) { + if (!strcmp("__func__", sname) || + !strcmp("__FUNCTION__", sname)) + immed(T_VALUE, strlen(current_fn) + 1); + else if (!strcmp("__FILE__", sname)) + immed(T_VALUE, strlen(fname_copy) + 1); + else if ((ptr = findloc(sname)) || + (ptr = findglb(sname))) { + k = ptr->size; + immed(T_VALUE, k); + } + else { + error("sizeof undeclared variable"); + immed(T_VALUE, 0); + } + } + else if (readqstr()) + immed(T_VALUE, strlen(litq2)); + else + error("sizeof only on type or variable"); + if (have_paren) + needbrack(")"); + lval->symbol = 0; + lval->indirect = 0; + return (0); + } + if (amatch("__FUNCTION__", 12) || amatch("__func__", 8)) { + const_str(num, current_fn); + immed(T_STRING, num[0]); + indflg = 0; + lval->value = num[0]; + lval->symbol = 0; + lval->indirect = 0; + return (0); + } + else if (amatch("__FILE__", 8)) { + const_str(num, fname_copy); + immed(T_STRING, num[0]); + indflg = 0; + lval->value = num[0]; + lval->symbol = 0; + lval->indirect = 0; + return (0); + } + else if (amatch("__sei", 5) && match("(") && match(")")) { + gsei(); + return (0); + } + else if (amatch("__cli", 5) && match("(") && match(")")) { + gcli(); + return (0); + } + + if (symname(sname)) { + if (find_enum(sname, num)) { + indflg = 0; + lval->value = num[0]; + lval->symbol = 0; + lval->indirect = 0; + immed(T_VALUE, *num); + return (0); + } + ptr = findloc(sname); + if (ptr) { + /* David, patched to support + * local 'static' variables + */ + lval->symbol = ptr; + lval->indirect = ptr->type; + lval->tagsym = 0; + if (ptr->type == CSTRUCT) + lval->tagsym = &tag_table[ptr->tagidx]; + if (ptr->ident == POINTER) { + if ((ptr->storage & ~WRITTEN) == LSTATIC) + lval->indirect = 0; + else { + lval->indirect = CUINT; + getloc(ptr); + } + lval->ptr_type = ptr->type; + lval->ptr_order = ptr->ptr_order; + return (1); + } + if (ptr->ident == ARRAY || + (ptr->ident == VARIABLE && ptr->type == CSTRUCT)) { + getloc(ptr); + lval->ptr_type = ptr->type; + lval->ptr_order = ptr->ptr_order; +// lval->ptr_type = 0; + if (ptr->type == CSTRUCT && ptr->ident == VARIABLE) + return (1); + else + return (0); + } + if ((ptr->storage & ~WRITTEN) == LSTATIC) + lval->indirect = 0; + else + getloc(ptr); + return (1); + } + ptr = findglb(sname); + if (ptr) { + if (ptr->ident != FUNCTION) { + lval->symbol = ptr; + lval->indirect = 0; + lval->tagsym = 0; + if (ptr->type == CSTRUCT) + lval->tagsym = &tag_table[ptr->tagidx]; + if (ptr->ident != ARRAY && + (ptr->ident != VARIABLE || ptr->type != CSTRUCT)) { + if (ptr->ident == POINTER) { + lval->ptr_type = ptr->type; + lval->ptr_order = ptr->ptr_order; + } + return (1); + } + if (!ptr->far) + immed(T_SYMBOL, (intptr_t)ptr); + else { + /* special variables */ + blanks(); + if ((ch() != '[') && (ch() != '(')) { + /* vram */ + if (strcmp(ptr->name, "vram") == 0) { + if (indflg) + return (1); + else + error("can't access vram this way"); + } + /* others */ + immed(T_SYMBOL, (intptr_t)ptr); +// error ("can't access far array"); + } + } + lval->indirect = lval->ptr_type = ptr->type; + lval->ptr_order = ptr->ptr_order; +// lval->ptr_type = 0; + if (ptr->ident == VARIABLE && ptr->type == CSTRUCT) + return (1); + else + return (0); + } + } + blanks(); + if (ch() != '(') { + if (ptr && (ptr->ident == FUNCTION)) { + lval->symbol = ptr; + lval->indirect = 0; + immed(T_SYMBOL, (intptr_t)ptr->name); + return (0); + } + error("undeclared variable"); + } + ptr = addglb(sname, FUNCTION, CINT, 0, PUBLIC, 0); + indflg = 0; + lval->symbol = ptr; + lval->indirect = 0; + return (0); + } + if ((k = constant(num))) { + indflg = 0; + lval->value = num[0]; + lval->symbol = 0; + lval->indirect = 0; + if (k == 2) { + lval->ptr_type = CCHAR; + lval->ptr_order = 1; + } + return (0); + } + else { + indflg = 0; + error("invalid expression"); + immed(T_VALUE, 0); + junk(); + return (0); + } +} + +/* + * true if val1 -> int pointer or int array and val2 not pointer or array + */ +intptr_t dbltest (LVALUE val1[], LVALUE val2[]) +{ + if (val1 == NULL || !val1->ptr_type) + return (FALSE); + + if (val1->ptr_type == CCHAR || val1->ptr_type == CUCHAR) + return (FALSE); + + if (val2->ptr_type) + return (FALSE); + + return (TRUE); +} + +/* + * determine type of binary operation + */ +void result (LVALUE lval[], LVALUE lval2[]) +{ + if (lval->ptr_type && lval2->ptr_type) { + lval->ptr_type = 0; + lval->ptr_order = 0; + } + else if (lval2->ptr_type) { + lval->symbol = lval2->symbol; + lval->indirect = lval2->indirect; + lval->ptr_type = lval2->ptr_type; + lval->ptr_order = lval2->ptr_order; + } +} + +intptr_t constant (intptr_t val[]) +{ + if (number(val)) + immed(T_VALUE, val[0]); + else if (pstr(val)) + immed(T_VALUE, val[0]); + else if (qstr(val)) { + immed(T_STRING, val[0]); + return (2); + } + else + return (0); + + return (1); +} + +intptr_t number (intptr_t val[]) +{ + intptr_t k, minus, base; + char c; + + k = minus = 1; + while (k) { + k = 0; + if (match("+")) + k = 1; + if (match("-")) { + minus = (-minus); + k = 1; + } + } + if (!numeric(c = ch())) + return (0); + + if (match("0x") || match("0X")) { + while (numeric(c = ch()) || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')) { + inbyte(); + k = k * 16 + + (numeric(c) ? (c - '0') : ((c & 07) + 9)); + } + } + else if (match("0b") || match("0B")) { + while (numeric(c = ch()) && + ((c == '1') || + (c == '0'))) { + inbyte(); + k = k * 2 + (c - '0'); + } + } + else { + base = (c == '0') ? 8 : 10; + while (numeric(ch())) { + c = inbyte(); + k = k * base + (c - '0'); + } + } + if (minus < 0) + k = (-k); + val[0] = k; + return (1); +} + +static int parse0 (intptr_t *num) +{ + if (!const_expr(num, ")", NULL)) + return (0); + + if (!match(")")) + error("internal error"); + return (1); +} + +static int parse3 (intptr_t *num) +{ + intptr_t num2; + struct type t; + char op; + char n[NAMESIZE]; + int have_paren = 0; + + if (match("-")) + op = '-'; + else if (match("+")) + op = '+'; + else if (match("~")) + op = '~'; + else if (match("!")) + op = '!'; + else if (match("(")) { + if (match_type(&t, YES, NO)) { + if (!match(")")) { + error("invalid type cast"); + return (0); + } + op = 'c'; + } + else { + have_paren = 1; + op = 0; + } + } + else + op = 0; + + if (!(have_paren && parse0(&num2)) && + !number(&num2) && + !pstr(&num2) && + !(symname(n) && find_enum(n, &num2))) + return (0); + + if (op == '-') + *num = -num2; + else if (op == '~') + *num = ~num2; + else if (op == '!') + *num = !num2; + else if (op == 'c') { + if (t.ident != POINTER) { + assert(sizeof(short) == 2); + switch (t.type) { + case CCHAR: + *num = (char)num2; + break; + case CUCHAR: + *num = (unsigned char)num2; + break; + case CINT: + *num = (short)num2; + break; + case CUINT: + *num = (unsigned short)num2; + break; + default: + error("unable to handle cast in constant expression"); + return (0); + } + } + else + *num = num2; + } + else + *num = num2; + return (1); +} + +static int parse5 (intptr_t *num) +{ + intptr_t num1, num2; + + if (!parse3(&num1)) + return (0); + + for (;;) { + char op; + if (match("*")) + op = '*'; + else if (match("/")) + op = '/'; + else { + *num = num1; + return (1); + } + + if (!parse3(&num2)) + return (0); + + if (op == '*') + num1 *= num2; + else + num1 /= num2; + } +} + +static int parse6 (intptr_t *num) +{ + intptr_t num1, num2; + + if (!parse5(&num1)) + return (0); + + for (;;) { + char op; + if (match("+")) + op = '+'; + else if (match("-")) + op = '-'; + else { + *num = num1; + return (1); + } + + if (!parse5(&num2)) + return (0); + + if (op == '-') + num1 -= num2; + else + num1 += num2; + } +} + +static int parse7 (intptr_t *num) +{ + intptr_t num1, num2; + + if (!parse6(&num1)) + return (0); + + for (;;) { + char op; + if (match("<<")) + op = 'l'; + else if (match(">>")) + op = 'r'; + else { + *num = num1; + return (1); + } + + if (!parse6(&num2)) + return (0); + + if (op == 'l') + num1 <<= num2; + else + num1 >>= num2; + } +} + +static int parse9 (intptr_t *num) +{ + intptr_t num1, num2; + + if (!parse7(&num1)) + return (0); + + for (;;) { + char op; + if (match("==")) + op = '='; + else if (match("!=")) + op = '!'; + else { + *num = num1; + return (1); + } + + if (!parse7(&num2)) + return (0); + + if (op == '=') + num1 = num1 == num2; + else + num1 = num1 != num2; + } +} + +int const_expr (intptr_t *num, char *end1, char *end2) +{ + if (!parse9(num)) { + error("failed to evaluate constant expression"); + return (0); + } + blanks(); + if (end1 && !sstreq(end1) && !(end2 && sstreq(end2))) { + error("unexpected character after constant expression"); + return (0); + } + return (1); +} + +/* + * pstr + * pstr parses a character than can eventually be 'double' i.e. like 'a9' + * returns 0 in case of failure else 1 + */ +intptr_t pstr (intptr_t val[]) +{ + intptr_t k; + char c; + + k = 0; + if (!match("'")) + return (0); + + while ((c = gch()) != '\'') { + c = (c == '\\') ? spechar() : c; + k = (k & 255) * 256 + (c & 255); + } + val[0] = k; + return (1); +} + +/* + * qstr + * qstr parses a double quoted string into litq + * return 0 in case of failure and 1 else + */ +intptr_t qstr (intptr_t val[]) +{ + char c; + + if (!match(quote)) + return (0); + + val[0] = litptr; + while (ch() != '"') { + if (ch() == 0) + break; + if (litptr >= LITMAX) { + error("string space exhausted"); + while (!match(quote)) + if (gch() == 0) + break; + return (1); + } + c = gch(); + litq[litptr++] = (c == '\\') ? spechar() : c; + } + gch(); + litq[litptr++] = 0; + return (1); +} + +intptr_t const_str (intptr_t *val, const char *str) +{ + if (litptr + strlen(str) + 1 >= LITMAX) { + error("string space exhausted"); + return (1); + } + strcpy(&litq[litptr], str); + *val = litptr; + litptr += strlen(str) + 1; + return (1); +} + +/* + * readqstr + * readqstr parses a double quoted string into litq2 + * return 0 in case of failure and 1 else + * Zeograd: this function don't dump the result of the reading in the literal + * pool, it is rather intended for use in pseudo code + */ +intptr_t readqstr (void) +{ + char c; + intptr_t posptr = 0; + + if (!match(quote)) + return (0); + + while (ch() != '"') { + if (ch() == 0) + break; + if (posptr >= LITMAX2) { + error("string space exhausted"); + while (!match(quote)) + if (gch() == 0) + break; + return (1); + } + c = gch(); + litq2[posptr++] = (c == '\\') ? spechar() : c; + } + gch(); + litq2[posptr] = 0; + return (1); +} + +/* + * readstr + * reaqstr parses a string into litq2 + * it only read alpha numeric characters + * return 0 in case of failure and 1 else + * Zeograd: this function don't dump the result of the reading in the literal + * pool, it is rather intended for use in pseudo code + */ +intptr_t readstr (void) +{ + char c; + intptr_t posptr = 0; + + while (an(ch()) || (ch() == '_')) { + if (ch() == 0) + break; + if (posptr >= LITMAX2) { + error("string space exhausted"); + return (1); + } + c = gch(); + litq2[posptr++] = (c == '\\') ? spechar() : c; + } + litq2[posptr] = 0; + return (1); +} + + +/* + * decode special characters (preceeded by back slashes) + */ +intptr_t spechar (void) +{ + char c; + + c = ch(); + + if (c == 'n') c = EOL; + else if (c == 't') c = TAB; + else if (c == 'r') c = CR; + else if (c == 'f') c = FFEED; + else if (c == 'b') c = BKSP; + else if (c == '0') c = EOS; + else if (numeric(c) && c < '8') { + /* octal character specification */ + int n = 0; + while (numeric(c) && c < '8') { + n = (n << 3) | (c - '0'); + gch(); + c = ch(); + } + return (n); + } + else if (c == 'x') { + int n = 0, i; + gch(); + for (i = 0; i < 2; i++) { + c = gch(); + if (c >= 'a' && c <= 'f') + c = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else if (c >= '0' && c <= '9') + c = c - '0'; + else { + error("invalid hex character"); + return (0); + } + n = (n << 4) | c; + } + return (n); + } + else if (c == EOS) return (c); + + gch(); + return (c); +} diff --git a/src/huc/primary.h b/src/huc/primary.h new file mode 100644 index 00000000..81ac99b8 --- /dev/null +++ b/src/huc/primary.h @@ -0,0 +1,24 @@ +/* File primary.c: 2.4 (84/11/27,16:26:07) */ +/*% cc -O -c % + * + */ + +#ifndef _PRIMARY_H +#define _PRIMARY_H + +intptr_t primary (LVALUE *lval, int comma); +intptr_t dbltest (LVALUE val1[], LVALUE val2[]); +void result (LVALUE lval[], LVALUE lval2[]); +intptr_t constant (intptr_t val[]); +intptr_t number (intptr_t val[]); +int const_expr (intptr_t *, char *, char *); +intptr_t pstr (intptr_t val[]); +intptr_t qstr (intptr_t val[]); +intptr_t const_str (intptr_t val[], const char *); +intptr_t readqstr (void); +intptr_t readstr (void); +intptr_t spechar (void); + +int match_type (struct type *, int do_ptr, int allow_unk_compound); + +#endif diff --git a/src/huc/pseudo.c b/src/huc/pseudo.c new file mode 100644 index 00000000..e0f75134 --- /dev/null +++ b/src/huc/pseudo.c @@ -0,0 +1,1164 @@ +/* + * pseudo.c + */ + +#include +#include +#include +#include "data.h" +#include "defs.h" +#include "code.h" +#include "const.h" +#include "error.h" +#include "io.h" +#include "lex.h" +#include "optimize.h" +#include "primary.h" +#include "pseudo.h" +#include "sym.h" + + +/* local array to store internal strings */ +static char str_buf[0x10000]; +static intptr_t str_idx; + +/* protos */ +char *new_string (intptr_t und, char *a); +void do_inc_ex (intptr_t type); + +/* + * This source file includes all kind of stuff used to 'simulate' pseudo code + * of the magic kit and so using itself pseudo C functions... + */ +void dopsdinc (void) +{ + intptr_t dummy; /* Used in the qstr function, I don't know its utility yet */ + intptr_t numericarg = 0; /* Number of numeric arg to test validity */ + + if (amatch("pal", 3)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".incpal \""); + + if (readqstr() == 0) { + /* read the filename */ + error("bad filename in incpal"); + kill(); + return; + } + + outstr(litq2); + outstr("\""); + + if (match(",")) + outstr(","); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + outdec(dummy); + if (match(",")) + outstr(","); + } + + nl(); + ol(".code"); + + if (numericarg > 2) + error("Maximum 2 numeric arg for incpal(name,\"filename\" [,start_pal] [,nb_pal])"); + + kill(); + } + else + if (amatch("bin", 3)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CUCHAR); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".incbin \""); + if (readqstr() == 0) { + /* read the filename */ + error("bad filename in incbin"); + kill(); + return; + } + outstr(litq2); + outstr("\"\n"); + + if (!match(")")) + error("missing )"); + + nl(); + ol(".code"); + kill(); + } + else + if (amatch("bat", 3)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".incbat \""); + + if (readqstr() == 0) { + error("bad filename in incbat"); + kill(); + return; + } + + outstr(litq2); + outstr("\""); + + if (match(",")) + outstr(","); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + outdec(dummy); + if (match(",")) + outstr(","); + } + + nl(); + ol(".code"); + + if ((numericarg != 1) && + (numericarg != 3) && + (numericarg != 5)) + error("Either 1,3 or 5 numeric arguments are needed for incbat statement"); + + kill(); + } + else + if (amatch("spr", 3)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".incspr \""); + + if (readqstr() == 0) { + error("bad filename in incspr"); + kill(); + return; + } + + outstr(litq2); + outstr("\""); + + if (match(",")) + outstr(","); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + outdec(dummy); + if (match(",")) + outstr(","); + } + + nl(); + ol(".code"); + + if ((numericarg != 0) && + (numericarg != 2) && + (numericarg != 4)) + error("Either 0,2 or 4 numeric arguments are needed for incspr statement"); + + kill(); + } + else + if (amatch("sprpal", 6)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".incsprpal \""); + + if (readqstr() == 0) { + error("bad filename in incsprpal"); + kill(); + return; + } + + outstr(litq2); + outstr("\""); + + if (match(",")) + outstr(","); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + outdec(dummy); + if (match(",")) + outstr(","); + } + + nl(); + ol(".code"); + + if ((numericarg != 0) && + (numericarg != 2) && + (numericarg != 4)) + error("Either 0,2 or 4 numeric arguments are needed for incsprpal statement"); + + kill(); + } + else + if (amatch("chr", 3)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".incchr \""); + + if (readqstr() == 0) { + error("bad filename in incchr"); + kill(); + return; + } + + outstr(litq2); + outstr("\""); + + if (match(",")) + outstr(","); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + outdec(dummy); + if (match(",")) + outstr(","); + } + + nl(); + ol(".code"); + + if ((numericarg != 0) && + (numericarg != 2) && + (numericarg != 4)) + error("Either 0,2 or 4 numeric arguments are needed for incchr statement"); + + kill(); + } + else + if (amatch("chrpal", 6)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".incchrpal \""); + + if (readqstr() == 0) { + error("bad filename in incchrpal"); + kill(); + return; + } + + outstr(litq2); + outstr("\""); + + if (match(",")) + outstr(","); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + outdec(dummy); + if (match(",")) + outstr(","); + } + + nl(); + ol(".code"); + + if ((numericarg != 0) && + (numericarg != 2) && + (numericarg != 4)) + error("Either 0,2 or 4 numeric arguments are needed for incchrpal statement"); + + kill(); + } + else + if (amatch("chr_ex", 6)) + do_inc_ex(8); + else + if (amatch("tile", 4)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".inctile \""); + + if (readqstr() == 0) { + error("bad filename in inctile"); + kill(); + return; + } + + outstr(litq2); + outstr("\""); + + if (match(",")) + outstr(","); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + outdec(dummy); + if (match(",")) + outstr(","); + } + + nl(); + ol(".code"); + + if ((numericarg != 0) && + (numericarg != 2) && + (numericarg != 4)) + error("Either 0,2 or 4 numeric arguments are needed for inctile statement"); + + kill(); + } + else + if (amatch("tilepal", 7)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":\n"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".inctilepal \""); + + if (readqstr() == 0) { + error("bad filename in inctilepal"); + kill(); + return; + } + + outstr(litq2); + outstr("\""); + + if (match(",")) + outstr(","); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + outdec(dummy); + if (match(",")) + outstr(","); + } + + nl(); + ol(".code"); + + if ((numericarg != 0) && + (numericarg != 2) && + (numericarg != 4)) + error("Either 0,2 or 4 numeric arguments are needed for inctilepal statement"); + + kill(); + } + else + if (amatch("tile_ex", 7)) + do_inc_ex(16); + else + if (amatch("asmlabel", 8)) { + if (!match("(")) + error("missing ("); + + // .data first! + nl(); + ol(".code"); + + // Get the label, but save it for later. + readstr(); + strcpy(str_buf, litq2); + addglb_far(litq2, CUCHAR); + + if (!match(",")) { + error("asmlabel missing ,"); + kill(); + return; + } + + // Get the file name + if (readqstr() == 0) { + error("bad filename in incasm"); + kill(); + return; + } + + // If page argument, then get it. Else default it. + if (match(",")) { + if (number(&dummy) != 0) { + ot(".page "); + if (dummy > 8) + outdec(dummy / 0x2000); + else + outdec(dummy); + nl(); + } + else { + error("missing page number/address"); + kill(); + return; + } + } + else { + ol(".page 2"); + } + + // Output the label name: + prefix(); + outstr(str_buf); + outstr(":\n"); + + ot(".include \""); + outstr(litq2); + outstr("\""); + nl(); + + if (!match(")")) + error("missing )"); + nl(); + kill(); + } + else + if (amatch("asm", 3)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + if (readqstr() == 0) { + error("bad filename in incasm"); + kill(); + return; + } + + if (match(",")) { + if (number(&dummy) != 0) { + ot(".page "); + if (dummy > 8) + outdec(dummy / 0x2000); + else + outdec(dummy); + nl(); + } + else { + error("missing page number/address"); + kill(); + return; + } + } + + ot(".include \""); + outstr(litq2); + outstr("\""); + nl(); + + ol(".page 3"); /* assumes data bank is mapped at 0x6000 */ + + if (!match(")")) + error("missing )"); + ol(".code"); + kill(); + } + else { + error("Unknown include directive"); + kill(); + } + return; +} + + +void dopsddef (void) +{ + intptr_t numericarg = 0; + intptr_t dummy; + intptr_t dummy_array[16]; + intptr_t i; + + if (amatch("pal", 3)) { + if (!match("(")) + error("missing ("); + + readstr(); /* read the label name */ + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ',' in #defpal"); + kill(); + return; + } + + numericarg = 0; + + while (!match(")")) { + number(&dummy_array[numericarg]); + numericarg++; + + if (numericarg > 16) + error("No more than 16 colors can be defined at once"); + + match(","); + } + + ol(".data"); + prefix(); + outstr(litq2); + outstr(":"); + ot(".defpal "); + + for (i = 0; i < numericarg; i++) { + outhexfix(dummy_array[i], 3); + + if (i < numericarg - 1) { + outstr(","); + if (i == 7) { + outstr(" \\\n"); + ot("\t"); + } + } + } + + nl(); + ol(".code"); + + kill(); + } + else + if (amatch("chr", 3)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".defchr "); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + + switch (numericarg) { + case 1: + outhexfix(dummy, 4); + outstr(","); + break; + case 2: + outdec(dummy); + outstr(",\\"); + nl(); + break; + case 10: + outhexfix(dummy, 8); + break; + default: + outhexfix(dummy, 8); + outstr(",\\"); + nl(); + } + + match(","); + } + + nl(); + ol(".code"); + + if (numericarg != 10) + error("You must enter the VRAM address, the default palette and 8 values for pattern"); + + kill(); + } + else + if (amatch("spr", 3)) { + if (!match("(")) + error("missing ("); + + ol(".data"); + + readstr(); /* read the label name */ + prefix(); + outstr(litq2); + outstr(":"); + addglb_far(litq2, CINT); + + if (!match(",")) { + error("missing ,"); + kill(); + return; + } + + ot(".defspr "); + + numericarg = 0; + + while (!match(")")) { + numericarg++; + + number(&dummy); + + switch (numericarg) { + case 1: + outhexfix(dummy, 4); + outstr(","); + break; + case 2: + outdec(dummy); + outstr(",\\"); + nl(); + break; + case 34: + outhexfix(dummy, 8); + break; + default: + outhexfix(dummy, 8); + outstr(","); + + if (!(numericarg & 1)) { + outstr("\\"); + nl(); + } + } + + match(","); + } + + nl(); + ol(".code"); + + if (numericarg != 34) + error("You must enter the VRAM address, the default palette and 32 values for pattern"); + + kill(); + } + else { + error("Unknown define directive"); + kill(); + } + return; +} + + +intptr_t outcomma (void) +{ + if (!match(",")) { + error("missing ,"); + kill(); + return (1); + } + + outbyte(','); + + return (0); +} + +intptr_t outnameunderline (void) +{ + char n[NAMESIZE]; + + if (!symname(n)) { + error("invalid identifier"); + kill(); + return (1); + } + + prefix(); + outstr(n); + + return (0); +} + +intptr_t outconst (void) +{ + intptr_t dummy; + + number(&dummy); + outbyte('#'); + outdec(dummy); + + return (0); +} + +void doset_bgpalstatement (void) +{ + /* syntax is + number of the first palette to alter : integer + name of the data for loading palettes : identifier + [ number of palette to load : integer ] + if last argument is missing, 1 is assumed + */ + + flush_ins(); /* David, optimize.c related */ + ot("_set_bgpal\t"); + + outconst(); + if (outcomma()) return; + + if (outnameunderline()) return; + + if (!match(",")) { + outstr(",#"); + outdec(1); + } + else { + outbyte(','); + outconst(); + } + + nl(); + needbrack(")"); +} + +void doset_sprpalstatement (void) +{ + /* syntax is + number of the first palette to alter : integer + name of the data for loading palettes : identifier + [ number of palette to load : integer ] + if last argument is missing, 1 is assumed + */ + + flush_ins(); /* David, optimize.c related */ + ot("_set_sprpal\t"); + + outconst(); + if (outcomma()) return; + + if (outnameunderline()) return; + + if (!match(",")) { + outstr(",#"); + outdec(1); + } + else { + outbyte(','); + outconst(); + } + + nl(); + needbrack(")"); +} + + +void doload_spritesstatement (void) +{ + /* syntax is + offset in vram to load data at : integer + name of the data to transfert : identifier + number of sprites (of size 32x64) to load : integer + */ + flush_ins(); /* David, optimize.c related */ + ot("load_sprites\t"); + + outconst(); + if (outcomma()) return; + + if (outnameunderline()) return; + + if (!match(",")) { + outstr(",#"); + outdec(1); + } + else { + outbyte(','); + outconst(); + } + + nl(); + needbrack(")"); +} + +void doload_backgroundstatement (void) +{ + /* syntax is + name of the beginning of the data pattern : identifier + name of the 16 palettes : identifier + name of the bat : identifier + width (in tiles [8x8] ) : integer + height (in tiles [8x8] ) : integer + */ + + flush_ins(); /* David, optimize.c related */ + ot("_load_background\t"); + + if (outnameunderline()) return; + + if (outcomma()) return; + + if (outnameunderline()) return; + + if (outcomma()) return; + + if (outnameunderline()) return; + + if (outcomma()) return; + + if (outconst()) return; + + if (outcomma()) return; + + if (outconst()) return; + + nl(); + needbrack(")"); +} + +void do_asm_func (intptr_t type) +{ + /* syntax is + name of the data : identifier + */ + char n[NAMESIZE]; + char *ptr; + + /* get identifier */ + if (!symname(n)) { + error("invalid identifier"); + kill(); + return; + } + + /* close function */ + needbrack(")"); + + /* duplicate identifier */ + ptr = new_string(1, n); + + /* gen code */ + if (ptr) + out_ins(I_LDWI, type, (intptr_t)ptr); + else + error("out of memory"); +} + +char *new_string (intptr_t und, char *a) +{ + intptr_t len; + intptr_t tmp; + + if (a == NULL) + return (NULL); + + len = strlen(a); + tmp = str_idx; + if ((len + str_idx) > 0xFFF0) + return (NULL); + + if (und) + str_buf[str_idx++] = '_'; + strcpy(&str_buf[str_idx], a); + str_idx += len; + str_buf[str_idx++] = '\0'; + return (&str_buf[tmp]); +} + +void do_inc_ex (intptr_t type) +{ + intptr_t end; + intptr_t i; + intptr_t j; + intptr_t num; + int nb_tile; + char label[NAMESIZE]; + char label2[NAMESIZE]; + char str[NAMESIZE + 32]; + + struct { + char fname[FILENAMESIZE]; + intptr_t arg[5]; + } tiles[16]; + + if (!match("(")) { + error("missing '('"); + kill(); + return; + } + + readstr(); /* read the label name */ + strcpy(label, litq2); + strcpy(label2, litq2); + strcpy(str, "__data__"); + strcat(label2, str); + addglb(label2, ARRAY, CINT, 0, EXTERN, 0); + addglb(label, ARRAY, CINT, 0, EXTERN, 0); + + if (!match(",")) { + error("comma missing"); + kill(); + return; + } + + end = 0; + num = 0; + nb_tile = 0; + while (!end) { + if (match("\\")) {}; + if (!readqstr()) { + error("not a file name"); + kill(); + return; + } + if (!match(",")) { + error("comma missing"); + kill(); + return; + } + strcpy(tiles[num].fname, litq2); + + for (i = 0; i < 5; i++) { + if (match("\\")) {}; + if (!number(&tiles[num].arg[i])) { + error("not a number"); + kill(); + return; + } + if (match(")")) { + if (i == 4) { + kill(); + end = 1; + break; + } + else { + error("arg missing"); + kill(); + return; + } + } + if (!match(",")) { + error("comma missing"); + kill(); + return; + } + while ((ch() == ' ') || (ch() == '\t')) + gch(); + if (ch() == '\0') { + error("arg missing"); + kill(); + return; + } + } + nb_tile += tiles[num].arg[2] * tiles[num].arg[3]; + num++; + if (num == 16) { + if (!end) { + error("too many args (max 16 files)"); + kill(); + return; + } + } + } + + /* create const array to hold extra infos */ + new_const(); + const_val[const_val_idx++] = const_data_idx; /* number of tile */ + sprintf(str, "%i", nb_tile); + add_buffer(str, '(', 1); + const_data[const_data_idx++] = '\0'; + const_val[const_val_idx++] = const_data_idx; /* tile size */ + sprintf(str, "%i", (int)type); + add_buffer(str, '(', 1); + const_data[const_data_idx++] = '\0'; + const_val[const_val_idx++] = const_data_idx; /* tile bank */ + sprintf(str, "BANK(_%s)", label2); + add_buffer(str, '(', 1); + const_data[const_data_idx++] = '\0'; + const_val[const_val_idx++] = const_data_idx; /* tile addr */ + sprintf(str, " _%s", label2); + add_buffer(str, '(', 1); + const_data[const_data_idx++] = '\0'; + const_val[const_val_idx++] = -(litptr + 1024); /* pal idx table addr */ + add_const(CINT); + + /* create pal idx table */ + for (i = 0; i < num; i++) { + j = tiles[i].arg[2] * tiles[i].arg[3]; + while (j) { + j--; + if (litptr < LITMAX) + litq[litptr++] = (tiles[i].arg[4] << 4); + } + } + + /* dump incchr/tile cmds */ + ol(".data"); + prefix(); + outstr(label2); + outstr(":\n"); + for (i = 0; i < num; i++) { + if (type == 8) + ot(".incchr \""); + else + ot(".inctile \""); + outstr(tiles[i].fname); + outstr("\""); + for (j = 0; j < 4; j++) { + outstr(","); + outdec(tiles[i].arg[j]); + } + nl(); + } + ol(".code"); + kill(); +} diff --git a/src/huc/pseudo.h b/src/huc/pseudo.h new file mode 100644 index 00000000..144d0af9 --- /dev/null +++ b/src/huc/pseudo.h @@ -0,0 +1,20 @@ +/* + * pseudo.h + */ + +#ifndef _PSEUDO_H +#define _PSEUDO_H + +void dopsdinc (void); +void dopsddef (void); +intptr_t outcomma (void); +intptr_t outnameunderline (void); +intptr_t outconst (void); +void doset_bgpalstatement (void); +void doset_sprpalstatement (void); +void doload_spritesstatement (void); +void doload_backgroundstatement (void); +void do_asm_func (intptr_t type); +char *new_string (intptr_t und, char *a); + +#endif diff --git a/src/huc/stmt.c b/src/huc/stmt.c new file mode 100644 index 00000000..a3fc0d22 --- /dev/null +++ b/src/huc/stmt.c @@ -0,0 +1,586 @@ +/* File stmt.c: 2.1 (83/03/20,16:02:17) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "code.h" +#include "enum.h" +#include "error.h" +#include "expr.h" +#include "gen.h" +#include "io.h" +#include "lex.h" +#include "preproc.h" +#include "primary.h" +#include "stmt.h" +#include "sym.h" +#include "while.h" +#include "struct.h" +#include "optimize.h" + +/* + * statement parser + * + * called whenever syntax requires a statement. this routine + * performs that statement and returns a number telling which one + * + * 'func' is true if we require a "function_statement", which + * must be compound, and must contain "statement_list" (even if + * "declaration_list" is omitted) + */ +intptr_t statement (intptr_t func) +{ + if ((ch() == 0) & feof(input)) + return (0); + + lastst = 0; + if (func) { + top_level_stkp = 1; /* uninitialized */ + if (match("{")) { + compound(YES); + return (lastst); + } + else + error("function requires compound statement"); + } + if (match("{")) + compound(NO); + else + stst(); + return (lastst); +} + +/* + * declaration + */ +intptr_t stdecl (void) +{ + if (amatch("register", 8)) + doldcls(DEFAUTO); + else if (amatch("auto", 4)) + doldcls(DEFAUTO); + else if (amatch("static", 6)) + doldcls(LSTATIC); + else if (doldcls(AUTO)) ; + else + return (NO); + + return (YES); +} + +intptr_t doldcls (intptr_t stclass) +{ + struct type t; + + blanks(); + /* we don't do optimizations that would require "volatile" */ + if (match_type(&t, NO, YES)) { + if (t.type == CSTRUCT && t.otag == -1) + t.otag = define_struct(t.sname, stclass, !!(t.flags & F_STRUCT)); + if (t.type == CVOID) { + blanks(); + if (ch() != '*') { + error("illegal type \"void\""); + junk(); + return (0); + } + } + if (t.type == CENUM) { + if (t.otag == -1) + t.otag = define_enum(t.sname, stclass); + t.type = enum_types[t.otag].base; + } + declloc(t.type, stclass, t.otag); + } + else + return (0); + + ns(); + return (1); +} + + +/* + * non-declaration statement + */ +void stst (void) +{ + if (amatch("if", 2)) { + doif(); + lastst = STIF; + } + else if (amatch("while", 5)) { + dowhile(); + lastst = STWHILE; + } + else if (amatch("switch", 6)) { + doswitch(); + lastst = STSWITCH; + } + else if (amatch("do", 2)) { + dodo(); + ns(); + lastst = STDO; + } + else if (amatch("for", 3)) { + dofor(); + lastst = STFOR; + } + else if (amatch("return", 6)) { + doreturn(); + ns(); + lastst = STRETURN; + } + else if (amatch("break", 5)) { + dobreak(); + ns(); + lastst = STBREAK; + } + else if (amatch("continue", 8)) { + docont(); + ns(); + lastst = STCONT; + } + else if (amatch("goto", 4)) { + dogoto(); + ns(); + lastst = STGOTO; + } + else if (match(";")) + ; + else if (amatch("case", 4)) { + docase(); + lastst = statement(NO); + } + else if (amatch("default", 7)) { + dodefault(); + lastst = statement(NO); + } + else if (match("#asm")) { + doasm(); + lastst = STASM; + } + else if (match("{")) + compound(NO); + else { + int slptr = lptr; + char lbl[NAMESIZE]; + if (symname(lbl) && ch() == ':') { + gch(); + dolabel(lbl); + lastst = statement(NO); + } + else { + lptr = slptr; + expression(YES); + ns(); + lastst = STEXP; + } + } +} + +/* + * compound statement + * + * allow any number of statements to fall between "{" and "}" + * + * 'func' is true if we are in a "function_statement", which + * must contain "statement_list" + */ +void compound (intptr_t func) +{ + intptr_t decls; + + decls = YES; + ncmp++; + /* remember stack pointer before entering the first compound + statement inside a function */ + if (!func && top_level_stkp == 1 && !norecurse) + top_level_stkp = stkp; + while (!match("}")) { + if (feof(input)) + return; + + if (decls) { + if (!stdecl()) { + decls = NO; + gtext(); + } + } + else + stst(); + } + ncmp--; +} + +/* + * "if" statement + */ +void doif (void) +{ + intptr_t fstkp, flab1, flab2; + SYMBOL *flev; + + flev = locptr; + fstkp = stkp; + flab1 = getlabel(); + test(flab1, FALSE); + statement(NO); + stkp = modstk(fstkp); + locptr = flev; + if (!amatch("else", 4)) { + gnlabel(flab1); + return; + } + jump(flab2 = getlabel()); + gnlabel(flab1); + statement(NO); + stkp = modstk(fstkp); + locptr = flev; + gnlabel(flab2); +} + +/* + * "while" statement + */ +void dowhile (void) +{ + intptr_t ws[7]; + + ws[WSSYM] = (intptr_t)locptr; + ws[WSSP] = stkp; + ws[WSTYP] = WSWHILE; + ws[WSTEST] = getlabel(); + ws[WSEXIT] = getlabel(); + addwhile(ws); + gnlabel(ws[WSTEST]); + test(ws[WSEXIT], FALSE); + statement(NO); + jump(ws[WSTEST]); + gnlabel(ws[WSEXIT]); + locptr = (SYMBOL *)ws[WSSYM]; + stkp = modstk(ws[WSSP]); + delwhile(); +} + +/* + * "do" statement + */ +void dodo (void) +{ + intptr_t ws[7]; + + ws[WSSYM] = (intptr_t)locptr; + ws[WSSP] = stkp; + ws[WSTYP] = WSDO; + ws[WSBODY] = getlabel(); + ws[WSTEST] = getlabel(); + ws[WSEXIT] = getlabel(); + addwhile(ws); + gnlabel(ws[WSBODY]); + statement(NO); + if (!match("while")) { + error("missing while"); + return; + } + gnlabel(ws[WSTEST]); + test(ws[WSBODY], TRUE); + gnlabel(ws[WSEXIT]); + locptr = (SYMBOL *)ws[WSSYM]; + stkp = modstk(ws[WSSP]); + delwhile(); +} + +/* + * "for" statement + */ +void dofor (void) +{ + intptr_t ws[7], + *pws; + + ws[WSSYM] = (intptr_t)locptr; + ws[WSSP] = stkp; + ws[WSTYP] = WSFOR; + ws[WSTEST] = getlabel(); + ws[WSINCR] = getlabel(); + ws[WSBODY] = getlabel(); + ws[WSEXIT] = getlabel(); + addwhile(ws); + pws = readwhile(); + needbrack("("); + if (!match(";")) { + expression(YES); + ns(); + } + gnlabel(pws[WSTEST]); + if (!match(";")) { + expression(YES); + testjump(pws[WSBODY], TRUE); + jump(pws[WSEXIT]); + ns(); + } + else + pws[WSTEST] = pws[WSBODY]; + gnlabel(pws[WSINCR]); + if (!match(")")) { + expression(YES); + needbrack(")"); + jump(pws[WSTEST]); + } + else + pws[WSINCR] = pws[WSTEST]; + gnlabel(pws[WSBODY]); + statement(NO); + stkp = modstk(pws[WSSP]); + jump(pws[WSINCR]); + gnlabel(pws[WSEXIT]); + locptr = (SYMBOL *)pws[WSSYM]; + delwhile(); +} + +/* + * "switch" statement + */ +void doswitch (void) +{ + intptr_t ws[7]; + intptr_t *ptr; + + ws[WSSYM] = (intptr_t)locptr; + ws[WSSP] = stkp; + ws[WSTYP] = WSSWITCH; + ws[WSCASEP] = swstp; + ws[WSTAB] = getlabel(); + ws[WSDEF] = ws[WSEXIT] = getlabel(); + addwhile(ws); + immed(T_LABEL, ws[WSTAB]); + gpush(); + needbrack("("); + expression(YES); + needbrack(")"); + stkp = stkp + INTSIZE; /* '?case' will adjust the stack */ + gjcase(); + statement(NO); + ptr = readswitch(); + jump(ptr[WSEXIT]); + dumpsw(ptr); + gnlabel(ptr[WSEXIT]); + locptr = (SYMBOL *)ptr[WSSYM]; + stkp = modstk(ptr[WSSP]); + swstp = ptr[WSCASEP]; + delwhile(); +} + +/* + * "case" label + */ +void docase (void) +{ + intptr_t val; + char n[NAMESIZE]; + + val = 0; + if (readswitch()) { + if (!number(&val)) + if (!pstr(&val)) + if (!(symname(n) && find_enum(n, &val))) + error("bad case label"); + addcase(val); + if (!match(":")) + error("missing colon"); + } + else + error("no active switch"); +} + +/* + * "default" label + */ +void dodefault (void) +{ + intptr_t *ptr, + lab; + + ptr = readswitch(); + if (ptr) { + ptr[WSDEF] = lab = getlabel(); + gnlabel(lab); + if (!match(":")) + error("missing colon"); + } + else + error("no active switch"); +} + +/* + * "return" statement + */ +void doreturn (void) +{ + /* Jumping to fexitlab will clean up the top-level stack, + but we may have added additional stack variables in + an inner compound statement, and if so we have to + clean those up as well. */ + if (top_level_stkp != 1 && stkp != top_level_stkp) + modstk(top_level_stkp); + + if (endst() == 0) + expression(YES); + + jump(fexitlab); +} + +/* + * "break" statement + */ +void dobreak (void) +{ + intptr_t *ptr; + + if ((ptr = readwhile()) == 0) + return; + + modstk(ptr[WSSP]); + jump(ptr[WSEXIT]); +} + +/* + * "continue" statement + */ +void docont (void) +{ + intptr_t *ptr; + + if ((ptr = findwhile()) == 0) + return; + + modstk(ptr[WSSP]); + if (ptr[WSTYP] == WSFOR) + jump(ptr[WSINCR]); + else + jump(ptr[WSTEST]); +} + +void dolabel (char *name) +{ + int i; + + for (i = 0; i < clabel_ptr; i++) { + if (!strcmp(clabels[i].name, name)) { + /* This label has been goto'd to before. + We have to create a stack pointer offset EQU + that describes the stack pointer difference from + the goto to here. */ + sprintf(name, "LL%d_stkp", clabels[i].label); + /* XXX: memleak */ + out_ins_ex(I_DEF, T_LITERAL, (intptr_t)strdup(name), + T_VALUE, stkp - clabels[i].stkp); + /* From now on, clabel::stkp contains the relative + stack pointer at the location of the label. */ + clabels[i].stkp = stkp; + gnlabel(clabels[i].label); + printf("old label %s stkp %ld\n", clabels[i].name, (long) stkp); + return; + } + } + /* This label has not been referenced before, we need to create a + new entry. */ + clabels = realloc(clabels, (clabel_ptr + 1) * sizeof(struct clabel)); + strcpy(clabels[clabel_ptr].name, name); + clabels[clabel_ptr].stkp = stkp; + clabels[clabel_ptr].label = getlabel(); + printf("new label %s id %d stkp %ld\n", name, clabels[clabel_ptr].label, (long) stkp); + gnlabel(clabels[clabel_ptr].label); + clabel_ptr++; +} + +void dogoto (void) +{ + int i; + char sname[NAMESIZE]; + + if (!symname(sname)) { + error("invalid label name"); + return; + } + for (i = 0; i < clabel_ptr; i++) { + if (!strcmp(clabels[i].name, sname)) { + /* This label has already been defined. All we have + to do is to adjust the stack pointer and jump. */ + printf("goto found label %s id %d stkp %d\n", sname, clabels[i].label, clabels[i].stkp); + modstk(clabels[i].stkp); + jump(clabels[i].label); + return; + } + } + + /* This label has not been defined yet. We have to create a new + entry in the label array. We also don't know yet what the relative + SP will be at the label, so we have to emit a stack pointer + operation with a symbolic operand that will be defined to the + appropriate value at the label definition. */ + clabels = realloc(clabels, (i + 1) * sizeof(*clabels)); + strcpy(clabels[i].name, sname); + /* Save our relative SP in the label entry; this will be corrected + to the label's relative SP at the time of definition. */ + clabels[i].stkp = stkp; + clabels[i].label = getlabel(); + sprintf(sname, "LL%d_stkp", clabels[i].label); + /* XXX: memleak */ + out_ins(I_ADDMI, T_LITERAL, (intptr_t)strdup(sname)); + jump(clabels[i].label); + clabel_ptr++; +} + + +/* + * dump switch table + */ +void dumpsw (intptr_t *ws) +/*intptr_t ws[];*/ +{ + intptr_t i, j; + +// gdata (); + gnlabel(ws[WSTAB]); + flush_ins(); + if (ws[WSCASEP] != swstp) { + j = ws[WSCASEP]; + while (j < swstp) { + defword(); + i = 4; + while (i--) { + outlabel(swstlab[j]); + outbyte(','); + outdec(swstcase[j++]); + if ((i == 0) | (j >= swstp)) { + nl(); + break; + } + outbyte(','); + } + } + } + defword(); + outstr("0,"); + outlabel(ws[WSDEF]); + nl(); +// gtext (); +} + +void test (intptr_t label, intptr_t ft) +/* intptr_t label, + ft; */ +{ + needbrack("("); + expression(YES); + needbrack(")"); + testjump(label, ft); +} diff --git a/src/huc/stmt.h b/src/huc/stmt.h new file mode 100644 index 00000000..d95b8e92 --- /dev/null +++ b/src/huc/stmt.h @@ -0,0 +1,30 @@ +/* File stmt.c: 2.1 (83/03/20,16:02:17) */ +/*% cc -O -c % + * + */ + + +#ifndef _STMT_H +#define _STMT_H + +intptr_t statement (intptr_t func); +intptr_t stdecl (void); +intptr_t doldcls (intptr_t stclass); +void stst (void); +void compound (intptr_t func); +void doif (void); +void dowhile (void); +void dodo (void); +void dofor (void); +void doswitch (void); +void docase (void); +void dodefault (void); +void doreturn (void); +void dobreak (void); +void docont (void); +void dolabel (char *name); +void dogoto (void); +void dumpsw (intptr_t *ws); +void test (intptr_t label, intptr_t ft); + +#endif diff --git a/src/huc/struct.c b/src/huc/struct.c new file mode 100644 index 00000000..a7b1ba26 --- /dev/null +++ b/src/huc/struct.c @@ -0,0 +1,116 @@ +/* + * File struct.c: (12/12/12,21:31:33) + */ + +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "lex.h" +#include "error.h" +#include "main.h" + +/** + * look up a tag in tag table by name + * @param sname + * @return index + */ +int find_tag (char *sname) +{ + int index; + + index = 0; + while (index < tag_table_index) { + if (astreq(sname, tag_table[index].name, NAMEMAX)) + return (index); + + ++index; + } + return (-1); +} + +/** + * determine if 'sname' is a member of the struct with tag 'tag' + * @param tag + * @param sname + * @return pointer to member symbol if it is, else 0 + */ +SYMBOL *find_member (TAG_SYMBOL *tag, char *sname) +{ + int member_idx; + + member_idx = tag->member_idx; + + while (member_idx < tag->member_idx + tag->number_of_members) { + if (strcmp(member_table[member_idx].name, sname) == 0) + return (&member_table[member_idx]); + + ++member_idx; + } + return (0); +} + +/** + * add new structure member to table + * @param sname + * @param identity - variable, array, pointer, function + * @param typ + * @param offset + * @param storage + * @return + */ +void add_member (char *sname, char identity, char type, int offset, int storage_class, int otag, int ptr_order) +{ + char *buffer_ptr; + SYMBOL *symbol; + + if (member_table_index >= NUMMEMB) { + error("symbol table overflow"); + return; + } + symbol = &member_table[member_table_index]; + buffer_ptr = symbol->name; + while (an(*buffer_ptr++ = *sname++)) ; + symbol->ident = identity; + symbol->type = type; + symbol->storage = storage_class; + symbol->offset = offset; + symbol->ptr_order = ptr_order; + if (type == CSTRUCT) + symbol->tagidx = otag; + + member_table_index++; +} + +int define_struct (char *sname, int storage, int is_struct) +{ + TAG_SYMBOL *symbol; + char *buffer_ptr; + int tti; + + // tag_table_index++; + if (tag_table_index >= NUMTAG) { + error("struct table overflow"); + return (0); + } + tti = tag_table_index++; + symbol = &tag_table[tti]; + buffer_ptr = symbol->name; + while (an(*buffer_ptr++ = *sname++)) ; + symbol->size = 0; + symbol->member_idx = member_table_index; + + needbrack("{"); + while (!match("}")) { + if (!dodcls(storage, &tag_table[tti], is_struct)) + break; + /* We need to keep number_of_members up-to-date to make sure that + find_member() works so we can catch duplicate member names. */ + symbol->number_of_members = member_table_index - symbol->member_idx; + } + ; + /* XXX: still necessary? */ + symbol->number_of_members = member_table_index - symbol->member_idx; + return (tti); +} diff --git a/src/huc/struct.h b/src/huc/struct.h new file mode 100644 index 00000000..e8e51dec --- /dev/null +++ b/src/huc/struct.h @@ -0,0 +1,3 @@ +int find_tag (char *sname); +int define_struct (char *sname, int storage, int is_struct); +void add_member (char *sname, char identity, char type, int offset, int storage_class, int otag, int ptr_order); diff --git a/src/huc/sym.c b/src/huc/sym.c new file mode 100644 index 00000000..425cbe60 --- /dev/null +++ b/src/huc/sym.c @@ -0,0 +1,600 @@ +/* File sym.c: 2.1 (83/03/20,16:02:19) */ +/*% cc -O -c % + * + */ + +#include +#include +#include +#include +#include "defs.h" +#include "data.h" +#include "code.h" +#include "const.h" +#include "error.h" +#include "gen.h" +#include "initials.h" +#include "io.h" +#include "lex.h" +#include "primary.h" +#include "pragma.h" +#include "sym.h" +#include "function.h" +#include "struct.h" + +/** + * evaluate one initializer, add data to table + * @param symbol_name + * @param type + * @param identity + * @param dim + * @param tag + * @return + */ +static int init (char *symbol_name, int type, int identity, int *dim, TAG_SYMBOL *tag) +{ + intptr_t value; + int number_of_chars; + + if (identity == POINTER) { + error("initializing non-const pointers unimplemented"); + kill(); + return (0); + } + + if (qstr(&value)) { + if ((identity == VARIABLE) || (type != CCHAR && type != CUCHAR)) + error("found string: must assign to char pointer or array"); /* XXX: make this a warning? */ + if (identity == POINTER) { + /* unimplemented */ + printf("initptr %s value %ld\n", symbol_name, (long) value); + abort(); + // add_data_initials(symbol_name, CUINT, value, tag); + } + else { + number_of_chars = litptr - value; + *dim = *dim - number_of_chars; + while (number_of_chars > 0) { + add_data_initials(symbol_name, CCHAR, litq[value++], tag); + number_of_chars = number_of_chars - 1; + } + } + } + else if (number(&value)) { + add_data_initials(symbol_name, CINT, value, tag); + *dim = *dim - 1; + } + else if (qstr(&value)) { + add_data_initials(symbol_name, CCHAR, value, tag); + *dim = *dim - 1; + } + else + return (0); + + return (1); +} + +/** + * initialise structure + * @param tag + */ +void struct_init (TAG_SYMBOL *tag, char *symbol_name) +{ + int dim; + int member_idx; + + member_idx = tag->member_idx; + while (member_idx < tag->member_idx + tag->number_of_members) { + init(symbol_name, member_table[tag->member_idx + member_idx].type, + member_table[tag->member_idx + member_idx].ident, &dim, tag); + ++member_idx; + if ((match(",") == 0) && (member_idx != (tag->member_idx + tag->number_of_members))) { + error("struct initialisaton out of data"); + break; + } + } +} + +/** + * initialize global objects + * @param symbol_name + * @param type char or integer or struct + * @param identity + * @param dim + * @return 1 if variable is initialized + */ +int initials (char *symbol_name, int type, int identity, int dim, int otag) +{ + int dim_unknown = 0; + + if (dim == 0) // allow for xx[] = {..}; declaration + dim_unknown = 1; + if (match("=")) { + if (type != CCHAR && type != CUCHAR && type != CINT && type != CUINT && type != CSTRUCT) + error("unsupported storage size"); + // an array or struct + if (match("{")) { + // aggregate initialiser + if ((identity == POINTER || identity == VARIABLE) && type == CSTRUCT) { + // aggregate is structure or pointer to structure + dim = 0; + struct_init(&tag_table[otag], symbol_name); + } + else { + while ((dim > 0) || dim_unknown) { + if (identity == ARRAY && type == CSTRUCT) { + // array of struct + needbrack("{"); + struct_init(&tag_table[otag], symbol_name); + --dim; + needbrack("}"); + } + else { + if (init(symbol_name, type, identity, &dim, 0)) + dim_unknown++; + } + if (match(",") == 0) + break; + } + } + needbrack("}"); + // single constant + } + else + init(symbol_name, type, identity, &dim, 0); + } + return (identity); +} + + +/* + * declare a static variable + * + * David, added support for const arrays and improved error detection + * + */ +intptr_t declglb (intptr_t typ, intptr_t stor, TAG_SYMBOL *mtag, int otag, int is_struct) +{ + intptr_t k, id; + char sname[NAMESIZE]; + int ptr_order; + SYMBOL *s; + + for (;;) { + for (;;) { + ptr_order = 0; + if (endst()) + return (0); + + k = 1; + id = VARIABLE; + while (match("*")) { + id = POINTER; + ptr_order++; + } + if (amatch("__fastcall", 10)) { + newfunc(NULL, ptr_order, typ, otag, 1); + return (2); + } + if (!symname(sname)) + illname(); + if (match("(")) { + newfunc(sname, ptr_order, typ, otag, 0); + return (2); + } + if ((s = findglb(sname))) { + if (s->storage != EXTERN && !mtag) + multidef(sname); + } + if (mtag && find_member(mtag, sname)) + multidef(sname); + if (match("[")) { + if (stor == CONST) + k = array_initializer(typ, id, stor); + else + k = needsub(); + if (k == -1) + return (1); + + /* XXX: This doesn't really beintptr_t here, but I + can't think of a better place right now. */ + if (id == POINTER && (typ == CCHAR || typ == CUCHAR || typ == CVOID)) + k *= INTSIZE; + if (k || (stor == EXTERN)) + id = ARRAY; + else { + if (stor == CONST) { + error("empty const array"); + id = ARRAY; + } + else if (id == POINTER) + id = ARRAY; + else { + id = POINTER; + ptr_order++; + } + } + } + else { + if (stor == CONST) { + /* stor = PUBLIC; XXX: What is this for? */ + scalar_initializer(typ, id, stor); + } + } + if (mtag == 0) { + if (typ == CSTRUCT) { + if (id == VARIABLE) + k = tag_table[otag].size; + else if (id == POINTER) + k = INTSIZE; + else if (id == ARRAY) + k *= tag_table[otag].size; + } + if (stor != CONST) { + id = initials(sname, typ, id, k, otag); + SYMBOL *c = addglb(sname, id, typ, k, stor, s); + if (typ == CSTRUCT) + c->tagidx = otag; + c->ptr_order = ptr_order; + } + else { + SYMBOL *c = addglb(sname, id, typ, k, CONST, s); + if (c) { + add_const(typ); + if (typ == CSTRUCT) + c->tagidx = otag; + } + c->ptr_order = ptr_order; + } + } + else if (is_struct) { + add_member(sname, id, typ, mtag->size, stor, otag, ptr_order); + if (id == POINTER) + typ = CUINT; + scale_const(typ, otag, &k); + mtag->size += k; + } + else { + add_member(sname, id, typ, 0, stor, otag, ptr_order); + if (id == POINTER) + typ = CUINT; + scale_const(typ, otag, &k); + if (mtag->size < k) + mtag->size = k; + } + break; + } + if (endst()) + return (0); + + if (!match(",")) { + error("syntax error"); + return (1); + } + } + return (0); +} + +/* + * declare local variables + * + * works just like "declglb", but modifies machine stack and adds + * symbol table entry with appropriate stack offset to find it again + * + * zeo : added "totalk" stuff and global stack modification (00/04/12) + */ +void declloc (intptr_t typ, intptr_t stclass, int otag) +{ + intptr_t k = 0, j; + intptr_t elements = 0; + char sname[NAMESIZE]; + intptr_t totalk = 0; + + for (;;) { + for (;;) { + int ptr_order = 0; + if (endst()) { + if (!norecurse) + stkp = modstk(stkp - totalk); + return; + } + j = VARIABLE; + while (match("*")) { + j = POINTER; + ptr_order++; + } + if (!symname(sname)) + illname(); + if (findloc(sname)) + multidef(sname); + if (match("[")) { + elements = k = needsub(); + if (k) { + if (typ == CINT || typ == CUINT || j == POINTER) + k = k * INTSIZE; + else if (typ == CSTRUCT) + k *= tag_table[otag].size; + j = ARRAY; + } + else { + j = POINTER; + ptr_order++; + k = INTSIZE; + elements = 1; + } + } + else { + elements = 1; + if ((typ == CCHAR || typ == CUCHAR) & (j != POINTER)) + k = 1; + else if (typ == CSTRUCT) { + if (j == VARIABLE) + k = tag_table[otag].size; + else if (j == POINTER) + k = INTSIZE; + } + else + k = INTSIZE; + } + if (stclass == LSTATIC) { + /* Local statics are identified in two + different ways: The human-readable + identifier as given in the source text, + and the internal label that is used in + the assembly output. + + The initializer code wants the label, and + it is also used to add a global to make + sure the right amount of space is + reserved in .bss and the initialized data + is dumped eventually. + + addloc(), OTOH, wants the identifier so + it can be found when referenced further + down in the source text. */ + char lsname[NAMESIZE]; + int label = getlabel(); + sprintf(lsname, "LL%d", label); + + j = initials(lsname, typ, j, k, otag); + /* NB: addglb() expects the number of + elements, not a byte size. Unless, of + course, we have a CSTRUCT. *sigh* */ + if (typ == CSTRUCT) + addglb(lsname, j, typ, k, LSTATIC, 0); + else + addglb(lsname, j, typ, elements, LSTATIC, 0); + + SYMBOL *c = addloc(sname, j, typ, label, LSTATIC, k); + if (typ == CSTRUCT) + c->tagidx = otag; + c->ptr_order = ptr_order; + } + else { + SYMBOL *c; +// k = galign(k); + totalk += k; + // stkp = modstk (stkp - k); + // addloc (sname, j, typ, stkp, AUTO); + if (!norecurse) + c = addloc(sname, j, typ, stkp - totalk, AUTO, k); + else + c = addloc(sname, j, typ, locals_ptr - totalk, AUTO, k); + if (typ == CSTRUCT) + c->tagidx = otag; + c->ptr_order = ptr_order; + } + break; + } + if (match("=")) { + intptr_t num[1]; + if (!norecurse) + stkp = modstk(stkp - totalk); + else + locals_ptr -= totalk; + totalk -= k; + if (const_expr(num, ",", ";")) { + /* XXX: minor memory leak */ + char *locsym = calloc(1,sizeof(SYMBOL)); + gtext(); + if (k == 1) { + if (norecurse) { + sprintf(locsym, "_%s_lend-%d", current_fn, (int) -locals_ptr); + out_ins_ex(I_STBI, T_SYMBOL, (intptr_t)locsym, T_VALUE, *num); + } + else + out_ins_ex(X_STBI_S, T_VALUE, 0, T_VALUE, *num); + } + else if (k == 2) { + if (norecurse) { + sprintf(locsym, "_%s_lend-%d", current_fn, (int) -locals_ptr); + out_ins_ex(I_STWI, T_SYMBOL, (intptr_t)locsym, T_VALUE, *num); + } + else + out_ins_ex(X_STWI_S, T_VALUE, 0, T_VALUE, *num); + } + else + error("complex type initialization not implemented"); + } + else + error("cannot parse initializer"); + } + if (!match(",")) { + if (!norecurse) + stkp = modstk(stkp - totalk); + else + locals_ptr -= totalk; + return; + } + } +} + +/* + * get required array size + */ +intptr_t needsub (void) +{ + intptr_t num[1]; + + if (match("]")) + return (0); + + if (!const_expr(num, "]", NULL)) { + error("must be constant"); + num[0] = 1; + } + if (!match("]")) + error("internal error"); + if (num[0] < 0) { + error("negative size illegal"); + num[0] = (-num[0]); + } + return (num[0]); +} + +SYMBOL *findglb (char *sname) +{ + SYMBOL *ptr; + + ptr = STARTGLB; + while (ptr != glbptr) { + if (astreq(sname, ptr->name, NAMEMAX)) + return (ptr); + + ptr++; + } + return (NULL); +} + +SYMBOL *findloc (char *sname) +{ + SYMBOL *ptr; + + ptr = locptr; + while (ptr != STARTLOC) { + ptr--; + if (astreq(sname, ptr->name, NAMEMAX)) + return (ptr); + } + return (NULL); +} + +SYMBOL *addglb (char *sname, char id, char typ, intptr_t value, intptr_t stor, SYMBOL *replace) +{ + char *ptr; + + if (!replace) { + cptr = findglb(sname); + if (cptr) + return (cptr); + + if (glbptr >= ENDGLB) { + error("global symbol table overflow"); + return (NULL); + } + cptr = glbptr; + glbptr++; + } + else + cptr = replace; + + ptr = cptr->name; + while (an(*ptr++ = *sname++)) ; + cptr->ident = id; + cptr->type = typ; + cptr->storage = stor; + cptr->offset = value; + cptr->size = value; + cptr->far = 0; + if (id == FUNCTION) + cptr->size = 0; + else if (id == POINTER) + cptr->size = INTSIZE; + else if (typ == CINT || typ == CUINT) + cptr->size *= 2; + return (cptr); +} + +SYMBOL *addglb_far (char *sname, char typ) +{ + SYMBOL *ptr; + + ptr = addglb(sname, ARRAY, typ, 0, EXTERN, 0); + if (ptr) + ptr->far = 1; + return (ptr); +} + + +SYMBOL *addloc (char *sname, char id, char typ, intptr_t value, intptr_t stclass, intptr_t size) +{ + char *ptr; + + cptr = findloc(sname); + if (cptr) + return (cptr); + + if (locptr >= ENDLOC) { + error("local symbol table overflow"); + return (NULL); + } + cptr = locptr; + ptr = locptr->name; + while (an(*ptr++ = *sname++)) ; + cptr->ident = id; + cptr->type = typ; + cptr->storage = stclass; + cptr->offset = value; + cptr->size = size; + locptr++; + return (cptr); +} + +/* + * test if next input string is legal symbol name + * + */ +intptr_t symname (char *sname) +{ + intptr_t k; + +/* char c; */ + + blanks(); + if (!alpha(ch())) + return (0); + + k = 0; + while (an(ch())) + sname[k++] = gch(); + sname[k] = 0; + return (1); +} + +void illname (void) +{ + error("illegal symbol name"); +} + +void multidef (char *sname) +{ + error("already defined"); + comment(); + outstr(sname); + nl(); +} + +intptr_t glint (SYMBOL *sym) +{ + return (sym->offset); +} + +SYMBOL *copysym (SYMBOL *sym) +{ + SYMBOL *ptr = malloc(sizeof(SYMBOL)); + if (ptr == NULL) + error("out of memory to copy symbol"); + else + memcpy(ptr, sym, sizeof(SYMBOL)); + return (ptr); +} diff --git a/src/huc/sym.h b/src/huc/sym.h new file mode 100644 index 00000000..29ce9f6d --- /dev/null +++ b/src/huc/sym.h @@ -0,0 +1,17 @@ +#ifndef _SYM_H +#define _SYM_H + +intptr_t declglb (intptr_t typ, intptr_t stor, TAG_SYMBOL *mtag, int otag, int is_struct); +void declloc (intptr_t typ, intptr_t stclass, int otag); +intptr_t needsub (void); +SYMBOL *findglb (char *sname); +SYMBOL *findloc (char *sname); +SYMBOL *addglb (char *sname, char id, char typ, intptr_t value, intptr_t stor, SYMBOL *replace); +SYMBOL *addglb_far (char *sname, char typ); +SYMBOL *addloc (char *sname, char id, char typ, intptr_t value, intptr_t stclass, intptr_t size); +intptr_t symname (char *sname); +void illname (void); +void multidef (char *sname); +intptr_t glint (SYMBOL *sym); +SYMBOL *copysym (SYMBOL *sym); +#endif diff --git a/src/huc/uncrustify.cfg b/src/huc/uncrustify.cfg new file mode 100644 index 00000000..302ed1d3 --- /dev/null +++ b/src/huc/uncrustify.cfg @@ -0,0 +1,143 @@ +# +# uncrustify config file for HuC +# +# Copyright (c) 2014, Ulrich Hecht +# All rights reserved. +# See LICENSE for details on use and redistribution. +# + +# +# Attempt to find a consistent style that is as close as possible to the +# existing formatting. In some cases the settings deviate from that rule +# if the option is considered a substantial win; those cases are marked +# as "deliberate". +# +# Options that have no effect on the current codebase, but that are +# desirable when an applicable construct appears in the future are +# marked as "no effect". +# + +indent_with_tabs = 2 # ok (1=indent to level only, 2=indent with tabs) +input_tab_size = 8 # ok (original tab size) +output_tab_size = 8 # ok (new tab size) +indent_columns = output_tab_size # ok + +indent_label = 1 # ok (pos: absolute col, neg: relative column) +indent_cmt_with_tabs = true # ok + +# +# inter-symbol newlines +# + +nl_enum_brace = remove # no effect ("enum {" vs "enum \n {") +nl_union_brace = remove # no effect ("union {" vs "union \n {") +nl_struct_brace = remove # ok ("struct {" vs "struct \n {") +nl_do_brace = remove # ok ("do {" vs "do \n {") +nl_if_brace = remove # ok ("if () {" vs "if () \n {") +nl_for_brace = remove # ok ("for () {" vs "for () \n {") +nl_else_brace = remove # ok ("else {" vs "else \n {") +nl_while_brace = remove # ok ("while () {" vs "while () \n {") +nl_switch_brace = remove # ok ("switch () {" vs "switch () \n {") +nl_brace_while = remove # ok ("} while" vs "} \n while" - cuddle while) +nl_brace_else = add # ok ("} else" vs "} \n else" - cuddle else) +sp_brace_else = force # no effect +sp_else_brace = force # ok +nl_func_var_def_blk = 1 # deliberate +nl_fcall_brace = remove # no effect ("list_for_each() {" vs "list_for_each()\n{") +nl_fdef_brace = add # ok ("int foo() {" vs "int foo()\n{") +nl_after_return = true # deliberate +# nl_before_case = 1 + +nl_after_brace_open = true # deliberate +nl_after_brace_open_cmt = true # deliberate + +nl_func_type_name = remove # ok + +# +# Source code modifications +# + +mod_paren_on_return = add # ok ("return 1;" vs "return (1);") +mod_full_brace_if = remove # ok ("if (a) a--;" vs "if (a) { a--; }") +mod_full_brace_if_chain = false # no effect +mod_full_brace_for = remove # deliberate ("for () a--;" vs "for () { a--; }") +mod_full_brace_do = remove # ok ("do a--; while ();" vs "do { a--; } while ();") +mod_full_brace_while = remove # ok ("while (a) a--;" vs "while (a) { a--; }") +mod_full_brace_nl = 2 # ok (don't remove if more than 2 newlines) + + +# +# inter-character spacing options +# + +sp_return_paren = force # ok ("return (1);" vs "return(1);") +sp_sizeof_paren = remove # ok ("sizeof (int)" vs "sizeof(int)") +sp_before_sparen = force # ok ("if (" vs "if(") +sp_after_sparen = force # ok ("if () {" vs "if (){") +sp_after_cast = remove # ok ("(int) a" vs "(int)a") +sp_inside_braces = remove # ok ("{ 1 }" vs "{1}") +sp_inside_braces_struct = remove # no effect ("{ 1 }" vs "{1}") +sp_inside_braces_enum = remove # no effect ("{ 1 }" vs "{1}") +sp_assign = force # ok +sp_arith = force # ok +sp_bool = force # ok +sp_compare = force # ok +sp_after_comma = force # ok +sp_func_def_paren = force # ok ("int foo (){" vs "int foo(){") +sp_func_call_paren = remove # ok ("foo (" vs "foo(") +sp_func_proto_paren = force # ok ("int foo ();" vs "int foo();") + +sp_after_semi_for_empty = remove # ok + +sp_cmt_cpp_start = add # ok + +# +# Aligning stuff +# + +align_with_tabs = true # no effect (use tabs to align) +align_on_tabstop = false # no effect (align on tabstops) +align_keep_tabs = false # deliberate +align_enum_equ_span = 4 # no effect ('=' in enum definition) +align_nl_cont = false # ok +align_var_def_span = 0 # ok +align_var_def_inline = false # no effect +align_var_def_star_style = 1 # no effect +align_var_def_colon = false # no effect +align_assign_span = 0 # ok +align_struct_init_span = 0 # ok (align stuff in a structure init '= { }') +align_right_cmt_span = 3 # deliberate +align_pp_define_span = 0; # ok +align_pp_define_gap = 2; # no effect + +cmt_star_cont = false # ok + +indent_brace = 0 # ok + +nl_func_paren = remove # ok +nl_func_decl_start = remove # ok +nl_func_decl_empty = remove # ok +nl_func_decl_args = remove # ok +nl_func_decl_end = remove # ok +sp_inside_paren = remove # ok +sp_inside_square = remove # ok +sp_inside_paren_cast = remove # ok +sp_inside_fparen = remove # ok +sp_inside_sparen = remove # ok +sp_paren_paren = remove # ok +sp_before_ptr_star = force # ok +sp_after_ptr_star = remove # ok +sp_between_ptr_star = remove # ok +align_func_params = true # no effect + +align_var_struct_span = 0 # ok + +eat_blanks_after_open_brace = true # deliberate +eat_blanks_before_close_brace = true # deliberate + +pp_indent = remove # ok + +nl_start_of_file = remove # deliberate +nl_end_of_file = force # ok +nl_end_of_file_min = 1 # ok +nl_comment_func_def = 1 # ok diff --git a/src/huc/version.h b/src/huc/version.h new file mode 100644 index 00000000..9673f7b0 --- /dev/null +++ b/src/huc/version.h @@ -0,0 +1,12 @@ +#ifndef HUC_VERSION_H +#define HUC_VERSION_H + +#ifndef GIT_VERSION +# define GIT_VERSION "dummy" +#endif /* !GIT_VERSION */ + +#ifndef GIT_DATE +# define GIT_DATE "1987/10/30" +#endif /* !GIT_DATE */ + +#endif /* HUC_VERSION_H */ diff --git a/src/huc/version.h.in b/src/huc/version.h.in new file mode 100644 index 00000000..a8115c8c --- /dev/null +++ b/src/huc/version.h.in @@ -0,0 +1,12 @@ +#ifndef HUC_VERSION_H +#define HUC_VERSION_H + +#ifndef GIT_VERSION +# define GIT_VERSION "@GIT_VERSION@" +#endif /* !GIT_VERSION */ + +#ifndef GIT_DATE +# define GIT_DATE @GIT_DATE@ +#endif /* !GIT_DATE */ + +#endif /* HUC_VERSION_H */ diff --git a/src/huc/while.c b/src/huc/while.c new file mode 100644 index 00000000..2c846405 --- /dev/null +++ b/src/huc/while.c @@ -0,0 +1,81 @@ +/* File while.c: 2.1 (83/03/20,16:02:22) */ +/*% cc -O -c % + * + */ + +#include +#include +#include "defs.h" +#include "data.h" +#include "error.h" +#include "gen.h" +#include "io.h" +#include "while.h" + +void addwhile (intptr_t *ptr) +/*intptr_t ptr[];*/ +{ + intptr_t k; + + if (wsptr == WSMAX) { + error("too many active whiles"); + return; + } + k = 0; + while (k < WSSIZ) + *wsptr++ = ptr[k++]; +} + +void delwhile (void) +{ + if (readwhile()) + wsptr = wsptr - WSSIZ; +} + +intptr_t *readwhile (void) +{ + if (wsptr == ws) { + error("no active do/for/while/switch"); + return (0); + } + else + return (wsptr - WSSIZ); +} + +intptr_t *findwhile (void) +{ + intptr_t *ptr; + + for (ptr = wsptr; ptr != ws;) { + ptr = ptr - WSSIZ; + if (ptr[WSTYP] != WSSWITCH) + return (ptr); + } + error("no active do/for/while"); + return (NULL); +} + +intptr_t *readswitch (void) +{ + intptr_t *ptr; + + ptr = readwhile(); + if (ptr) + if (ptr[WSTYP] == WSSWITCH) + return (ptr); + + return (0); +} + +void addcase (intptr_t val) +{ + intptr_t lab; + + if (swstp == SWSTSZ) + error("too many case labels"); + else { + swstcase[swstp] = val; + swstlab[swstp++] = lab = getlabel(); + gnlabel(lab); + } +} diff --git a/src/huc/while.h b/src/huc/while.h new file mode 100644 index 00000000..f35b3ccd --- /dev/null +++ b/src/huc/while.h @@ -0,0 +1,11 @@ +#ifndef _WHILE_H +#define _WHILE_H + +void addwhile (intptr_t *ptr); +void delwhile (void); +intptr_t *readwhile (void); +intptr_t *findwhile (void); +intptr_t *readswitch (void); +void addcase (intptr_t val); + +#endif