commit 98a36557e48d61ba8f9a895420b9c67b1df20d98 Author: Michael Steil Date: Sat May 3 22:20:34 2014 -0700 Initial commit from macross.tar.gz MD5 (macross.tar.gz) = 4ecb4a6e015b11fef043fe78d1eedb61 diff --git a/.mark b/.mark new file mode 100644 index 0000000..3fc6e21 --- /dev/null +++ b/.mark @@ -0,0 +1 @@ +Mon Feb 2 23:18:33 PST 1987 diff --git a/DOC b/DOC new file mode 100644 index 0000000..9bdf982 --- /dev/null +++ b/DOC @@ -0,0 +1,34 @@ +/u0/chip/macross: + This directory contains the source to Macross. Here's what's here: + +DOC - this file + +Makefile - current makefile +Makefile_6502 - makefile for 6502 version +Makefile_68000 - makefile for 68000 + + There are both 6502 and 68000 versions of Macross, though the 68000 +version has not been very well tested. Source for both is here. Source files +which come in different flavors for the different versions are marked 6502 or +68000 in their names as appropriate. There are two different Makefiles also. +At any given time, either the 6502 version or the 68000 version is the +'working' version. The 'working' version is what the default makefile +'Makefile' will produce. Typing 'make foobar' will change the working version +by swapping the makefiles. + +*.c, *.h, *.y - source for the program + +doc/ - the manual and other user documentation are here +notes68/ - notes on 68000 syntax and operand structure +opt/ - working directory for 'optimized' version. When I + was developing the program, I needed to keep two separate copies of + the source and object code. This is because the C compiler can + compile with debugging or with optimization, but not both. The + version that folks use needs to be compiled with optimization, but I + need a version with debugging to fix any problems that crop up. Since + the time to recompile the whole thing is so enormous, it was easiest + to keep two copies. In the interest of saving file space, all that is + in this directory now, however, are the Makefiles for compiling with + optimization. + +slinky/ - Slinky lives here diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..84fcd09 --- /dev/null +++ b/Makefile @@ -0,0 +1,164 @@ +.SUFFIXES: .o .c .h .run + +# to make for another target CPU, redefine PROC to the name of the target +# processor, e.g., 68000 +PROC =6502 + +OBJECTS = y.tab.o actions.o buildStuff1.o buildStuff2.o\ +buildStuff3.o builtInFunctions.o builtInFunsSD.o debugPrint.o debugPrintSD.o\ +emitBranch.o emitStuff.o encode.o errorStuff.o expressionSemantics.o fixups.o\ +garbage.o initialize.o lexer.o listing.o lookups.o macrossTables.o main.o\ +malloc.o object.o operandStuffSD.o parserMisc.o semanticMisc.o\ +statementSemantics.o structSemantics.o tokenStrings.o + +SOURCES = macross_$(PROC).y actions_$(PROC).c buildStuff1.c buildStuff2.c\ +buildStuff3.c builtInFunctions.c builtInFunsSD_$(PROC).c debugPrint.c\ +debugPrintSD_$(PROC).c emitBranch_$(PROC).c emitStuff.c encode.c errorStuff.c\ +expressionSemantics.c fixups.c garbage.c initialize.c lexer.c listing.c\ +lookups.c macrossTables_$(PROC).c main.c malloc.c object.c\ +operandStuffSD_$(PROC).c parserMisc.c semanticMisc.c statementSemantics.c\ +structSemantics.c tokenStrings_$(PROC).c lexerTables.h macrossGlobals.h\ +macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h driver.c slinkyExpressions.h + +HEADERS = macrossTypes.h macrossGlobals.h + +.c.o: + cc -c -g -DTARGET_CPU=CPU_$(PROC) $*.c + +.c.run: + cc -o $* $*.c + +macross: $(OBJECTS) + cc -g -o macross $(OBJECTS) + +driver: driver.c + cc -o driver driver.c + +update: .mark + kessel "(cd /u0/chip/macross; make macross >&errorfyle)" & + +install: macross + cp macross /u1/gg/bin/macross_tmp + strip /u1/gg/bin/macross_tmp + mv /u1/gg/bin/macross_$(PROC) /u1/gg/bin/macross_$(PROC).old + mv /u1/gg/bin/macross_tmp /u1/gg/bin/macross_$(PROC) + cp /u1/gg/bin/macross_$(PROC) /net/mycroft/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/shem/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/weyr/u1/gg/bin + +dinstall: driver + cp driver /u1/gg/bin/driver_tmp + strip /u1/gg/bin/driver_tmp + mv /u1/gg/bin/driver_tmp /u1/gg/bin/driver/macross + cp /u1/gg/bin/driver /net/mycroft/u1/gg/bin/macross + cp /u1/gg/bin/driver /net/shem/u1/gg/bin/macross + cp /u1/gg/bin/driver /net/weyr/u1/gg/bin/macross + +change: + rm *.o + rm *.tab.* + cp Makefile_68000 Makefile + +move: .mark + +.mark: $(SOURCES) + cp $? /net/kessel/u0/chip/macross + cp $? /net/kessel/u0/chip/macross/prof + cp $? opt + date >.mark + date >/net/kessel/u0/chip/macross/.mark + date >/net/kessel/u0/chip/macross/prof/.mark + date >opt/.mark + +macrossTypes.h: macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h + +actions.o: actions_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) actions_$(PROC).c + mv actions_$(PROC).o actions.o + +buildStuff1.o: buildStuff1.c $(HEADERS) + +buildStuff2.o: buildStuff2.c $(HEADERS) + +buildStuff3.o: buildStuff3.c $(HEADERS) + +builtInFunctions.o: builtInFunctions.c $(HEADERS) + +builtInFunsSD.o: builtInFunsSD_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) builtInFunsSD_$(PROC).c + mv builtInFunsSD_$(PROC).o builtInFunsSD.o + +debugPrint.o: debugPrint.c y.tab.h $(HEADERS) + +debugPrintSD.o: debugPrintSD_$(PROC).c y.tab.h $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) debugPrintSD_$(PROC).c + mv debugPrintSD_$(PROC).o debugPrintSD.o + +emitBranch.o: emitBranch_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) emitBranch_$(PROC).c + mv emitBranch_$(PROC).o emitBranch.o + +emitStuff.o: emitStuff.c $(HEADERS) + cc -c -g -DBYTESWAPPED -DTARGET_CPU=CPU_$(PROC) emitStuff.c + +encode.o: encode.c $(HEADERS) + +errorStuff.o: errorStuff.c $(HEADERS) + +expressionSemantics.o: expressionSemantics.c y.tab.h $(HEADERS) + +fixups.o: fixups.c $(HEADERS) + +garbage.o: garbage.c y.tab.h $(HEADERS) + +initialize.o: initialize.c $(HEADERS) + +lexer.o: lexer.c lexerTables.h y.tab.h $(HEADERS) + +listing.o: listing.c $(HEADERS) + +lookups.o: lookups.c $(HEADERS) + +macrossTables.o: macrossTables_$(PROC).c y.tab.h macrossTypes.h + cc -c -g -DTARGET_CPU=CPU_$(PROC) macrossTables_$(PROC).c + mv macrossTables_$(PROC).o macrossTables.o + +malloc.o: malloc.c + +main.o: main.c $(HEADERS) + +object.o: object.c $(HEADERS) + +operandStuffSD.o: operandStuffSD_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) operandStuffSD_$(PROC).c + mv operandStuffSD_$(PROC).o operandStuffSD.o + +parserMisc.o: parserMisc.c y.tab.h $(HEADERS) + +semanticMisc.o: semanticMisc.c $(HEADERS) + +statementSemantics.o: statementSemantics.c $(HEADERS) + +structSemantics.o: structSemantics.c $(HEADERS) + +tokenStrings.o: tokenStrings_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) tokenStrings_$(PROC).c + mv tokenStrings_$(PROC).o tokenStrings.o + +y.tab.o: y.tab.c $(HEADERS) + cc -c -g -DYYDEBUG -DTARGET_CPU=CPU_$(PROC) y.tab.c + +y.tab.c y.tab.h: macross_$(PROC).y + yacc -d macross_$(PROC).y + +y.output: macross_$(PROC).y + yacc -vd macross_$(PROC).y + +cleanup: + /bin/rm -f *.o y.output y.tab.c y.tab.h macross + +love: + @echo "Not war?" + diff --git a/Makefile_6502 b/Makefile_6502 new file mode 100644 index 0000000..5891e6f --- /dev/null +++ b/Makefile_6502 @@ -0,0 +1,162 @@ +.SUFFIXES: .o .c .h .run + +# to make for another target CPU, redefine PROC to the name of the target +# processor, e.g., 68000 +PROC =6502 + +OBJECTS = y.tab.o actions.o buildStuff1.o buildStuff2.o\ +buildStuff3.o builtInFunctions.o builtInFunsSD.o debugPrint.o debugPrintSD.o\ +emitBranch.o emitStuff.o errorStuff.o expressionSemantics.o fixups.o\ +garbage.o initialize.o lexer.o listing.o lookups.o macrossTables.o main.o\ +malloc.o object.o operandStuffSD.o parserMisc.o semanticMisc.o\ +statementSemantics.o structSemantics.o tokenStrings.o + +SOURCES = macross_$(PROC).y actions_$(PROC).c buildStuff1.c buildStuff2.c\ +buildStuff3.c builtInFunctions.c builtInFunsSD_$(PROC).c debugPrint.c\ +debugPrintSD_$(PROC).c emitBranch_$(PROC).c emitStuff.c errorStuff.c\ +expressionSemantics.c fixups.c garbage.c initialize.c lexer.c listing.c\ +lookups.c macrossTables_$(PROC).c main.c malloc.c object.c\ +operandStuffSD_$(PROC).c parserMisc.c semanticMisc.c statementSemantics.c\ +structSemantics.c tokenStrings_$(PROC).c lexerTables.h macrossGlobals.h\ +macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h driver.c + +HEADERS = macrossTypes.h macrossGlobals.h + +.c.o: + cc -c -g -DTARGET_CPU=CPU_$(PROC) $*.c + +.c.run: + cc -o $* $*.c + +macross: $(OBJECTS) + cc -g -o macross $(OBJECTS) + +driver: driver.c + cc -o driver driver.c + +update: .mark + kessel "(cd /u0/chip/macross; make macross >&errorfyle)" & + +install: macross + cp macross /u1/gg/bin/macross_tmp + strip /u1/gg/bin/macross_tmp + mv /u1/gg/bin/macross_$(PROC) /u1/gg/bin/macross_$(PROC).old + mv /u1/gg/bin/macross_tmp /u1/gg/bin/macross_$(PROC) + cp /u1/gg/bin/macross_$(PROC) /net/mycroft/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/shem/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/weyr/u1/gg/bin + +dinstall: driver + cp driver /u1/gg/bin/driver_tmp + strip /u1/gg/bin/driver_tmp + mv /u1/gg/bin/driver_tmp /u1/gg/bin/driver/macross + cp /u1/gg/bin/driver /net/mycroft/u1/gg/bin/macross + cp /u1/gg/bin/driver /net/shem/u1/gg/bin/macross + cp /u1/gg/bin/driver /net/weyr/u1/gg/bin/macross + +change: + rm *.o + rm *.tab.* + cp Makefile_68000 Makefile + +move: .mark + +.mark: $(SOURCES) + cp $? /net/kessel/u0/chip/macross + cp $? /net/kessel/u0/chip/macross/prof + cp $? opt + date >.mark + date >/net/kessel/u0/chip/macross/.mark + date >/net/kessel/u0/chip/macross/prof/.mark + date >opt/.mark + +macrossTypes.h: macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h + +actions.o: actions_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) actions_$(PROC).c + mv actions_$(PROC).o actions.o + +buildStuff1.o: buildStuff1.c $(HEADERS) + +buildStuff2.o: buildStuff2.c $(HEADERS) + +buildStuff3.o: buildStuff3.c $(HEADERS) + +builtInFunctions.o: builtInFunctions.c $(HEADERS) + +builtInFunsSD.o: builtInFunsSD_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) builtInFunsSD_$(PROC).c + mv builtInFunsSD_$(PROC).o builtInFunsSD.o + +debugPrint.o: debugPrint.c y.tab.h $(HEADERS) + +debugPrintSD.o: debugPrintSD_$(PROC).c y.tab.h $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) debugPrintSD_$(PROC).c + mv debugPrintSD_$(PROC).o debugPrintSD.o + +emitBranch.o: emitBranch_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) emitBranch_$(PROC).c + mv emitBranch_$(PROC).o emitBranch.o + +emitStuff.o: emitStuff.c $(HEADERS) + cc -c -g -DBYTESWAPPED -DTARGET_CPU=CPU_$(PROC) emitStuff.c + +errorStuff.o: errorStuff.c $(HEADERS) + +expressionSemantics.o: expressionSemantics.c y.tab.h $(HEADERS) + +fixups.o: fixups.c $(HEADERS) + +garbage.o: garbage.c y.tab.h $(HEADERS) + +initialize.o: initialize.c $(HEADERS) + +lexer.o: lexer.c lexerTables.h y.tab.h $(HEADERS) + +listing.o: listing.c $(HEADERS) + +lookups.o: lookups.c $(HEADERS) + +macrossTables.o: macrossTables_$(PROC).c y.tab.h macrossTypes.h + cc -c -g -DTARGET_CPU=CPU_$(PROC) macrossTables_$(PROC).c + mv macrossTables_$(PROC).o macrossTables.o + +malloc.o: malloc.c + +main.o: main.c $(HEADERS) + +object.o: object.c $(HEADERS) + +operandStuffSD.o: operandStuffSD_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) operandStuffSD_$(PROC).c + mv operandStuffSD_$(PROC).o operandStuffSD.o + +parserMisc.o: parserMisc.c y.tab.h $(HEADERS) + +semanticMisc.o: semanticMisc.c $(HEADERS) + +statementSemantics.o: statementSemantics.c $(HEADERS) + +structSemantics.o: structSemantics.c $(HEADERS) + +tokenStrings.o: tokenStrings_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) tokenStrings_$(PROC).c + mv tokenStrings_$(PROC).o tokenStrings.o + +y.tab.o: y.tab.c $(HEADERS) + cc -c -g -DYYDEBUG -DTARGET_CPU=CPU_$(PROC) y.tab.c + +y.tab.c y.tab.h: macross_$(PROC).y + yacc -d macross_$(PROC).y + +y.output: macross_$(PROC).y + yacc -vd macross_$(PROC).y + +cleanup: + /bin/rm -f *.o y.output y.tab.c y.tab.h macross + +love: + @echo "Not war?" + diff --git a/Makefile_68000 b/Makefile_68000 new file mode 100644 index 0000000..70e8b63 --- /dev/null +++ b/Makefile_68000 @@ -0,0 +1,162 @@ +.SUFFIXES: .o .c .h .run + +# to make for another target CPU, redefine PROC to the name of the target +# processor, e.g., 68000 +PROC =68000 + +OBJECTS = y.tab.o actions.o buildStuff1.o buildStuff2.o\ +buildStuff3.o builtInFunctions.o builtInFunsSD.o debugPrint.o debugPrintSD.o\ +emitBranch.o emitStuff.o errorStuff.o expressionSemantics.o fixups.o\ +garbage.o initialize.o lexer.o listing.o lookups.o macrossTables.o main.o\ +malloc.o object.o operandStuffSD.o parserMisc.o semanticMisc.o\ +statementSemantics.o structSemantics.o tokenStrings.o + +SOURCES = macross_$(PROC).y actions_$(PROC).c buildStuff1.c buildStuff2.c\ +buildStuff3.c builtInFunctions.c builtInFunsSD_$(PROC).c debugPrint.c\ +debugPrintSD_$(PROC).c emitBranch_$(PROC).c emitStuff.c errorStuff.c\ +expressionSemantics.c fixups.c garbage.c initialize.c lexer.c listing.c\ +lookups.c macrossTables_$(PROC).c main.c malloc.c object.c\ +operandStuffSD_$(PROC).c parserMisc.c semanticMisc.c statementSemantics.c\ +structSemantics.c tokenStrings_$(PROC).c lexerTables.h macrossGlobals.h\ +macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h driver.c + +HEADERS = macrossTypes.h macrossGlobals.h + +.c.o: + cc -c -g -DTARGET_CPU=CPU_$(PROC) $*.c + +.c.run: + cc -o $* $*.c + +macross: $(OBJECTS) + cc -g -o macross $(OBJECTS) + +driver: driver.c + cc -o driver driver.c + +update: .mark + kessel "(cd /u0/chip/macross; make macross >&errorfyle)" & + +install: macross + cp macross /u1/gg/bin/macross_tmp + strip /u1/gg/bin/macross_tmp + mv /u1/gg/bin/macross_$(PROC) /u1/gg/bin/macross_$(PROC).old + mv /u1/gg/bin/macross_tmp /u1/gg/bin/macross_$(PROC) + cp /u1/gg/bin/macross_$(PROC) /net/mycroft/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/shem/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/weyr/u1/gg/bin + +dinstall: driver + cp driver /u1/gg/bin/driver_tmp + strip /u1/gg/bin/driver_tmp + mv /u1/gg/bin/driver_tmp /u1/gg/bin/driver/macross + cp /u1/gg/bin/driver /net/mycroft/u1/gg/bin/macross + cp /u1/gg/bin/driver /net/shem/u1/gg/bin/macross + cp /u1/gg/bin/driver /net/weyr/u1/gg/bin/macross + +change: + rm *.o + rm *.tab.* + cp Makefile_6502 Makefile + +move: .mark + +.mark: $(SOURCES) + cp $? /net/kessel/u0/chip/macross + cp $? /net/kessel/u0/chip/macross/prof + cp $? opt + date >.mark + date >/net/kessel/u0/chip/macross/.mark + date >/net/kessel/u0/chip/macross/prof/.mark + date >opt/.mark + +macrossTypes.h: macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h + +actions.o: actions_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) actions_$(PROC).c + mv actions_$(PROC).o actions.o + +buildStuff1.o: buildStuff1.c $(HEADERS) + +buildStuff2.o: buildStuff2.c $(HEADERS) + +buildStuff3.o: buildStuff3.c $(HEADERS) + +builtInFunctions.o: builtInFunctions.c $(HEADERS) + +builtInFunsSD.o: builtInFunsSD_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) builtInFunsSD_$(PROC).c + mv builtInFunsSD_$(PROC).o builtInFunsSD.o + +debugPrint.o: debugPrint.c y.tab.h $(HEADERS) + +debugPrintSD.o: debugPrintSD_$(PROC).c y.tab.h $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) debugPrintSD_$(PROC).c + mv debugPrintSD_$(PROC).o debugPrintSD.o + +emitBranch.o: emitBranch_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) emitBranch_$(PROC).c + mv emitBranch_$(PROC).o emitBranch.o + +emitStuff.o: emitStuff.c $(HEADERS) + cc -c -g -DBYTESWAPPED -DTARGET_CPU=CPU_$(PROC) emitStuff.c + +errorStuff.o: errorStuff.c $(HEADERS) + +expressionSemantics.o: expressionSemantics.c y.tab.h $(HEADERS) + +fixups.o: fixups.c $(HEADERS) + +garbage.o: garbage.c y.tab.h $(HEADERS) + +initialize.o: initialize.c $(HEADERS) + +lexer.o: lexer.c lexerTables.h y.tab.h $(HEADERS) + +listing.o: listing.c $(HEADERS) + +lookups.o: lookups.c $(HEADERS) + +macrossTables.o: macrossTables_$(PROC).c y.tab.h macrossTypes.h + cc -c -g -DTARGET_CPU=CPU_$(PROC) macrossTables_$(PROC).c + mv macrossTables_$(PROC).o macrossTables.o + +malloc.o: malloc.c + +main.o: main.c $(HEADERS) + +object.o: object.c $(HEADERS) + +operandStuffSD.o: operandStuffSD_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) operandStuffSD_$(PROC).c + mv operandStuffSD_$(PROC).o operandStuffSD.o + +parserMisc.o: parserMisc.c y.tab.h $(HEADERS) + +semanticMisc.o: semanticMisc.c $(HEADERS) + +statementSemantics.o: statementSemantics.c $(HEADERS) + +structSemantics.o: structSemantics.c $(HEADERS) + +tokenStrings.o: tokenStrings_$(PROC).c $(HEADERS) + cc -c -g -DTARGET_CPU=CPU_$(PROC) tokenStrings_$(PROC).c + mv tokenStrings_$(PROC).o tokenStrings.o + +y.tab.o: y.tab.c $(HEADERS) + cc -c -g -DYYDEBUG -DTARGET_CPU=CPU_$(PROC) y.tab.c + +y.tab.c y.tab.h: macross_$(PROC).y + yacc -d macross_$(PROC).y + +y.output: macross_$(PROC).y + yacc -vd macross_$(PROC).y + +cleanup: + /bin/rm -f *.o y.output y.tab.c y.tab.h macross + +love: + @echo "Not war?" + diff --git a/actions.o b/actions.o new file mode 100644 index 0000000..2f3d201 Binary files /dev/null and b/actions.o differ diff --git a/actions_6502.c b/actions_6502.c new file mode 100644 index 0000000..b476ab7 --- /dev/null +++ b/actions_6502.c @@ -0,0 +1,511 @@ +/* + actions.c -- Actions associated with various machine instruction + classes (6502 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 16-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +#define operand (evaluatedOperands[0]) +#define address (evaluatedOperands[0])->value +#define class (evaluatedOperands[0])->addressMode +#define binary opcode->opcode + +/* + These routines are vectored off of the opcode lookup table. Each + instruction is of a particular category that defines which address modes + it accepts its operands in and what size (one byte or two) the operands + are. There is one "actionsXXXX" routine for each of these categories that + grabs the operand, checks the address mode, and emits the binary opcode + and operand. + */ + + void +actionsDir1(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define ZERO_PAGE_ADDRESS_BIT 0x00 +#define NON_ZERO_PAGE_ADDRESS_BIT 0x08 + + if(class==EXPRESSION_OPND && isByteAddress(operand) && + isDefined(operand)){ + emitByte(binary | ZERO_PAGE_ADDRESS_BIT); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary | NON_ZERO_PAGE_ADDRESS_BIT); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } +} + + void +actionsDir2(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ + if (wordCheck(address)) { + emitByte(binary); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } +} + + void +actionsDirIndir(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define DIRECT_ADDRESS_BIT 0x00 +#define INDIRECT_ADDRESS_BIT 0x20 + + if (wordCheck(address)) { + if (class == INDIRECT_OPND) + emitByte(binary | INDIRECT_ADDRESS_BIT); + else + emitByte(binary | DIRECT_ADDRESS_BIT); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } +} + + void +actionsDirX1(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define DIRECT_ADDRESS_ZERO_PAGE_BITS_X1 0x04 +#define A_REGISTER_BITS_X1 0x08 +#define DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_X1 0x0C +#define X_INDEXED_ZERO_PAGE_BITS_X1 0x14 +#define X_INDEXED_NON_ZERO_PAGE_BITS_X1 0x1C + + if (class == EXPRESSION_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_X1); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary|DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_X1); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else if (class==X_INDEXED_OPND || class==X_SELECTED_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | X_INDEXED_ZERO_PAGE_BITS_X1); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary | X_INDEXED_NON_ZERO_PAGE_BITS_X1); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else { + emitByte(binary | A_REGISTER_BITS_X1); + } +} + + void +actionsDirX2(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define DIRECT_ADDRESS_ZERO_PAGE_BITS_X2 0x00 +#define DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_X2 0x08 +#define X_INDEXED_ZERO_PAGE_BITS_X2 0x10 +#define X_INDEXED_NON_ZERO_PAGE_BITS_X2 0x18 + + if (class == EXPRESSION_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_X2); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary|DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_X2); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | X_INDEXED_ZERO_PAGE_BITS_X2); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary | X_INDEXED_NON_ZERO_PAGE_BITS_X2); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } +} + + void +actionsDirX3(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ + if (class == EXPRESSION_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_X2); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary|DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_X2); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else { + if (byteCheck(address)) { + emitByte(binary | X_INDEXED_ZERO_PAGE_BITS_X2); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } +} + + void +actionsDirY(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define DIRECT_ADDRESS_ZERO_PAGE_BITS_Y 0x00 +#define DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_Y 0x08 +#define Y_INDEXED_ZERO_PAGE_BITS_Y 0x10 + + if (class == EXPRESSION_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_Y); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary|DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_Y); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else { + if (byteCheck(address)) { + emitByte(binary | Y_INDEXED_ZERO_PAGE_BITS_Y); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } +} + + void +actionsImmDir(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define IMMEDIATE_DATA_BITS_ID 0x00 +#define DIRECT_ADDRESS_ZERO_PAGE_BITS_ID 0x04 +#define DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_ID 0x0C + + if (class == IMMEDIATE_OPND) { + if (byteCheck(address)) { + emitByte(binary | IMMEDIATE_DATA_BITS_ID); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } else { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_ID); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary|DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_ID); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } +} + + void +actionsImmDirX(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define IMMEDIATE_DATA_BITS_IX 0x00 +#define DIRECT_ADDRESS_ZERO_PAGE_BITS_IX 0x04 +#define DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_IX 0x0C +#define X_INDEXED_ZERO_PAGE_BITS_IX 0x14 +#define X_INDEXED_NON_ZERO_PAGE_BITS_IX 0x1C + + if (class == IMMEDIATE_OPND) { + if (byteCheck(address)) { + emitByte(binary | IMMEDIATE_DATA_BITS_IX); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } else if (class == EXPRESSION_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_IX); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary|DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_IX); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | X_INDEXED_ZERO_PAGE_BITS_IX); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary | X_INDEXED_NON_ZERO_PAGE_BITS_IX); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } +} + + void +actionsImmDirY(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define IMMEDIATE_DATA_BITS_IY 0x00 +#define DIRECT_ADDRESS_ZERO_PAGE_BITS_IY 0x04 +#define DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_IY 0x0C +#define Y_INDEXED_ZERO_PAGE_BITS_IY 0x14 +#define Y_INDEXED_NON_ZERO_PAGE_BITS_IY 0x1C + + if (class == IMMEDIATE_OPND) { + if (byteCheck(address)) { + emitByte(binary | IMMEDIATE_DATA_BITS_IY); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } else if (class == EXPRESSION_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_IY); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary|DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_IY); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | Y_INDEXED_ZERO_PAGE_BITS_IY); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary | Y_INDEXED_NON_ZERO_PAGE_BITS_IY); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } +} + + void +actionsImmIndex(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define PRE_INDEXED_BITS_A 0x00 +#define DIRECT_ADDRESS_ZERO_PAGE_BITS_A 0x04 +#define IMMEDIATE_DATA_BITS_A 0x08 +#define DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_A 0x0C +#define POST_INDEXED_BITS_A 0x10 +#define X_INDEXED_ZERO_PAGE_BITS_A 0x14 +#define Y_INDEXED_NON_ZERO_PAGE_BITS_A 0x18 +#define X_INDEXED_NON_ZERO_PAGE_BITS_A 0x1C + + if (class == EXPRESSION_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_A); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary |DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_A); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else if (class==X_INDEXED_OPND || class==X_SELECTED_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | X_INDEXED_ZERO_PAGE_BITS_A); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary | X_INDEXED_NON_ZERO_PAGE_BITS_A); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else if (class==Y_INDEXED_OPND || class==Y_SELECTED_OPND) { + if (wordCheck(address)) { + emitByte(binary | Y_INDEXED_NON_ZERO_PAGE_BITS_A); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else if (class == IMMEDIATE_OPND) { + if (byteCheck(address)) { + emitByte(binary | IMMEDIATE_DATA_BITS_A); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } else if (class == POST_INDEXED_Y_OPND) { + if (byteCheck(address)) { + emitByte(binary | POST_INDEXED_BITS_A); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } else { + if (byteCheck(address)) { + emitByte(binary | PRE_INDEXED_BITS_A); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } +} + + void +actionsIndex(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ + if (class == EXPRESSION_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | DIRECT_ADDRESS_ZERO_PAGE_BITS_A); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary |DIRECT_ADDRESS_NON_ZERO_PAGE_BITS_A); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else if (class==X_INDEXED_OPND || class==X_SELECTED_OPND) { + if (isByteAddress(operand) && isDefined(operand)) { + emitByte(binary | X_INDEXED_ZERO_PAGE_BITS_A); + emitByte(address); + } else if (wordCheck(address)) { + emitByte(binary | X_INDEXED_NON_ZERO_PAGE_BITS_A); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else if (class==Y_INDEXED_OPND || class==Y_SELECTED_OPND) { + if (wordCheck(address)) { + emitByte(binary | Y_INDEXED_NON_ZERO_PAGE_BITS_A); + putFixupsHere(WORD_FIXUP, 0); + emitWord(address); + } + } else if (class == POST_INDEXED_Y_OPND) { + if (byteCheck(address)) { + emitByte(binary | POST_INDEXED_BITS_A); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } else { + if (byteCheck(address)) { + emitByte(binary | PRE_INDEXED_BITS_A); + putFixupsHere(BYTE_FIXUP, 0); + emitByte(address); + } + } +} + + void +actionsNone(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ + emitByte(binary); +} + + void +actionsRelative(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ + int offset; + + if (operand->kindOfValue == UNDEFINED_VALUE || (currentCodeMode == + RELOCATABLE_BUFFER && targetOffset == 0)) + offset = 0; + else + offset = address - (currentLocationCounter.value - targetOffset) - 1; + if (offset < 0) + offset--; + if (isByteOffset(offset)) { + emitByte(binary); + putFixupsHere(BYTE_RELATIVE_FIXUP, 0); + emitByte(offset); + } else { + error(RELATIVE_OFFSET_TOO_LARGE_ERROR); + } +} + +/* + Miscellaneous helper predicates. + */ + + bool +isByte(value) + int value; +{ + return (-129kindOfValue==ABSOLUTE_VALUE && isByte(value->value)); +} + + bool +isWord(value) + int value; +{ + return (-32769kindOfValue!=UNDEFINED_VALUE); +} diff --git a/actions_68000.c b/actions_68000.c new file mode 100644 index 0000000..bdbea9c --- /dev/null +++ b/actions_68000.c @@ -0,0 +1,1089 @@ +/* + actions.c -- Actions associated with various machine instruction + classes (68000 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 26-April-1985 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +#define binary opcode->opcode +#define altBinary opcode->subClass +#define sub opcode->subClass + +#define mode(n) ((evaluatedOperands[n])->addressMode) +#define trueMode(n) (operandKindField(mode(n))) +#define address(n) (evaluatedOperands[n]->value) +#define forward(n) (!isDefined(evaluatedOperands[n])) +#define register(n) (getRegister(mode(n))) +#define controlRegister(n) (trueMode(n)==USP_REGISTER_OPND ? \ + 0x800 : (register(n) == SFC_REGISTER ? \ + 0x000 : (register(n) == DFC_REGISTER ? \ + 0x001 : 0x801))) +#define eaPC(n) (effectiveAddressBits(mode(n), address(n), \ + forward(n), TRUE)) +#define eaNoPC(n) (effectiveAddressBits(mode(n), address(n), \ + forward(n), FALSE)) +#define eaFlop(n) (eaNoPC(n)>>3 | (eaNoPC(n)&7)<<3) +#define extendPC(n) emitPossibleExtension(address(n), mode(n), binary, n,\ + forward(n), TRUE) +#define extendNoPC(n) emitPossibleExtension(address(n), mode(n), binary, n,\ + forward(n), FALSE) +#define check(g, n) ((operandClassTable[(int)trueMode(n)] &\ + g) != 0) +#define defcheck(n) isDefined(evaluatedOperands[n]) +#define check1(g) (numberOfOperands==1 && check(g, 0)) +#define check2(g1, g2) (numberOfOperands==2 && check(g1, 0) && check(g2, 1)) +/*#define check1(g) (numberOfOperands==1 && check(g, 0) && defcheck(0)) +#define check2(g1, g2) (numberOfOperands==2 && check(g1, 0) && check(g2, 1)\ + && defcheck(0) && defcheck(1))*/ + +#define iifCheck0() if (numberOfOperands==0) { +#define iifCheck1(g) if (check1(g)) { +#define eifCheck1(g) } else if (check1(g)) { +#define iifCheck2(g1, g2) if (check2(g1, g2)) { +#define eifCheck2(g1, g2) } else if (check2(g1, g2)) { +#define done } else {\ + error(INAPPROPRIATE_ADDRESS_MODES_ERROR);\ + } + +#define D_TO_EA_BIT 0x0100 +#define EA_TO_D_BIT 0x0000 +#define R_SHIFT 9 +#define Q_DATA_SHIFT 9 + +#define OP_SIZE_BITS 0x00C0 +#define BYTE_OP_SIZE_BITS 0x0000 +#define WORD_OP_SIZE_BITS 0x0040 +#define LONG_OP_SIZE_BITS 0x0080 + +#define byteOp(op) (((op) & OP_SIZE_BITS) == BYTE_OP_SIZE_BITS) +#define wordOp(op) (((op) & OP_SIZE_BITS) == WORD_OP_SIZE_BITS) +#define longOp(op) (((op) & OP_SIZE_BITS) == LONG_OP_SIZE_BITS) + +#define MOVE_OP_SIZE_BITS 0x3000 +#define MOVE_BYTE_OP_SIZE_BITS 0x1000 +#define MOVE_WORD_OP_SIZE_BITS 0x3000 +#define MOVE_LONG_OP_SIZE_BITS 0x2000 + +#define moveByteOp(op) (((op) & MOVE_OP_SIZE_BITS) == \ + MOVE_BYTE_OP_SIZE_BITS) +#define moveWordOp(op) (((op) & MOVE_OP_SIZE_BITS) == \ + MOVE_WORD_OP_SIZE_BITS) +#define moveLongOp(op) (((op) & MOVE_OP_SIZE_BITS) == \ + MOVE_LONG_OP_SIZE_BITS) + +#define isMoveOp(op) ((op)==0x1000 || (op)==0x2000 || (op)==0x3000) +#define byteOpGeneral(op) (isMoveOp(op) ? moveByteOp(op) : byteOp(op)) +#define wordOpGeneral(op) (isMoveOp(op) ? moveWordOp(op) : wordOp(op)) + +void emitPossibleExtension(); + +#define emitImmediate(n) \ + if (byteOp(binary)) {\ + if (byteCheck(address(n))) {\ + emitByte(0);\ + putFixupsHere(BYTE_FIXUP, n);\ + emitByte(address(n));\ + }\ + } else if (wordOp(binary)) {\ + if (wordCheck(address(n))) {\ + putFixupsHere(WORD_FIXUP, n);\ + emitWord(address(n));\ + }\ + } else {\ + putFixupsHere(LONG_FIXUP, n);\ + emitLong(address(n));\ + } + +/* + These routines are vectored off of the opcode lookup table. Each + instruction is of a particular category that defines which address modes + it accepts its operands in and what size the operands are. There is one + "actionsXXXX" routine for each of these categories that grabs the operands, + checks their address modes, and emits the binary instruction and operands. + */ + +/* Class I: abcd, addxb, addxw, addxl, sbcd, subxb, subxw, subxl */ + void +actionsClassI(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ +#define D_REGISTER_BIT_I 0x0000 +#define PREDECREMENT_BIT_I 0x0008 + +iifCheck2(GROUP_A, GROUP_A) + emitWord(binary | register(1)<data */ + emitWord(binary | register(0)<addr */ + emitWord(binary | register(0)<data */ + emitWord(binary | register(1)<addr */ + emitWord(binary | register(0)<kindOfValue==ABSOLUTE_VALUE && isByte(value->value)); +} + + bool +isWord(value) + int value; +{ + return (-32769kindOfValue!=UNDEFINED_VALUE); +} + +#define D_REGISTER_EA 0x0000 +#define A_REGISTER_EA 0x0008 +#define A_REGISTER_INDIRECT_EA 0x0010 +#define POSTINCREMENT_EA 0x0018 +#define PREDECREMENT_EA 0x0020 +#define DISPLACEMENT_EA 0x0028 +#define SELECTED_EA 0x0028 +#define INDEXED_EA 0x0030 +#define INDEX_SELECTED_EA 0x0030 +#define PC_DISPLACEMENT_EA 0x003A +#define PC_INDEXED_EA 0x003B +#define IMMEDIATE_EA 0x003C +#define ABSOLUTE_SHORT_EA 0x0038 +#define ABSOLUTE_LONG_EA 0x0039 + + int +effectiveAddressBits(operandKind, value, isForwardRef, pcRelativeOK) + operandKindType operandKind; + int value; + bool isForwardRef; + bool pcRelativeOK; +{ + switch(operandKindField(operandKind)) { + case D_REGISTER_OPND: + return(D_REGISTER_EA | getRegister(operandKind)); + break; + case A_REGISTER_OPND: + return(A_REGISTER_EA | getRegister(operandKind)); + break; + case A_REGISTER_INDIRECT_OPND: + return(A_REGISTER_INDIRECT_EA | getRegister(operandKind)); + break; + case POSTINCREMENT_OPND: + return(POSTINCREMENT_EA | getRegister(operandKind)); + break; + case PREDECREMENT_OPND: + return(PREDECREMENT_EA | getRegister(operandKind)); + break; + case DISPLACEMENT_OPND: + return(DISPLACEMENT_EA | getRegister(operandKind)); + break; + case SELECTED_OPND: + return(SELECTED_EA | getRegister(operandKind)); + break; + case INDEXED_OPND: + return(INDEXED_EA | getRegister(operandKind)); + break; + case INDEX_SELECTED_OPND: + return(INDEX_SELECTED_EA | getRegister(operandKind)); + break; + case PC_DISPLACEMENT_OPND: + return(PC_DISPLACEMENT_EA); + break; + case PC_INDEXED_OPND: + return(PC_INDEXED_EA); + break; + case IMMEDIATE_OPND: + return(IMMEDIATE_EA); + break; + case ABSOLUTE_SHORT_OPND: + return(ABSOLUTE_SHORT_EA); + break; + case ABSOLUTE_LONG_OPND: + return(ABSOLUTE_LONG_EA); + break; + case EXPRESSION_OPND: + if (pcRelativeOK && isWordOffset(value - + (currentLocationCounter.value - targetOffset + + 2)) && !isForwardRef) + return(PC_DISPLACEMENT_EA); + else if (isWord(value) && !isForwardRef) + return(ABSOLUTE_SHORT_EA); + else + return(ABSOLUTE_LONG_EA); + break; + case STRING_OPND: + botch("string opnd to get ea\n"); + break; + case BLOCK_OPND: + botch("block opnd to get ea\n"); + break; + case CC_REGISTER_OPND: + case STATUS_REGISTER_OPND: + case USP_REGISTER_OPND: + case CONTROL_REGISTER_OPND: + botch("funny opnd to get ea\n"); + break; + default: + botch("non-existant operand kind to get ea: %x\n", + operandKind); + break; + } +} + + void +emitPossibleExtension(value, addressMode, opcode, operandNumber, isForwardRef, + pcRelativeOK) + int value; + operandKindType addressMode; + int opcode; + int operandNumber; + bool isForwardRef; + bool pcRelativeOK; +{ + switch (operandKindField(addressMode)) { + + case DISPLACEMENT_OPND: + case SELECTED_OPND: + case ABSOLUTE_SHORT_OPND: + case PC_DISPLACEMENT_OPND: + putFixupsHere(WORD_FIXUP, operandNumber); + wordCheck(value); + emitWord(value); + break; + case INDEXED_OPND: + case INDEX_SELECTED_OPND: + case PC_INDEXED_OPND: + emitByte(indexByte(addressMode)); + putFixupsHere(BYTE_FIXUP,operandNumber); + byteCheck(value); + emitByte(value); + break; + case ABSOLUTE_LONG_OPND: + putFixupsHere(LONG_FIXUP, operandNumber); + emitLong(value); + break; + case IMMEDIATE_OPND: + if (byteOpGeneral(opcode)) { + emitByte(0); + putFixupsHere(BYTE_FIXUP, operandNumber); + byteCheck(value); + emitByte(value); + } else if (wordOpGeneral(opcode)) { + putFixupsHere(WORD_FIXUP, operandNumber); + wordCheck(value); + emitWord(value); + } else { + putFixupsHere(LONG_FIXUP, operandNumber); + emitLong(value); + } + break; + case EXPRESSION_OPND: + if (pcRelativeOK && isWordOffset(value - + (currentLocationCounter.value - + targetOffset)) && !isForwardRef) { + putFixupsHere(WORD_RELATIVE_FIXUP, + operandNumber); + emitWord(value - (currentLocationCounter.value - + targetOffset)); + } else if (isWord(value) && !isForwardRef) { + putFixupsHere(WORD_FIXUP, operandNumber); + emitWord(value); + } else { + putFixupsHere(LONG_FIXUP, operandNumber); + emitLong(value); + } + break; + default: + break; + } +} + + int +indexByte(operandKind) + operandKindType operandKind; +{ + return((getIndexRegister(operandKind)<<4) | (getWL(operandKind)<<3)); +} diff --git a/buildStuff1.c b/buildStuff1.c new file mode 100644 index 0000000..18319e9 --- /dev/null +++ b/buildStuff1.c @@ -0,0 +1,547 @@ +/* + buildStuff1.c -- Routines to build parse-tree structures for the + Macross assembler. This module is target processor + independent. + + Chip Morningstar -- Lucasfilm Ltd. + + 1-November-1984 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +symbolTableEntryType *lookupOrEnterSymbol(); +char *saveString(); + +/* Generic routine to create statement nodes */ + statementType * +newStatement(kind, body) + statementKindType kind; + statementBodyType body; +{ + statementType *result; + + result = typeAlloc(statementType); + result->kindOfStatement = kind; + result->labels = NULL; + result->statementBody = body; + result->nextStatement = NULL; + result->fileName = currentFileName; + result->lineNumber = currentLineNumber; + result->cumulativeLineNumber = cumulativeLineNumber; + return(result); +} + +/* + These routines specifically build top-level parse-tree nodes corresponding + to the different types of Macross statements. There is one such routine of + the form "buildXxxxStatement" for each kind of Macross statement. + */ + + statementType * +buildAlignStatement(expression) + expressionType *expression; +{ + return(newStatement(ALIGN_STATEMENT, + (alignStatementBodyType *) expression)); +} + + statementType * +buildAssertStatement(condition, message) + expressionType *condition; + expressionType *message; +{ + assertStatementBodyType *result; + + result = typeAlloc(assertStatementBodyType); + + result->condition = condition; + result->message = message; + return(newStatement(ASSERT_STATEMENT, result)); +} + + statementType * +buildBlockStatement(expressionList) + expressionListType *expressionList; +{ + return(newStatement(BLOCK_STATEMENT, + (blockStatementBodyType *) expressionList)); +} + + statementType * +buildByteStatement(expressionList) + expressionListType *expressionList; +{ + return(newStatement(BYTE_STATEMENT, + (byteStatementBodyType *) expressionList)); +} + + statementType * +buildConstrainStatement(expression, block) + expressionType *expression; + blockType *block; +{ + constrainStatementBodyType *result; + + result = typeAlloc(constrainStatementBodyType); + + result->constraint = expression; + result->constrainedBlock = block; + return(newStatement(CONSTRAIN_STATEMENT, result)); +} + + statementType * +buildDbyteStatement(expressionList) + expressionListType *expressionList; +{ + return(newStatement(DBYTE_STATEMENT, + (dbyteStatementBodyType *) expressionList)); +} + + statementType * +buildDefineStatement(name, value) + stringType *name; + expressionType *value; +{ + defineStatementBodyType *result; + + result = typeAlloc(defineStatementBodyType); + result->theSymbol = lookupOrEnterSymbol(name, UNKNOWN_SYMBOL); + result->theValue = value; + return(newStatement(DEFINE_STATEMENT, result)); +} + + statementType * +buildDoUntilStatement(body, condition) + blockType *body; + conditionType condition; +{ + doUntilStatementBodyType *result; + + result = typeAlloc(doUntilStatementBodyType); + result->doUntilCondition = condition; + result->doUntilLoop = body; + return(newStatement(DO_UNTIL_STATEMENT,result)); +} + + statementType * +buildDoWhileStatement(body, condition) + blockType *body; + conditionType condition; +{ + doWhileStatementBodyType *result; + + result = typeAlloc(doWhileStatementBodyType); + result->doWhileCondition = condition; + result->doWhileLoop = body; + return(newStatement(DO_WHILE_STATEMENT, result)); +} + + statementType * +buildDoStatement(body, end) + blockType *body; + doEndType *end; +{ + statementType *result; + + if (end->doEndKind == UNTIL_END) + result = buildDoUntilStatement(body, end->doEndCondition); + else if (end->doEndKind == WHILE_END) + result = buildDoWhileStatement(body, end->doEndCondition); + else + botch("bad do-end kind: %d\n", end->doEndCondition); + qfree(end); + return(result); +} + + statementType * +buildExternStatement(identifierList) + identifierListType *identifierList; +{ + return(newStatement(EXTERN_STATEMENT, + (externStatementBodyType *) identifierList)); +} + + statementType * +buildFreturnStatement(expression) + expressionType *expression; +{ + return(newStatement(FRETURN_STATEMENT, + (freturnStatementBodyType *) expression)); +} + + statementType * +buildFunctionStatement(name, arguments, body) + stringType *name; + argumentDefinitionListType *arguments; + blockType *body; +{ + functionStatementBodyType *result; + symbolTableEntryType *testSymbol; + + testSymbol = lookupOrEnterSymbol(name, FUNCTION_SYMBOL); + if (testSymbol->context->usage != FUNCTION_SYMBOL && testSymbol-> + context->usage != UNKNOWN_FUNCTION_SYMBOL) { + error(SYMBOL_ALREADY_THERE_ERROR, symbName(testSymbol)); + return(NULL); + } + result = typeAlloc(functionStatementBodyType); + result->functionName = saveString(name); + result->theArguments = arguments; + result->theBlock = body; + return(newStatement(FUNCTION_STATEMENT, result)); +} + + statementType * +buildGroupStatement(block) + blockType *block; +{ + return(newStatement(GROUP_STATEMENT, + (groupStatementBodyType *) block)); +} + + statementType * +buildIfStatement(head, continuation, continuationKind) + ifHeadType *head; + ifContinuationType continuation; + ifContinuationKindType continuationKind; +{ + ifStatementBodyType *result; + + result = typeAlloc(ifStatementBodyType); + + result->ifCondition = head->headCondition; + result->consequence = head->headBody; + if (continuationKind == NO_CONTINUATION) + result->continuation.blockUnion = NULL; + else if (continuationKind == ELSE_CONTINUATION) { + result->continuation.continuationBodyUnion = + typeAlloc(ifContinuationBodyType); + result->continuation.continuationBodyUnion->ifCondition = + ALWAYS_COND; + result->continuation.continuationBodyUnion->consequence = + continuation.blockUnion; + result->continuation.continuationBodyUnion-> + continuation.continuationBodyUnion = NULL; + } else if (continuationKind == ELSEIF_CONTINUATION) + result->continuation = continuation; + else + botch("bad continuation kind: %d\n", continuationKind); + qfree(head); + return(newStatement(IF_STATEMENT, result)); +} + + statementType * +buildIncludeStatement(filename) + expressionType *filename; +{ + return(newStatement(INCLUDE_STATEMENT, + (includeStatementBodyType *) filename)); +} + + statementType * +buildInstructionStatement(opcode, operands) + opcodeTableEntryType *opcode; + operandListType *operands; +{ + instructionStatementBodyType *result; + + result = typeAlloc(instructionStatementBodyType); + result->kindOfInstruction = OPCODE_INSTRUCTION; + result->theInstruction.opcodeUnion = opcode; + result->theOperands = operands; + return(newStatement(INSTRUCTION_STATEMENT, result)); +} + + statementType * +buildLongStatement(expressionList) + expressionListType *expressionList; +{ + return(newStatement(LONG_STATEMENT, + (longStatementBodyType *) expressionList)); +} + + statementType * +buildMacroStatement(macro, arguments, body) + macroTableEntryType *macro; + argumentDefinitionListType *arguments; + blockType *body; +{ + macroStatementBodyType *result; + + result = typeAlloc(macroStatementBodyType); + result->theMacro = macro; + result->theArguments = arguments; + result->theBlock = body; + return(newStatement(MACRO_STATEMENT, result)); +} + + statementType * +buildMacroInstructionStatement(macro, operands) + macroTableEntryType *macro; + operandListType *operands; +{ + instructionStatementBodyType *result; + + result = typeAlloc(instructionStatementBodyType); + result->kindOfInstruction = MACRO_INSTRUCTION; + result->theInstruction.macroUnion = macro; + result->theOperands = operands; + return(newStatement(INSTRUCTION_STATEMENT, result)); +} + + statementType * +buildMdefineStatement(name, value) + stringType *name; + expressionType *value; +{ + mdefineStatementBodyType *result; + + result = typeAlloc(mdefineStatementBodyType); + result->theSymbol = lookupOrEnterSymbol(name, DEAD_SYMBOL); + result->theValue = value; + return(newStatement(MDEFINE_STATEMENT, result)); +} + + statementType * +buildMdoUntilStatement(body, condition) + blockType *body; + ExpressionType *condition; +{ + mdoUntilStatementBodyType *result; + + result = typeAlloc(mdoUntilStatementBodyType); + result->mdoUntilCondition = condition; + result->mdoUntilLoop = body; + return(newStatement(MDO_UNTIL_STATEMENT,result)); +} + + statementType * +buildMdoWhileStatement(body, condition) + blockType *body; + expressionType *condition; +{ + mdoWhileStatementBodyType *result; + + result = typeAlloc(mdoWhileStatementBodyType); + result->mdoWhileCondition = condition; + result->mdoWhileLoop = body; + return(newStatement(MDO_WHILE_STATEMENT, result)); +} + + statementType * +buildMdoStatement(body, end) + blockType *body; + doEndType *end; +{ + statementType *result; + + if (end->doEndKind == UNTIL_END) + result = buildMdoUntilStatement(body, end->doEndCondition); + else if (end->doEndKind == WHILE_END) + result = buildMdoWhileStatement(body, end->doEndCondition); + else + botch("bad mdo-end kind: %d\n", end->doEndCondition); + qfree(end); + return(result); +} + + statementType * +buildMforStatement(forExpressions, body) + forExpressionsType *forExpressions; + blockType *body; +{ + mforStatementBodyType *result; + + result = typeAlloc(mforStatementBodyType); + result->initExpression = forExpressions->initExpression; + result->testExpression = forExpressions->testExpression; + result->incrExpression = forExpressions->incrExpression; + result->forLoop = body; + qfree(forExpressions); + return(newStatement(MFOR_STATEMENT, result)); +} + + statementType * +buildMifStatement(head, continuation, continuationKind) + mifHeadType *head; + mifContinuationType continuation; + ifContinuationKindType continuationKind; +{ + mifStatementBodyType *result; + + result = typeAlloc(mifStatementBodyType); + + result->mifCondition = head->headCondition; + result->mifConsequence = head->headBody; + if (continuationKind == NO_CONTINUATION) + result->mifContinuation.mifContinuationBodyUnion = NULL; + else if (continuationKind == ELSE_CONTINUATION) { + result->mifContinuation.mifContinuationBodyUnion = + typeAlloc(mifContinuationBodyType); + result->mifContinuation.mifContinuationBodyUnion-> + mifCondition = NULL; + result->mifContinuation.mifContinuationBodyUnion-> + mifConsequence = continuation.mifBlockUnion; + result->mifContinuation.mifContinuationBodyUnion-> + mifContinuation.mifContinuationBodyUnion = NULL; + } else if (continuationKind == ELSEIF_CONTINUATION) + result->mifContinuation = continuation; + else + botch("bad mif continuation kind: %d\n", continuationKind); + qfree(head); + return(newStatement(MIF_STATEMENT, result)); +} + + statementType * +buildMswitchStatement(switchExpression, cases) + expressionType *switchExpression; + caseListType *cases; +{ + mswitchStatementBodyType *result; + + result = typeAlloc(mswitchStatementBodyType); + result->switchExpression = switchExpression; + result->cases = cases; + return(newStatement(MSWITCH_STATEMENT, result)); +} + + statementType * +buildMvariableStatement(name, value, dimension) + stringType *name; + expressionListType *value; + expressionType *dimension; +{ + mvariableStatementBodyType *result; + + result = typeAlloc(mvariableStatementBodyType); + result->theSymbol = lookupOrEnterSymbol(name, DEAD_SYMBOL); + result->theValue = value; + result->theDimension = dimension; + return(newStatement(MVARIABLE_STATEMENT, result)); +} + + statementType * +buildMwhileStatement(condition, body) + expressionType *condition; + blockType *body; +{ + mwhileStatementBodyType *result; + + result = typeAlloc(mwhileStatementBodyType); + result->mwhileCondition = condition; + result->mwhileLoop = body; + return(newStatement(MWHILE_STATEMENT, result)); +} + + statementType * +buildNullStatement() +{ + return(newStatement(NULL_STATEMENT, NULL)); +} + + statementType * +buildOrgStatement(expression) + expressionType *expression; +{ + return(newStatement(ORG_STATEMENT, + (orgStatementBodyType *) expression)); +} + + statementType * +buildPerformStatement(expression) + expressionType *expression; +{ + return(newStatement(PERFORM_STATEMENT, + (performStatementBodyType *) expression)); +} + + statementType * +buildRelStatement() +{ + return(newStatement(REL_STATEMENT, NULL)); +} + + statementType * +buildStartStatement(expression) + expressionType *expression; +{ + return(newStatement(START_STATEMENT, + (startStatementBodyType *) expression)); +} + + statementType * +buildStringStatement(expressionList) + expressionListType *expressionList; +{ + return(newStatement(STRING_STATEMENT, + (stringStatementBodyType *) expressionList)); +} + + statementType * +buildStructStatement(name, body) + symbolTableEntryType *name; + blockType *body; +{ + structStatementBodyType *result; + + result = typeAlloc(structStatementBodyType); + result->structBody = body; + result->structName = name; + return(newStatement(STRUCT_STATEMENT, result)); +} + + statementType * +buildTargetStatement(expression) + expressionType *expression; +{ + return(newStatement(TARGET_STATEMENT, + (targetStatementBodyType *) expression)); +} + + statementType * +buildUndefineStatement(identifierList) + identifierListType *identifierList; +{ + return(newStatement(UNDEFINE_STATEMENT, + (undefineStatementBodyType *) identifierList)); +} + + statementType * +buildVariableStatement(name, value, dimension) + stringType *name; + expressionListType *value; + expressionType *dimension; +{ + variableStatementBodyType *result; + + result = typeAlloc(variableStatementBodyType); + result->theSymbol = lookupOrEnterSymbol(name, VARIABLE_SYMBOL); + result->theValue = value; + result->theDimension = dimension; + return(newStatement(VARIABLE_STATEMENT, result)); +} + + statementType * +buildWhileStatement(condition, body) + conditionType condition; + blockType *body; +{ + whileStatementBodyType *result; + + result = typeAlloc(whileStatementBodyType); + result->whileCondition = condition; + result->whileLoop = body; + return(newStatement(WHILE_STATEMENT, result)); +} + + statementType * +buildWordStatement(expressionList) + expressionListType *expressionList; +{ + return(newStatement(WORD_STATEMENT, + (wordStatementBodyType *) expressionList)); +} + diff --git a/buildStuff1.o b/buildStuff1.o new file mode 100644 index 0000000..63fa732 Binary files /dev/null and b/buildStuff1.o differ diff --git a/buildStuff2.c b/buildStuff2.c new file mode 100644 index 0000000..c03b9cc --- /dev/null +++ b/buildStuff2.c @@ -0,0 +1,358 @@ +/* + buildStuff2.c -- More routines to build parse-tree structures for the + Macross assembler. This module is target processor + independent. + + Chip Morningstar -- Lucasfilm Ltd. + + 2-November-1984 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* + These are all the miscellaneous routines for building pieces of parse-tree + structures. + */ + + +/* Fragments of statement structures */ + + caseType * +buildCase(caseTags, caseBody) + expressionListType *caseTags; + blockType *caseBody; +{ + caseType *result; + + result = typeAlloc(caseType); + result->caseTags = caseTags; + result->caseBody = caseBody; + return(result); +} + + doEndType * +buildDoEnd(condition, kindOfDoEnd) + conditionType condition; + doEndKindType kindOfDoEnd; +{ + doEndType *result; + + result = typeAlloc(doEndType); + result->doEndKind = kindOfDoEnd; + result->doEndCondition = condition; + return(result); +} + + forExpressionsType * +buildForExpressions(initExpression, testExpression, incrExpression) + expressionType *initExpression; + expressionType *testExpression; + expressionType *incrExpression; +{ + forExpressionsType *result; + + result = typeAlloc(forExpressionsType); + result->initExpression = initExpression; + result->testExpression = testExpression; + result->incrExpression = incrExpression; + return(result); +} + + ifHeadType * +buildIfHead(condition, block) + conditionType condition; + blockType *block; +{ + ifHeadType *result; + + result = typeAlloc(ifHeadType); + result->headCondition = condition; + result->headBody = block; + return(result); +} + + mdoEndType * +buildMdoEnd(condition, kindOfMdoEnd) + expressionType *condition; + doEndKindType kindOfMdoEnd; +{ + mdoEndType *result; + + result = typeAlloc(mdoEndType); + result->mdoEndKind = kindOfMdoEnd; + result->mdoEndCondition = condition; + return(result); +} + + + mifHeadType * +buildMifHead(condition, block) + expressionType *condition; + blockType *block; +{ + mifHeadType *result; + + result = typeAlloc(mifHeadType); + result->headCondition = condition; + result->headBody = block; + return(result); +} + + +/* Fragments of expression structures */ + + arrayTermType * +buildArrayTerm(array, index) + expressionType *array; + expressionType *index; +{ + arrayTermType *result; + + result = typeAlloc(arrayTermType); + result->arrayName = array; + result->arrayIndex = index; + return(result); +} + + binopTermType * +buildBinopTerm(binop, leftArgument, rightArgument) + binopKindType binop; + expressionType *leftArgument; + expressionType *rightArgument; +{ + binopTermType *result; + + result = typeAlloc(binopTermType); + result->binop = binop; + result->leftArgument = leftArgument; + result->rightArgument = rightArgument; + return(result); +} + + functionCallTermType * +buildFunctionCall(functionName, arguments) + stringType *functionName; + operandListType *arguments; +{ + functionCallTermType *result; + symbolTableEntryType *lookupOrEnterSymbol(); + + result = typeAlloc(functionCallTermType); + result->functionName = lookupOrEnterSymbol(functionName, + UNKNOWN_FUNCTION_SYMBOL); + result->parameters = arguments; + return(result); +} + + postOpTermType * +buildPostOpTerm(postOp, postOpArgument) + postOpKindType postOp; + expressionType *postOpArgument; +{ + postOpTermType *result; + + result = typeAlloc(postOpTermType); + result->postOp = postOp; + result->postOpArgument = postOpArgument; + return(result); +} + + preOpTermType * +buildPreOpTerm(preOp, preOpArgument) + preOpKindType preOp; + expressionType *preOpArgument; +{ + preOpTermType *result; + + result = typeAlloc(preOpTermType); + result->preOp = preOp; + result->preOpArgument = preOpArgument; + return(result); +} + + unopTermType * +buildUnopTerm(unop, unopArgument) + unopKindType unop; + expressionType *unopArgument; +{ + unopTermType *result; + + result = typeAlloc(unopTermType); + result->unop = unop; + result->unopArgument = unopArgument; + return(result); +} + + expressionTermType * +buildExpressionTerm(kindOfExpressionTerm, arg1, arg2, arg3) + expressionTermKindType kindOfExpressionTerm; + anyOldThing *arg1; + anyOldThing *arg2; + anyOldThing *arg3; +{ + expressionType *result; + + symbolTableEntryType *lookupOrEnterSymbol(); + + result = typeAlloc(expressionType); + result->kindOfTerm = kindOfExpressionTerm; + switch (kindOfExpressionTerm) { + + case IDENTIFIER_EXPR: + result->expressionTerm.identifierUnion = + (identifierTermType *) arg1; + break; + + case ARRAY_EXPR: + result->expressionTerm.arrayUnion = + buildArrayTerm((expressionType *) arg1, + (expressionType *) arg2); + break; + + case FUNCTION_CALL_EXPR: + result->expressionTerm.functionCallUnion = + (functionCallTermType *) arg1; + break; + + case NUMBER_EXPR: + result->expressionTerm.numberUnion = (numberTermType) arg1; + break; + + case STRING_EXPR: + result->expressionTerm.stringUnion = (stringTermType *) arg1; + break; + + case SUBEXPRESSION_EXPR: + result->expressionTerm.subexpressionUnion = + (subexpressionTermType *) arg1; + break; + + case UNOP_EXPR: + result->expressionTerm.unopUnion = + buildUnopTerm((unopKindType) arg1, + (expressionType *) arg2); + break; + + case ASSIGN_EXPR: + case BINOP_EXPR: + result->expressionTerm.binopUnion = + buildBinopTerm((binopKindType) arg1, + (expressionType *) arg2, + (expressionType *) arg3); + break; + + case PREOP_EXPR: + result->expressionTerm.preOpUnion = + buildPreOpTerm((preOpKindType) arg1, + (expressionType *) arg2); + break; + + case POSTOP_EXPR: + result->expressionTerm.postOpUnion = + buildPostOpTerm((postOpKindType) arg1, + (expressionType *) arg2); + break; + + case HERE_EXPR: + result->expressionTerm.hereUnion = (hereTermType *) NULL; + break; + + case CONDITION_CODE_EXPR: + result->expressionTerm.conditionCodeUnion = + (conditionCodeTermType) arg1; + break; + + default: + botch("invalid expression term kind: %d\n", + kindOfExpressionTerm); + break; + } + return(result); +} + + +/* Other stuff */ + + macroTableEntryType * +buildMacroTableEntry(name) + stringType *name; +{ + macroTableEntryType *result; + char *saveString(); + + result = typeAlloc(macroTableEntryType); + result->macroName = saveString(name); + result->nextMacro = NULL; + result->arguments = NULL; + result->body = NULL; + return(result); +} + + symbolTableEntryType * +buildSymbolTableEntry(name, usage) + stringType *name; + symbolUsageKindType usage; +{ + symbolTableEntryType *result; + char *saveString(); + + result = typeAlloc(symbolTableEntryType); + result->symbolName = saveString(name); + result->nextSymbol = NULL; + result->context = typeAlloc(symbolInContextType); + result->referenceCount = 0; + dupValue(result->context->value, UndefinedValue); + result->context->attributes = 0; + result->context->referenceCount = 0; + result->context->usage = usage; + result->context->pushedContexts = NULL; + result->context->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; + return(result); +} + + codeBreakType * +buildCodeBreak(kind, address, data) + codeBreakKindType kind; + addressType address; + int data; +{ + codeBreakType *result; + + result = typeAlloc(codeBreakType); + result->kindOfBreak = kind; + result->breakAddress = address; + result->breakData = data; + result->nextBreak = NULL; + return(result); +} + + reservationListType * +buildReservation(startAddress, blockSize, nextReservation) + addressType startAddress; + int blockSize; + reservationListType *nextReservation; +{ + reservationListType *result; + + result = typeAlloc(reservationListType); + result->startAddress = startAddress; + result->blockSize = blockSize; + result->nextReservation = nextReservation; + return(result); +} + + simpleFixupListType * +buildSimpleFixupList(locationToFixup, previousList) + valueType locationToFixup; + simpleFixupListType *previousList; +{ + simpleFixupListType *result; + + result = typeAlloc(simpleFixupListType); + result->locationToFixup = locationToFixup; + result->nextFixup = previousList; + return(result); +} diff --git a/buildStuff2.o b/buildStuff2.o new file mode 100644 index 0000000..a2168c8 Binary files /dev/null and b/buildStuff2.o differ diff --git a/buildStuff3.c b/buildStuff3.c new file mode 100644 index 0000000..cf2bb56 --- /dev/null +++ b/buildStuff3.c @@ -0,0 +1,232 @@ +/* + buildStuff3.c -- Still more routines to build parse-tree structures + for the Macross assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 2-November-1984 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* + These routines all build list-type structures. Since yacc likes to build + things left-recursively but we don't want lists to be backwards (which + would then necessitate reversing them at some point -- yuck), we employ + the ruse of substituting for the first element of a list a different + struct which is identical to a normal one but contains an additional field + for a pointer to the tail element of the list. We can then add things + directly onto the tail as we like. + */ + + argumentListHeadType * +buildArgumentList(new, rest, arrayTag) + stringType *new; + argumentListHeadType *rest; + bool arrayTag; +{ + argumentListHeadType *newListHead; + argumentDefinitionListType *newArgument; + symbolTableEntryType *lookupOrEnterSymbol(); + + if (rest == NULL) { + newListHead = typeAlloc(argumentListHeadType); + newListHead->theArgument = lookupOrEnterSymbol(new, + DEAD_SYMBOL); + newListHead->nextArgument = NULL; + newListHead->tail = NULL; + newListHead->arrayTag = arrayTag; + return(newListHead); + } else { + newArgument = typeAlloc(argumentDefinitionListType); + newArgument->theArgument = lookupOrEnterSymbol(new, + DEAD_SYMBOL); + newArgument->nextArgument = NULL; + if (rest->tail != NULL) + rest->tail->nextArgument = newArgument; + else + rest->nextArgument = newArgument; + rest->tail = newArgument; + rest->arrayTag = arrayTag; + return(rest); + } +} + + caseListHeadType * +buildCaseList(new, rest) + caseType *new; + caseListHeadType *rest; +{ + caseListHeadType *newListHead; + caseListType *newCase; + + if (rest == NULL) { + newListHead = typeAlloc(caseListHeadType); + newListHead->theCase = new; + newListHead->nextCase = NULL; + newListHead->tail = NULL; + return(newListHead); + } else { + newCase = typeAlloc(caseListType); + newCase->theCase = new; + newCase->nextCase = NULL; + if (rest->tail != NULL) + rest->tail->nextCase = newCase; + else + rest->nextCase = newCase; + rest->tail = newCase; + return(rest); + } +} + + expressionListHeadType * +buildExpressionList(new, rest) + expressionType *new; + expressionListHeadType *rest; +{ + expressionListHeadType *newListHead; + expressionListType *newListEntry; + + if (rest == NULL) { + newListHead = typeAlloc(expressionListHeadType); + newListHead->theExpression = new; + newListHead->nextExpression = NULL; + newListHead->tail = NULL; + return(newListHead); + } else { + newListEntry = typeAlloc(expressionListType); + newListEntry->theExpression = new; + newListEntry->nextExpression = NULL; + if (rest->tail != NULL) + rest->tail->nextExpression = newListEntry; + else + rest->nextExpression = newListEntry; + rest->tail = newListEntry; + return(rest); + } +} + + identifierListHeadType * +buildIdentifierList(new, rest, usage) + stringType *new; + identifierListHeadType *rest; + symbolUsageKindType usage; +{ + identifierListType *newListEntry; + identifierListHeadType *newListHead; + + symbolTableEntryType *lookupOrEnterSymbol(); + + if (rest == NULL) { + newListHead = typeAlloc(identifierListHeadType); + newListHead->theSymbol = lookupOrEnterSymbol(new, usage); + newListHead->nextIdentifier = NULL; + newListHead->tail = NULL; + return(newListHead); + } else { + newListEntry = typeAlloc(identifierListType); + newListEntry->theSymbol = lookupOrEnterSymbol(new, usage); + newListEntry->nextIdentifier = NULL; + if (rest->tail != NULL) + rest->tail->nextIdentifier = newListEntry; + else + rest->nextIdentifier = newListEntry; + rest->tail = newListEntry; + return(rest); + } +} + + labelListHeadType * +buildLabelList(new, rest) + symbolTableEntryType *new; + labelListHeadType *rest; +{ + labelListHeadType *newLabelHead; + labelListType *newLabel; + + if (rest == NULL) { + newLabelHead = typeAlloc(labelListHeadType); + newLabelHead->theLabel = new; + newLabelHead->nextLabel = NULL; + newLabelHead->tail = NULL; + return(newLabelHead); + } else { + newLabel = typeAlloc(labelListType); + newLabel->theLabel = new; + newLabel->nextLabel = NULL; + if (rest->tail != NULL) + rest->tail->nextLabel = newLabel; + else + rest->nextLabel = newLabel; + rest->tail = newLabel; + return(rest); + } +} + + operandListHeadType * +buildOperandList(new, rest) + operandType *new; + operandListHeadType *rest; +{ + operandListHeadType *newListHead; + + if (rest == NULL) { + newListHead = typeAlloc(operandListHeadType); + newListHead->kindOfOperand = new->kindOfOperand; + newListHead->theOperand = new->theOperand; + newListHead->nextOperand = NULL; + newListHead->tail = NULL; + qfree(new); + return(newListHead); + } else { + new->nextOperand = NULL; + if (rest->tail != NULL) + rest->tail->nextOperand = new; + else + rest->nextOperand = new; + rest->tail = new; + return(rest); + } +} + + selectionListHeadType * +buildSelectionList(new, rest) + selectionListType *new; + selectionListHeadType *rest; +{ + return((selectionListHeadType *) buildIdentifierList(new, rest)); +} + + statementListHeadType * +buildStatementList(new, rest) + statementType *new; + statementListHeadType *rest; +{ + statementListHeadType *newListHead; + + if (new == NULL) + return(rest); + if (rest == NULL) { + newListHead = typeAlloc(statementListHeadType); + newListHead->kindOfStatement = new->kindOfStatement; + newListHead->labels = new->labels; + newListHead->statementBody = new->statementBody; + newListHead->lineNumber = new->lineNumber; + newListHead->fileName = new->fileName; + newListHead->cumulativeLineNumber = new->cumulativeLineNumber; + newListHead->nextStatement = NULL; + newListHead->tail = NULL; + qfree(new); + return(newListHead); + } else { + new->nextStatement = NULL; + if (rest->tail != NULL) + rest->tail->nextStatement = new; + else + rest->nextStatement = new; + rest->tail = new; + return(rest); + } +} diff --git a/buildStuff3.o b/buildStuff3.o new file mode 100644 index 0000000..ed45f7d Binary files /dev/null and b/buildStuff3.o differ diff --git a/builtInFunctions.c b/builtInFunctions.c new file mode 100644 index 0000000..90c63b5 --- /dev/null +++ b/builtInFunctions.c @@ -0,0 +1,1033 @@ +/* + builtInFunctions.c -- Code for various intrinsic user callable + functions in the Macross assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 11-January-1985 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include + +/* + Helper routines to return values into the Macross expression evaluation + environment + */ + + valueType * +makeBooleanValue(test) + int test; +{ + valueType *newValue(); + + return(newValue(ABSOLUTE_VALUE, test!=0, EXPRESSION_OPND)); +} + + valueType * +makeFailureValue() +{ + valueType *newValue(); + + return(newValue(FAIL, 0, EXPRESSION_OPND)); +} + + valueType * +makeIntegerValue(integer) + int integer; +{ + valueType *newValue(); + + return(newValue(ABSOLUTE_VALUE, integer, EXPRESSION_OPND)); +} + + valueType * +makeOperandValue(operand) + operandType *operand; +{ + valueType *newValue(); + + return(newValue(OPERAND_VALUE, operand, EXPRESSION_OPND)); +} + + valueType * +makeStringValue(string) + stringType *string; +{ + valueType *newValue(); + + return(newValue(STRING_VALUE, string, STRING_OPND)); +} + + valueType * +makeUndefinedValue() +{ + valueType *newValue(); + + return(newValue(UNDEFINED_VALUE, 0, EXPRESSION_OPND)); +} + + +/* + The built-in-functions themselves: pointers to these are loaded into the + values of the predefined Macross symbols denoting them at assembly + initialization time from the built-in-function table. Each symbol of the + form "xxx" is assigned a pointer to "xxxBIF" (BIF == Built-In-Function). + */ + +/* Return internal address mode of an operand */ + valueType * +addressModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeIntegerValue(evaluatedParameter->addressMode)); + } else { + return(makeIntegerValue(-1)); + } +} + +/* Call a macro where the macro name is obtained dynamically from a string */ + valueType * +applyBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *stringValue; + stringType *macroToLookup; + macroTableEntryType *macroToCall; + + macroTableEntryType *lookupMacroName(); + valueType *evaluateOperand(); + + if (parameterList == NULL) { + error(NO_ARGUMENTS_TO_BIF_ERROR, "apply"); + return(makeFailureValue()); + } + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, "apply"); + return(makeFailureValue()); + } + macroToLookup = (stringType *)stringValue->value; + if ((macroToCall = lookupMacroName(macroToLookup, + hashString(macroToLookup))) == 0) { + error(APPLY_ARGUMENT_IS_NOT_MACRO_ERROR, macroToLookup); + return(makeFailureValue()); + } + assembleMacro(macroToCall, parameterList->nextOperand); + return(makeBooleanValue(TRUE)); +} + +/* return the length of an array */ + valueType * +arrayLengthBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *testObjectValue; + valueType *evaluateOperand(); + + if (parameterList == NULL) + return(makeIntegerValue(0)); + testObjectValue = evaluateOperand(parameterList, NO_FIXUP_OK); + if (testObjectValue->kindOfValue == STRING_VALUE) { + return(makeIntegerValue(strlen(testObjectValue->value))); + } else if (testObjectValue->kindOfValue == ARRAY_VALUE) { + return(makeIntegerValue(((arrayType *)(testObjectValue-> + value))->arraySize)); + } else { + return(makeIntegerValue(0)); + } +} + +/* The two ATASCII related BIF's refer to this table -- This really only + makes sense for the 6502 version, but is harmless in other versions. */ +static char atasciiTable[] = { /* 0xFFs will become 0x00s on output */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0xFF, +}; + +/* Convert a string to ATASCII */ + valueType * +atasciiBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + int i; + valueType *stringValue; + stringType *string; + stringType *newString; + + valueType *evaluateOperand(); + + if (parameterList == NULL) + return(makeStringValue("")); + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, "atascii"); + return(makeFailureValue()); + } + string = (stringType *)stringValue->value; + newString = (stringType *)malloc(strlen(string)+1); + for (i=0; string[i]!='\0'; i++) + newString[i] = atasciiTable[string[i]]; + newString[i] = '\0'; + return(makeStringValue(newString)); +} + +/* Convert a string to ATASCII while setting high-order color bits */ + valueType * +atasciiColorBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + int i; + valueType *stringValue; + stringType *string; + valueType *colorValue; + int color; + stringType *newString; + byte testChar; + + valueType *evaluateOperand(); + + if (parameterList == NULL) + return(makeStringValue("")); + stringValue = evaluateOperand(parameterList, NO_FIXUP); + parameterList = parameterList->nextOperand; + if (parameterList == NULL) { + color = 0; + } else { + colorValue = evaluateOperand(parameterList, NO_FIXUP); + if (colorValue->kindOfValue != ABSOLUTE_VALUE) { + error(BAD_COLOR_ARGUMENT_TO_ATASCII_COLOR_ERROR); + return(makeFailureValue()); + } + color = colorValue->value; + } + color = (color & 0x03) << 6; + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, "atasciiColor"); + return(makeFailureValue()); + } + string = (stringType *)stringValue->value; + newString = (stringType *)malloc(strlen(string)+1); + for (i=0; string[i]!='\0'; i++) { + testChar = atasciiTable[string[i]]; + if (testChar == 0xFF) + testChar = 0; + testChar = (testChar & 0x3F) | color; + if (testChar == 0) + testChar = 0xFF; + newString[i] = testChar; + } + newString[i] = '\0'; + return(makeStringValue(newString)); +} + +/* Turn debug mode off and on */ + valueType * +debugModeOffBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + debug = FALSE; + return(makeBooleanValue(FALSE)); +} + + valueType * +debugModeOnBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + debug = TRUE; + return(makeBooleanValue(TRUE)); +} + +/* Turn display of code emission off and on */ + valueType * +emitModeOffBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + emitPrint = FALSE; + return(makeBooleanValue(FALSE)); +} + + valueType * +emitModeOnBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + emitPrint = TRUE; + return(makeBooleanValue(TRUE)); +} + +/* Check if an operand is absolute (as opposed to relocatable) */ + valueType * +isAbsoluteValueBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + ABSOLUTE_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is code block */ + valueType * +isBlockBIF(parameterList, kindOfFixup) /* questionable */ + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + BLOCK_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is a BIF */ + valueType * +isBuiltInFunctionBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + BUILT_IN_FUNCTION_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is a condition code */ + valueType * +isConditionCodeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + CONDITION_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if a symbol is defined */ + valueType * +isDefinedBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + expressionType *expression; + symbolInContextType *context; + + symbolInContextType *getWorkingContext(); + symbolTableEntryType *effectiveSymbol(); + + if (parameterList != NULL) { + if (parameterList->kindOfOperand == EXPRESSION_OPND && + (expression = parameterList->theOperand. + expressionUnion) != NULL && expression-> + kindOfTerm == IDENTIFIER_EXPR && + effectiveSymbol(expression->expressionTerm. + identifierUnion, &context) != NULL && + context != NULL && (context->value-> + kindOfValue == UNDEFINED_VALUE || context-> + value->kindOfValue == FAIL)) { + if ((context->usage == UNKNOWN_SYMBOL || context-> + usage == NESTED_UNKNOWN_SYMBOL) && + context->referenceCount == 0) + context->usage = DEAD_SYMBOL; + return(makeBooleanValue(FALSE)); + } else { + return(makeBooleanValue(TRUE)); + } + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if a symbol is externally visible */ + valueType * +isExternalBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + expressionType *expression; + symbolInContextType *context; + + symbolInContextType *getWorkingContext(); + + if (parameterList != NULL && parameterList->kindOfOperand == + EXPRESSION_OPND) { + expression = parameterList->theOperand.expressionUnion; + return(makeBooleanValue(expression->kindOfTerm == + IDENTIFIER_EXPR && (context = getWorkingContext( + expression->expressionTerm.identifierUnion))!=NULL && + (context->attributes & GLOBAL_ATT)!=0)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand is a struct field */ + valueType * +isFieldBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + FIELD_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand is a user-defined function */ + valueType * +isFunctionBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + FUNCTION_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand value is relocatable */ + valueType * +isRelocatableValueBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + RELOCATABLE_VALUE || evaluatedParameter-> + kindOfValue == DATA_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand is a string */ + valueType * +isStringBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + STRING_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand is a struct */ + valueType * +isStructBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->kindOfValue == + STRUCT_VALUE)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand is a symbol */ + valueType * +isSymbolBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + expressionType *expression; + + if (parameterList != NULL && parameterList->kindOfOperand == + EXPRESSION_OPND) { + expression = parameterList->theOperand.expressionUnion; + return(makeBooleanValue(expression->kindOfTerm == + IDENTIFIER_EXPR)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Turn listing off and on */ + valueType * +listingOffBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + if (listingOn) { + if (!listingControlCounter) + saveListingOff(); + listingControlCounter++; + } + return(makeBooleanValue(FALSE)); +} + + valueType * +listingOnBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + if (listingOn) { + if (--listingControlCounter < 0) { + listingControlCounter = 0; + return(makeBooleanValue(TRUE)); + } else if (listingControlCounter) { + return(makeBooleanValue(FALSE)); + } else { + saveListingOn(); + return(makeBooleanValue(TRUE)); + } + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Generate an array on the fly */ + valueType * +makeArrayBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *lengthValue; + int length; + valueType *result; + valueType **arrayContents; + int i; + + if (parameterList == NULL) { + error(NO_ARGUMENTS_TO_BIF_ERROR, "makeArray"); + return(makeFailureValue()); + } + lengthValue = evaluateOperand(parameterList, NO_FIXUP); + if (lengthValue->kindOfValue != ABSOLUTE_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_ABSOLUTE_VALUE_ERROR, + "makeArray", 1); + return(makeFailureValue()); + } else if (lengthValue->value < 0) { + error(NEGATIVE_ARRAY_SIZE_TO_MAKEARRAY_ERROR); + return(makeFailureValue()); + } + length = lengthValue->value; + result = newValue(ARRAY_VALUE, allocArray(length, &arrayContents), + EXPRESSION_OPND); + parameterList = parameterList->nextOperand; + for (i=0; inextOperand; + } else { + arrayContents[i] = NULL; + } + } + if (parameterList != NULL) { + error(TOO_MANY_INITIALIZATION_ARGS_TO_MAKEARRAY_ERROR); + return(makeFailureValue()); + } + return(result); +} + +/* Return the Nth character of a string (as an integer) */ + valueType * +nthCharBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *positionValue; + int position; + valueType *stringValue; + stringType *string; + + valueType *evaluateOperand(); + + if (parameterList == NULL) + return(makeFailureValue()); + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, "nthChar"); + return(makeFailureValue()); + } + parameterList = parameterList->nextOperand; + if (parameterList == NULL) { + position = 0; + } else { + positionValue = evaluateOperand(parameterList, NO_FIXUP); + if (positionValue->kindOfValue != ABSOLUTE_VALUE) { + error(BAD_POSITION_ARGUMENT_TO_NTH_CHAR_ERROR); + return(makeFailureValue()); + } + position = positionValue->value; + } + + string = (stringType *)stringValue->value; + if (position >= strlen(string)) { + error(BAD_POSITION_ARGUMENT_TO_NTH_CHAR_ERROR); + return(makeFailureValue()); + } + return(makeIntegerValue(string[position])); +} + +/* Pass stuff through to stdio's 'printf' function */ + valueType * +printfBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + stringType *formatString; + valueType *stringValue; + int argumentCount; + int argument[20]; + valueType *result; + + valueType *evaluateOperand(); + + result = makeFailureValue(); + if (parameterList != NULL) { + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(PRINTF_FORMAT_IS_NOT_A_STRING_ERROR); + return(result); + } + formatString = (stringType *)stringValue->value; + parameterList = parameterList->nextOperand; + argumentCount = 0; + while (parameterList != NULL && argumentCount < 20) { + argument[argumentCount++] = evaluateOperand( + parameterList)->value; + parameterList = parameterList->nextOperand; + } + /* cretinous hack */ + printf(formatString, argument[0], argument[1], argument[2], + argument[3], argument[4], argument[5], argument[6], + argument[7], argument[8], argument[9], argument[10], + argument[11], argument[12], argument[13], + argument[14], argument[15], argument[16], + argument[17], argument[18], argument[19]); + } + return(result); +} + +/* Concatenate two strings */ + valueType * +strcatBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *stringValue; + stringType *string1; + stringType *string2; + stringType *newString; + + if (parameterList == NULL) + return(makeStringValue("")); + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_A_STRING_ERROR, "strcat", 1); + return(makeFailureValue()); + } + string1 = (stringType *)stringValue->value; + parameterList = parameterList->nextOperand; + if (parameterList == NULL) + return(makeStringValue(string1)); + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_A_STRING_ERROR, "strcat", 2); + return(makeFailureValue()); + } + string2 = (stringType *)stringValue->value; + newString = (stringType *)malloc(strlen(string1)+strlen(string2)+1); + strcpy(newString, string1); + strcat(newString, string2); + return(makeStringValue(newString)); +} + +/* Compare two strings */ + valueType * +strcmpBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *stringValue; + stringType *string1; + stringType *string2; + stringType *newString; + + if (parameterList == NULL) { + error(NO_ARGUMENTS_TO_BIF_ERROR, "strcmp"); + return(makeFailureValue()); + } + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_A_STRING_ERROR, "strcmp", 1); + return(makeFailureValue()); + } + string1 = (stringType *)stringValue->value; + parameterList = parameterList->nextOperand; + if (parameterList == NULL) + return(makeStringValue(string1)); + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_A_STRING_ERROR, "strcmp", 2); + return(makeFailureValue()); + } + string2 = (stringType *)stringValue->value; + return(makeIntegerValue(strcmp(string1, string2))); +} + +/* Compare two strings in a case-independent fashion */ + valueType * +strcmplcBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *stringValue; + stringType *string1; + stringType *string2; + stringType *newString; + + if (parameterList == NULL) { + error(NO_ARGUMENTS_TO_BIF_ERROR, "strcmplc"); + return(makeFailureValue()); + } + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_A_STRING_ERROR, "strcmplc", 1); + return(makeFailureValue()); + } + string1 = (stringType *)stringValue->value; + parameterList = parameterList->nextOperand; + if (parameterList == NULL) + return(makeStringValue(string1)); + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_A_STRING_ERROR, "strcmplc", 2); + return(makeFailureValue()); + } + string2 = (stringType *)stringValue->value; + return(makeIntegerValue(strcmplc(string1, string2))); +} + +/* Return the length of a string */ + valueType * +strlenBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *stringValue; + + if (parameterList == NULL) + return(makeIntegerValue(-1)); + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, "strlen"); + return(makeFailureValue()); + } else + return(makeIntegerValue(strlen(stringValue->value))); +} + +/* Return a substring of a string */ + valueType * +substrBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *stringValue; + stringType *string; + valueType *startValue; + int start; + valueType *lengthValue; + int length; + stringType *newString; + int originalLength; + bool backwards; + + if (parameterList == NULL) { + error(NO_ARGUMENTS_TO_BIF_ERROR, "substr"); + return(makeFailureValue()); + } + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, "substr"); + return(makeFailureValue()); + } + string = (stringType *)stringValue->value; + originalLength = strlen(string); + + parameterList = parameterList->nextOperand; + if (parameterList == NULL) { + error(TOO_FEW_ARGUMENTS_TO_BIF_ERROR, "substr"); + return(makeFailureValue()); + } + startValue = evaluateOperand(parameterList, NO_FIXUP); + if (startValue->kindOfValue != ABSOLUTE_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_ABSOLUTE_VALUE_ERROR, "substr", + 2); + return(makeFailureValue()); + } + start = startValue->value; + if (start < 0) { + start = -start - 1; + backwards = TRUE; + } else + backwards = FALSE; + + parameterList = parameterList->nextOperand; + if (parameterList == NULL) { + length = originalLength - start; + if (backwards) + length = -length; + } else { + lengthValue = evaluateOperand(parameterList, NO_FIXUP); + if (lengthValue->kindOfValue != ABSOLUTE_VALUE) { + error(BIF_NTH_ARGUMENT_IS_NOT_ABSOLUTE_VALUE_ERROR, + "substr", 3); + return(makeFailureValue()); + } + length = lengthValue->value; + } + if (length < 0) { + length = -length; + if (backwards) + start = start + length - 1; + else + start = start - length + 1; + } + if (backwards) + start = originalLength - start - 1; + if (originalLength <= start || originalLength < length + start || + start < 0 ){ + error(BAD_SUBSTRING_INDICES_ERROR); + return(makeFailureValue()); + } + newString = (stringType *)malloc(length+1); + strncpy(newString, string+start, length); + newString[length] = '\0'; + return(makeStringValue(newString)); +} + +/* Turn a string into a symbol */ + valueType * +symbolLookupBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *stringValue; + stringType *identifierToLookup; + + expressionTermType *buildExpressionTerm(); + operandType *buildOperand(); + valueType *evaluateIdentifier(); + + if (parameterList == NULL) { + error(NO_ARGUMENTS_TO_BIF_ERROR, "symbolLookup"); + return(makeFailureValue()); + } + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, "symbolLookup"); + return(makeFailureValue()); + } + identifierToLookup = (stringType *)stringValue->value; + return(evaluateIdentifier(lookupOrEnterSymbol(identifierToLookup, + UNKNOWN_SYMBOL), FALSE, kindOfFixup)); +} + +/* Define a string as a symbol */ + valueType * +symbolDefineBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *stringValue; + statementType *syntheticDefineStatement; + statementType *buildDefineStatement(); + + if (parameterList == NULL) { + error(NO_ARGUMENTS_TO_BIF_ERROR, "symbolDefine"); + return(makeFailureValue()); + } + stringValue = evaluateOperand(parameterList, NO_FIXUP); + if (stringValue->kindOfValue != STRING_VALUE) { + error(BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, "symbolDefine"); + return(makeFailureValue()); + } + parameterList = parameterList->nextOperand; + if (parameterList == NULL) { + syntheticDefineStatement = buildDefineStatement(stringValue-> + value, NULL); + } else if (parameterList->kindOfOperand != EXPRESSION_OPND) { + error(SYMBOL_DEFINE_VALUE_NOT_EXPRESSION_OPND_ERROR); + return(makeFailureValue()); + } else { + syntheticDefineStatement = buildDefineStatement(stringValue-> + value, parameterList->theOperand); + } + assembleDefineStatement(syntheticDefineStatement->statementBody); + freeStatement(syntheticDefineStatement); + return(makeBooleanValue(TRUE)); +} + +/* Turn a symbol into a string */ + valueType * +symbolNameBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + expressionType *expression; + symbolInContextType *context; + environmentType *saveEnvironment; + + symbolInContextType *getWorkingContext(); + + saveEnvironment = currentEnvironment; + while (parameterList != NULL && parameterList->kindOfOperand == + EXPRESSION_OPND) { + expression = parameterList->theOperand.expressionUnion; + if (expression->kindOfTerm == IDENTIFIER_EXPR && (context = + getWorkingContext(expression->expressionTerm. + identifierUnion)) != NULL) { + if (context->value->kindOfValue != OPERAND_VALUE || + context->usage != ARGUMENT_SYMBOL) { + currentEnvironment = saveEnvironment; + return(makeStringValue(symbName(expression-> + expressionTerm.identifierUnion))); + } else { + currentEnvironment = currentEnvironment-> + previousEnvironment; + parameterList = (operandListType *)context-> + value->value; + } + } else { + break; + } + } + currentEnvironment = saveEnvironment; + error(CANT_FIND_SYMBOL_ERROR); + return(makeStringValue("")); +} + +/* Return internal form of what sort of symbol a symbol is */ + valueType * +symbolUsageBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + expressionType *expression; + symbolInContextType *context; + + symbolInContextType *getWorkingContext(); + + if (parameterList != NULL && parameterList->kindOfOperand == + EXPRESSION_OPND) { + expression = parameterList->theOperand.expressionUnion; + if (expression->kindOfTerm == IDENTIFIER_EXPR && (context = + getWorkingContext(expression->expressionTerm. + identifierUnion))!=NULL) + return(makeIntegerValue(context->usage)); + } + return(makeIntegerValue(-1)); +} + +/* Return internal form of what sort of value a value is */ + valueType * +valueTypeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeIntegerValue(evaluatedParameter->kindOfValue)); + } else { + return(makeIntegerValue(-1)); + } +} + diff --git a/builtInFunctions.o b/builtInFunctions.o new file mode 100644 index 0000000..b81a0a4 Binary files /dev/null and b/builtInFunctions.o differ diff --git a/builtInFunsSD.o b/builtInFunsSD.o new file mode 100644 index 0000000..191a3c9 Binary files /dev/null and b/builtInFunsSD.o differ diff --git a/builtInFunsSD_6502.c b/builtInFunsSD_6502.c new file mode 100644 index 0000000..db515b3 --- /dev/null +++ b/builtInFunsSD_6502.c @@ -0,0 +1,237 @@ +/* + builtInFunsSD_6502.c -- Code for target-processor dependent + intrinsic user callable functions in the Macross assembler. + (6502 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 23-April-1985 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* Helper functions, defined in builtInFunctions.c */ +valueType *makeBooleanValue(); +valueType *makeFailureValue(); +valueType *makeIntegerValue(); +valueType *makeOperandValue(); +valueType *makeStringValue(); +valueType *makeUndefinedValue(); + + +/* Check if operand is the accumulator */ + valueType * +isARegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + A_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is DIRECT */ + valueType * +isDirectModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + EXPRESSION_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is IMMEDIATE */ + valueType * +isImmediateModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + IMMEDIATE_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is INDEXED (either X or Y) */ + valueType * +isIndexedModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + X_INDEXED_OPND || evaluatedParameter->addressMode == + Y_INDEXED_OPND || evaluatedParameter->addressMode == + X_SELECTED_OPND || evaluatedParameter->addressMode == + Y_SELECTED_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is INDIRECT */ + valueType * +isIndirectModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + INDIRECT_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is POST-INDEXED */ + valueType * +isPostIndexedModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + POST_INDEXED_Y_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is PRE-INDEXED */ + valueType * +isPreIndexedModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + PRE_INDEXED_X_OPND || evaluatedParameter-> + addressMode == PRE_SELECTED_X_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is X-INDEXED */ + valueType * +isXIndexedModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + X_INDEXED_OPND || evaluatedParameter->addressMode == + X_SELECTED_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand is the X index register */ + valueType * +isXRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + X_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is Y-INDEXED */ + valueType * +isYIndexedModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + Y_INDEXED_OPND || evaluatedParameter->addressMode == + Y_SELECTED_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand is the Y index register */ + valueType * +isYRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(evaluatedParameter->addressMode == + Y_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} diff --git a/builtInFunsSD_68000.c b/builtInFunsSD_68000.c new file mode 100644 index 0000000..3f67a39 --- /dev/null +++ b/builtInFunsSD_68000.c @@ -0,0 +1,505 @@ +/* + builtInFunsSD_68000.c -- Code for target-processor dependent + intrinsic user callable functions in the Macross assembler. + (68000 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 26-April-1985 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* Helper functions, defined in builtInFunctions.c */ +valueType *makeBooleanValue(); +valueType *makeFailureValue(); +valueType *makeIntegerValue(); +valueType *makeOperandValue(); +valueType *makeStringValue(); +valueType *makeUndefinedValue(); + + +/* Get address register component of operand */ + valueType * +getAddressRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeIntegerValue(getAddressRegister( + evaluatedParameter->addressMode))); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Get data register component of operand */ + valueType * +getDataRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeIntegerValue(getDataRegister(evaluatedParameter-> + addressMode))); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Get index register component of operand */ + valueType * +getIndexRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeIntegerValue(getIndexRegister(evaluatedParameter-> + addressMode))); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Get register component of operand */ + valueType * +getRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeIntegerValue(getRegister(evaluatedParameter-> + addressMode))); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Get word/long component of operand */ + valueType * +getWLBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeIntegerValue(getWL(evaluatedParameter-> + addressMode))); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is absolute */ + valueType * +isAbsoluteModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == ABSOLUTE_SHORT_OPND || + operandKindField(evaluatedParameter->addressMode) == + ABSOLUTE_LONG_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is absolute long */ + valueType * +isAbsoluteLongModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == ABSOLUTE_LONG_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is absolute short */ + valueType * +isAbsoluteShortModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == ABSOLUTE_SHORT_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is an address register */ + valueType * +isARegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == A_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is the condition code register */ + valueType * +isCCRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == CC_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is a control register */ + valueType * +isControlRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == CONTROL_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is a data register */ + valueType * +isDRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == D_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is DFC register */ + valueType * +isDFCRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == CONTROL_REGISTER_OPND && + getRegister(evaluatedParameter->addressMode) == + DFC_REGISTER)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is displacement */ + valueType * +isDisplacementModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == DISPLACEMENT_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is IMMEDIATE */ + valueType * +isImmediateModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == IMMEDIATE_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is indexed */ + valueType * +isIndexedModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == INDEXED_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is indirect */ + valueType * +isIndirectModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == A_REGISTER_INDIRECT_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is pc displacement */ + valueType * +isPCDisplacementModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == PC_DISPLACEMENT_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is pc indexed */ + valueType * +isPCIndexedModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == PC_INDEXED_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is postincrement */ + valueType * +isPostincrementModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == POSTINCREMENT_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if an operand's address mode is predecrement */ + valueType * +isPredecrementModeBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == PREDECREMENT_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is SFC register */ + valueType * +isSFCRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == CONTROL_REGISTER_OPND && + getRegister(evaluatedParameter->addressMode) == + SFC_REGISTER)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is the status register */ + valueType * +isStatusRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == STATUS_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is user stack pointer */ + valueType * +isUSPBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == USP_REGISTER_OPND)); + } else { + return(makeBooleanValue(FALSE)); + } +} + +/* Check if operand is VB register */ + valueType * +isVBRegisterBIF(parameterList, kindOfFixup) + operandListType *parameterList; + fixupKindType kindOfFixup; +{ + valueType *evaluatedParameter; + + valueType *evaluateOperand(); + + if (parameterList != NULL) { + evaluatedParameter = evaluateOperand(parameterList, NO_FIXUP); + return(makeBooleanValue(operandKindField(evaluatedParameter-> + addressMode) == CONTROL_REGISTER_OPND && + getRegister(evaluatedParameter->addressMode) == + VBR_REGISTER)); + } else { + return(makeBooleanValue(FALSE)); + } +} diff --git a/conditionDefs_6502.h b/conditionDefs_6502.h new file mode 100644 index 0000000..602abd1 --- /dev/null +++ b/conditionDefs_6502.h @@ -0,0 +1,19 @@ +/* + conditionDefs_6502.h -- Define types for 6502 branch condition codes. + + Chip Morningstar -- Lucasfilm Ltd. + + 18-April-1985 +*/ + +typedef enum { + CARRY_COND, ZERO_COND, NEGATIVE_COND, OVERFLOW_COND, LT_COND, + LEQ_COND, SLT_COND, SLEQ_COND, + ALWAYS_COND, + NOT_CARRY_COND, NOT_ZERO_COND, NOT_NEGATIVE_COND, + NOT_OVERFLOW_COND, GEQ_COND, GT_COND, SGEQ_COND, SGT_COND, + NEVER_COND, + NOT_FOUND_COND, + } conditionType; + +#define COMPOUND_BRANCH_MAX 3 diff --git a/conditionDefs_68000.h b/conditionDefs_68000.h new file mode 100644 index 0000000..e83b7a2 --- /dev/null +++ b/conditionDefs_68000.h @@ -0,0 +1,20 @@ +/* + conditionDefs_68000.h -- Define types for 68000 condition codes. + + Chip Morningstar -- Lucasfilm Ltd. + + 25-April-1985 +*/ + +typedef enum { + CARRY_COND, EQUAL_COND, OVERFLOW_COND, MINUS_COND, LT_COND, + LEQ_COND, LOW_OR_SAME_COND, + ALWAYS_COND, + NOT_CARRY_COND, NOT_EQUAL_COND, NOT_OVERFLOW_COND, PLUS_COND, + GEQ_COND, GT_COND, HIGH_COND, + NEVER_COND, + NOT_FOUND_COND, + } conditionType; + +#define COMPOUND_BRANCH_MAX 1 + diff --git a/debugPrint.c b/debugPrint.c new file mode 100644 index 0000000..630252a --- /dev/null +++ b/debugPrint.c @@ -0,0 +1,1200 @@ +/* + debugPrint.c -- Routines to print out things for debugging purposes. + + Chip Morningstar -- Lucasfilm Ltd. + + 5-November-1984 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" + +/* + Print out the parse-tree. + */ + +int tablevel = 0; + +/* Fundamental nop print operation */ +#define nullPrint(thing) if (thing==NULL) { tab(); printf("()\n"); return; } + +/* For keeping nested structures looking pretty */ + void +tab() +{ + int n; + + n = tablevel; + while (n-- > 0) + printf(" "); +} + +/* + The following routines print readable strings for the values of various + enumerated types and pre-defined constants. Each contains a static table + of strings that must be kept consistent with the type or set of + definitions that it represents. + */ + + void +printAssignmentKind(assignmentKind) + assignmentKindType assignmentKind; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'assignmentKindType'. */ + static char *assignmentTable[] = { + "ASSIGN_ASSIGN", + "ADD_ASSIGN", + "SUB_ASSIGN", + "MUL_ASSIGN", + "DIV_ASSIGN", + "MOD_ASSIGN", + "AND_ASSIGN", + "OR_ASSIGN", + "XOR_ASSIGN", + "LEFT_SHIFT_ASSIGN", + "RIGHT_SHIFT_ASSIGN", + "NO_ASSIGN", + }; + + printf("%s", assignmentTable[(int)assignmentKind]); +} + + void +printExpressionKind(kind) + expressionTermKindType kind; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'expressionTermKindType'. */ + static char *expressionKindTable[] = { + "identifier expr", + "function call expr", + "number expr", + "subexpression", + "unop expr", + "binop expr", + "preop expr", + "postop expr", + "here", + "assignment expr", + "condition code expr", + "string expr", + "value", + "array expr", + }; + + printf("%s", expressionKindTable[(int)kind]); +} + + stringType * +statementKindString(kind) + statementKindType kind; +{ +/* This table MUST be maintained congruently with the definition of + the enumerated type 'statementKindType'. */ +static char *statementKindTable[] = { + "if", + "while", + "do_while", + "do_until", + "word", + "dbyte", + "byte", + "string", + "struct", + "instruction", + "define", + "undefine", + "mif", + "freturn", + "mfor", + "mdo_while", + "mdo_until", + "include", + "extern", + "start", + "align", + "org", + "rel", + "perform", + "block", + "mwhile", + "mdefine", + "null", + "group", + "macro", + "function", + "variable", + "mvariable", + "constrain", + "assert", + "mswitch", + "long", + "target", + }; + return(statementKindTable[(int)kind]); +} + + void +printStatementKind(kind) + statementKindType kind; +{ + printf("%s", statementKindString(kind)); +} + + +/* + These routines collectively print expressions and values. + */ + + void +printValue(value) + valueType *value; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'valueKindType'. */ + static char *valueKindTable[NUM_OF_VALUE_KINDS] = { + "ABSOLUTE_VALUE", + "DATA_VALUE", + "RELOCATABLE_VALUE", + "BSS_VALUE", + "STRUCT_VALUE", + "FIELD_VALUE", + "MACRO_VALUE", + "OPERAND_VALUE", + "STRING_VALUE", + "CONDITION_VALUE", + "UNDEFINED_VALUE", + "FUNCTION_VALUE", + "BLOCK_VALUE", + "BUILT_IN_FUNCTION_VALUE", + "ARRAY_VALUE", + "FAIL", + }; + + if (value != NULL) { + printf("(%s: %d==0x%x ", valueKindTable[(int)value-> + kindOfValue], value->value, value->value); + printOperandKind(value->addressMode); + printf(")"); + } else + printf("(no value)"); +} + + void +printSymbol(symbol) + symbolTableEntryType *symbol; +{ +/* This table MUST be maintained congruent with the definition of the + enumerated type 'symbolUsageKindType'. */ + static char *symbolUsageTable[] = { + "STRUCT_NAME_SYMBOL", + "STRUCT_FIELD_SYMBOL", + "MACRO_SYMBOL", + "ARGUMENT_SYMBOL", + "LABEL_SYMBOL", + "EXTERNAL_SYMBOL", + "VARIABLE_SYMBOL", + "MVARIABLE_SYMBOL", + "UNKNOWN_SYMBOL", + "DEAD_SYMBOL", + "FUNCTION_SYMBOL", + "BUILT_IN_FUNCTION_SYMBOL", + "NESTED_UNKNOWN_SYMBOL", + "DEFINE_SYMBOL", + "MDEFINE_SYMBOL", + "UNKNOWN_FUNCTION_SYMBOL", + "UNKNOWN_MACRO_SYMBOL", + }; + + nullPrint(symbol); + tab(); printf("(symbol: %s ", symbol->symbolName); + printValue(symbol->context->value); + printf(" %d %s", symbol->context->attributes, + symbolUsageTable[(int)symbol->context->usage]); + if (symbol->context->pushedContexts != NULL) + printf(" ..."); + printf(")\n"); +} + + void +printArgumentDefinitionList(list) + argumentDefinitionListType *list; +{ + nullPrint(list); + tab(); printf("(arguments:\n"); + tablevel++; + while (list != NULL) { + printSymbol(list->theArgument); + list = list->nextArgument; + } + tablevel--; + tab(); printf(")\n"); +} + + void +printBlock(block) + blockType *block; +{ + void printStatement(); + + nullPrint(block); + tab(); printf("(block:\n"); + tablevel++; + printStatement(block); + tablevel--; + tab(); printf(")\n"); +} + + void +printArrayTerm(arrayTerm) + arrayTermType *arrayTerm; +{ + void printIdentifier(); + void printExpression(); + + nullPrint(arrayTerm); + tab(); printf("(array\n"); + tablevel++; + printExpression(arrayTerm->arrayName); + printExpression(arrayTerm->arrayIndex); + tablevel--; + tab(); printf(")\n"); +} + + void +printAssignmentTerm(assignmentTerm) + binopTermType *assignmentTerm; +{ + void printExpression(); + + nullPrint(assignmentTerm); + tab(); printf("(assignment ["); + printAssignmentKind(assignmentTerm->binop); + printf("]\n"); + tablevel++; + printExpression(assignmentTerm->leftArgument); + printExpression(assignmentTerm->rightArgument); + tablevel--; + tab(); printf(")\n"); +} + + void +printBinopTerm(binopTerm) + binopTermType *binopTerm; +{ + void printIdentifier(); + void printExpression(); + + nullPrint(binopTerm); + tab(); printf("(binop ["); + printToken(binopTerm->binop); + printf("]\n"); + tablevel++; + printExpression(binopTerm->leftArgument); + if (binopTerm->binop == SELECT) + printIdentifier(binopTerm->rightArgument); + else + printExpression(binopTerm->rightArgument); + tablevel--; + tab(); printf(")\n"); +} + + void +printFunctionCall(functionCall) + functionCallTermType *functionCall; +{ + void printOperandList(); + + nullPrint(functionCall); + tab(); printf("(function call %s\n", functionCall->functionName-> + symbolName); + tablevel++; + printOperandList(functionCall->parameters); + tablevel--; + tab(); printf(")\n"); +} + + void +printHere() +{ + tab(); printf("(here)\n"); +} + + void +printIdentifier(identifier) + symbolTableEntryType *identifier; +{ + nullPrint(identifier); + printSymbol(identifier); +} + + void +printNumber(number) + numberTermType number; +{ + tab(); printf("(number: %d)\n", number); +} + + void +printPostopTerm(postopTerm) + postOpTermType *postopTerm; +{ + nullPrint(postopTerm); + tab(); printf("(postop ["); + printToken(postopTerm->postOp); + printf("]\n"); + tablevel++; + printExpression(postopTerm->postOpArgument); + tablevel--; + tab(); printf(")\n"); +} + + void +printPreopTerm(preopTerm) + preOpTermType *preopTerm; +{ + nullPrint(preopTerm); + tab(); printf("(preop ["); + printToken(preopTerm->preOp); + printf("]\n"); + tablevel++; + printExpression(preopTerm->preOpArgument); + tablevel--; + tab(); printf(")\n"); +} + + void +printUnopTerm(unopTerm) + unopTermType *unopTerm; +{ + void printExpression(); + + nullPrint(unopTerm); + tab(); printf("(unop ["); + printToken(unopTerm->unop); + printf("]\n"); + tablevel++; + printExpression(unopTerm->unopArgument); + tablevel--; + tab(); printf(")\n"); +} + + void +printExpression(expression) + expressionType *expression; +{ + nullPrint(expression); + tab(); printf("(expression: ["); + printExpressionKind(expression->kindOfTerm); + printf("]\n"); + tablevel++; + switch (expression->kindOfTerm) { + + case ARRAY_EXPR: + printArrayTerm(expression->expressionTerm); + break; + + case ASSIGN_EXPR: + printAssignmentTerm(expression->expressionTerm); + break; + + case BINOP_EXPR: + printBinopTerm(expression->expressionTerm); + break; + + case CONDITION_CODE_EXPR: + printCondition(expression->expressionTerm); + break; + + case FUNCTION_CALL_EXPR: + printFunctionCall(expression->expressionTerm); + break; + + case HERE_EXPR: + printHere(); + break; + + case IDENTIFIER_EXPR: + printIdentifier(expression->expressionTerm); + break; + + case NUMBER_EXPR: + printNumber(expression->expressionTerm); + break; + + case POSTOP_EXPR: + printPostopTerm(expression->expressionTerm); + break; + + case PREOP_EXPR: + printPreopTerm(expression->expressionTerm); + break; + + case STRING_EXPR: + tab(); printf("%s\n", expression->expressionTerm); + break; + + case SUBEXPRESSION_EXPR: + printExpression(expression->expressionTerm); + break; + + case UNOP_EXPR: + printUnopTerm(expression->expressionTerm); + break; + + case VALUE_EXPR: + printValue(expression->expressionTerm); + break; + + default: + printf("eh? funny expression kind %d\n", + expression->kindOfTerm); + break; + } + tablevel--; + tab(); printf(")\n"); +} + + void +printExpressionList(expressionList) + expressionListType *expressionList; +{ + while (expressionList != NULL) { + printExpression(expressionList->theExpression); + expressionList = expressionList->nextExpression; + } +} + + void +printIdentifierList(identifierList) + identifierListType *identifierList; +{ + nullPrint(identifierList); + printSymbol(identifierList->theSymbol); + if (identifierList->nextIdentifier != NULL) + printIdentifierList(identifierList->nextIdentifier); +} + + +/* + These routines collectively print statements and statement fragments. + */ + + void +printCase(aCase) + caseType *aCase; +{ + tab(); printf("(case:\n"); tablevel++; + if (aCase->caseTags == NULL) { + tab(); printf("(default case)\n"); + } else { + printExpressionList(aCase->caseTags); + } + tablevel--; + tab(); printf(")\n"); + tab(); printf("(body:\n"); tablevel++; + printBlock(aCase->caseBody); + tablevel--; + tab(); printf(")\n"); +} + + void +printCaseList(caseList) + caseListType *caseList; +{ + tab(); printf("(cases:\n"); + tablevel++; + while (caseList != NULL) { + printCase(caseList->theCase); + caseList = caseList->nextCase; + } + tablevel--; + tab(); printf(")\n"); +} + + void +printMacro(macroInstruction) + macroTableEntryType *macroInstruction; +{ + nullPrint(macroInstruction); + tab(); printf("(macro: %s)\n", macroInstruction->macroName); +} + + void +printOpcode(opcode) + opcodeTableEntryType *opcode; +{ + nullPrint(opcode); + tab(); printf("(opcode: %s)\n", opcode->mnemonic); +} + + void +printOperandList(operandList) + operandListType *operandList; +{ + nullPrint(operandList); + printOperand(operandList); + if (operandList->nextOperand != NULL) + printOperandList(operandList->nextOperand); +} + + void +printAlignStatement(alignStatement) + alignStatementBodyType *alignStatement; +{ + nullPrint(alignStatement); + printExpression(alignStatement); +} + + void +printAssertStatement(assertStatement) + assertStatementBodyType *assertStatement; +{ + nullPrint(assertStatement); + printExpression(assertStatement->condition); + printExpression(assertStatement->message); +} + + void +printBlockStatement(blockStatement) + blockStatementBodyType *blockStatement; +{ + nullPrint(blockStatement); + printExpressionList(blockStatement); +} + + void +printByteStatement(byteStatement) + byteStatementBodyType *byteStatement; +{ + nullPrint(byteStatement); + printExpressionList(byteStatement); +} + + void +printConstrainStatement(constrainStatement) + constrainStatementBodyType *constrainStatement; +{ + nullPrint(constrainStatement); + printExpression(constrainStatement->constraint); + printBlock(constrainStatement->constrainedBlock); +} + + void +printDbyteStatement(dbyteStatement) + dbyteStatementBodyType *dbyteStatement; +{ + nullPrint(dbyteStatement); + printExpressionList(dbyteStatement); +} + + void +printDefineStatement(defineStatement) + defineStatementBodyType *defineStatement; +{ + nullPrint(defineStatement); + printSymbol(defineStatement->theSymbol); + printExpression(defineStatement->theValue); +} + + void +printDoUntilStatement(doUntilStatement) + doUntilStatementBodyType *doUntilStatement; +{ + nullPrint(doUntilStatement); + printBlock(doUntilStatement->doUntilLoop); + tab(); printf("(condition: "); + printCondition(doUntilStatement->doUntilCondition); + printf(")\n"); +} + + void +printDoWhileStatement(doWhileStatement) + doWhileStatementBodyType *doWhileStatement; +{ + nullPrint(doWhileStatement); + printBlock(doWhileStatement->doWhileLoop); + tab(); printf("(condition: "); + printCondition(doWhileStatement->doWhileCondition); + printf(")\n"); +} + + void +printExternStatement(externStatement) + externStatementBodyType *externStatement; +{ + nullPrint(externStatement); + printIdentifierList(externStatement); +} + + void +printFreturnStatement(freturnStatement) + freturnStatementBodyType *freturnStatement; +{ + nullPrint(freturnStatement); + printExpression(freturnStatement); +} + + void +printFunctionStatement(functionStatement) + functionStatementBodyType *functionStatement; +{ + nullPrint(functionStatement); + tab();printf("(function name: %s)\n",functionStatement->functionName); + printArgumentDefinitionList(functionStatement->theArguments); + printBlock(functionStatement->theBlock); +} + + void +printIfStatement(ifStatement) + ifStatementBodyType *ifStatement; +{ + nullPrint(ifStatement); + tab(); printf("(condition: "); + printCondition(ifStatement->ifCondition); + printf(")\n"); + printBlock(ifStatement->consequence); + tab(); printf("(else:\n"); + tablevel++; + printIfStatement(ifStatement->continuation); + tablevel--; + tab(); printf(")\n"); +} + + void +printIncludeStatement(includeStatement) + includeStatementBodyType *includeStatement; +{ + nullPrint(includeStatement); + printExpression(includeStatement); +} + + void +printInstructionStatement(instructionStatement) + instructionStatementBodyType *instructionStatement; +{ + nullPrint(instructionStatement); + switch(instructionStatement->kindOfInstruction) { + case OPCODE_INSTRUCTION: + printOpcode(instructionStatement->theInstruction); + break; + + case MACRO_INSTRUCTION: + printMacro(instructionStatement->theInstruction); + break; + + default: + printf("huh? instruction type=%d\n", instructionStatement-> + kindOfInstruction); + break; + } + printOperandList(instructionStatement->theOperands); +} + + void +printLongStatement(longStatement) + longStatementBodyType *longStatement; +{ + nullPrint(longStatement); + printExpressionList(longStatement); +} + + void +printMacroStatement(macroStatement) + macroStatementBodyType *macroStatement; +{ + nullPrint(macroStatement); + tab(); printf("(macro name: %s)\n", macroStatement->theMacro); + printArgumentDefinitionList(macroStatement->theArguments); + printBlock(macroStatement->theBlock); +} + + void +printMdefineStatement(mdefineStatement) + defineStatementBodyType *mdefineStatement; +{ + nullPrint(mdefineStatement); + printSymbol(mdefineStatement->theSymbol); + printExpression(mdefineStatement->theValue); +} + + void +printMdoUntilStatement(mdoUntilStatement) + mdoUntilStatementBodyType *mdoUntilStatement; +{ + nullPrint(mdoUntilStatement); + printBlock(mdoUntilStatement->mdoUntilLoop); + printExpression(mdoUntilStatement->mdoUntilCondition); +} + + void +printMdoWhileStatement(mdoWhileStatement) + mdoWhileStatementBodyType *mdoWhileStatement; +{ + nullPrint(mdoWhileStatement); + printBlock(mdoWhileStatement->mdoWhileLoop); + printExpression(mdoWhileStatement->mdoWhileCondition); +} + + void +printMforStatement(mforStatement) + mforStatementBodyType *mforStatement; +{ + nullPrint(mforStatement); + printExpression(mforStatement->initExpression); + printExpression(mforStatement->testExpression); + printExpression(mforStatement->incrExpression); + printBlock(mforStatement->forLoop); +} + + void +printMifStatement(mifStatement) + mifStatementBodyType *mifStatement; +{ + nullPrint(mifStatement); + printExpression(mifStatement->mifCondition); + printBlock(mifStatement->mifConsequence); + tab(); printf("(melse:\n"); + tablevel++; + printMifStatement(mifStatement->mifContinuation); + tablevel--; + tab(); printf(")\n"); +} + + void +printMswitchStatement(mswitchStatement) + mswitchStatementBodyType *mswitchStatement; +{ + nullPrint(mswitchStatement); + printExpression(mswitchStatement->switchExpression); + printCaseList(mswitchStatement->cases); +} + + void +printMvariableStatement(mvariableStatement) + mvariableStatementBodyType *mvariableStatement; +{ + nullPrint(mvariableStatement); + printSymbol(mvariableStatement->theSymbol); + printExpression(mvariableStatement->theValue); +} + + void +printMwhileStatement(mwhileStatement) + mwhileStatementBodyType *mwhileStatement; +{ + nullPrint(mwhileStatement); + printExpression(mwhileStatement->mwhileCondition); + printBlock(mwhileStatement->mwhileLoop); +} + + void +printOrgStatement(orgStatement) + orgStatementBodyType *orgStatement; +{ + nullPrint(orgStatement); + printExpression(orgStatement); +} + + void +printPerformStatement(performStatement) + performStatementBodyType *performStatement; +{ + nullPrint(performStatement); + printExpression(performStatement); +} + + void +printRelStatement(relStatement) + relStatementBodyType *relStatement; +{ + /* there's nothing here... */ +} + + void +printStartStatement(startStatement) + startStatementBodyType *startStatement; +{ + nullPrint(startStatement); + printExpression(startStatement); +} + + void +printStringStatement(stringStatement) + stringStatementBodyType *stringStatement; +{ + nullPrint(stringStatement); + printExpressionList(stringStatement); +} + + void +printStructStatement(structStatement) + structStatementBodyType *structStatement; +{ + nullPrint(structStatement); + printSymbol(structStatement->structName); + printBlock(structStatement->structBody); +} + + void +printTargetStatement(targetStatement) + targetStatementBodyType *targetStatement; +{ + nullPrint(targetStatement); + printExpression(targetStatement); +} + + void +printUndefineStatement(undefineStatement) + undefineStatementBodyType *undefineStatement; +{ + nullPrint(undefineStatement); + printIdentifierList(undefineStatement); +} + + void +printVariableStatement(variableStatement) + variableStatementBodyType *variableStatement; +{ + nullPrint(variableStatement); + printSymbol(variableStatement->theSymbol); + printExpression(variableStatement->theValue); +} + + void +printWhileStatement(whileStatement) + whileStatementBodyType *whileStatement; +{ + nullPrint(whileStatement); + tab(); printf("(condition: "); + printCondition(whileStatement->whileCondition); + printf(")\n"); + printBlock(whileStatement->whileLoop); +} + + void +printWordStatement(wordStatement) + wordStatementBodyType *wordStatement; +{ + nullPrint(wordStatement); + printExpressionList(wordStatement); +} + + void +printLabelList(labelList) + labelListType *labelList; +{ + nullPrint(labelList); + tab(); printf("(\n"); + tablevel++; + while (labelList != NULL) { + printSymbol(labelList->theLabel); + labelList = labelList->nextLabel; + } + tablevel--; + tab(); printf(")\n"); +} + + void +printStatementBody(kind, body) + statementKindType kind; + statementBodyType body; +{ + switch (kind) { + + case ALIGN_STATEMENT: + printAlignStatement(body); + break; + + case ASSERT_STATEMENT: + printAssertStatement(body); + break; + + case BLOCK_STATEMENT: + printBlockStatement(body); + break; + + case BYTE_STATEMENT: + printByteStatement(body); + break; + + case CONSTRAIN_STATEMENT: + printConstrainStatement(body); + break; + + case DBYTE_STATEMENT: + printDbyteStatement(body); + break; + + case DEFINE_STATEMENT: + printDefineStatement(body); + break; + + case DO_UNTIL_STATEMENT: + printDoUntilStatement(body); + break; + + case DO_WHILE_STATEMENT: + printDoWhileStatement(body); + break; + + case EXTERN_STATEMENT: + printExternStatement(body); + break; + + case FRETURN_STATEMENT: + printFreturnStatement(body); + break; + + case FUNCTION_STATEMENT: + printFunctionStatement(body); + break; + + case GROUP_STATEMENT: + printBlock(body); + break; + + case IF_STATEMENT: + printIfStatement(body); + break; + + case INCLUDE_STATEMENT: + printIncludeStatement(body); + break; + + case INSTRUCTION_STATEMENT: + printInstructionStatement(body); + break; + + case LONG_STATEMENT: + printLongStatement(body); + break; + + case MACRO_STATEMENT: + printMacroStatement(body); + break; + + case MDEFINE_STATEMENT: + printMdefineStatement(body); + break; + + case MDO_UNTIL_STATEMENT: + printMdoUntilStatement(body); + break; + + case MDO_WHILE_STATEMENT: + printMdoWhileStatement(body); + break; + + case MFOR_STATEMENT: + printMforStatement(body); + break; + + case MIF_STATEMENT: + printMifStatement(body); + break; + + case MSWITCH_STATEMENT: + printMswitchStatement(body); + break; + + case MVARIABLE_STATEMENT: + printMvariableStatement(body); + break; + + case MWHILE_STATEMENT: + printMwhileStatement(body); + break; + + case NULL_STATEMENT: + /* do nothing */ + break; + + case ORG_STATEMENT: + printOrgStatement(body); + break; + + case PERFORM_STATEMENT: + printPerformStatement(body); + break; + + case REL_STATEMENT: + printRelStatement(body); + break; + + case START_STATEMENT: + printStartStatement(body); + break; + + case STRING_STATEMENT: + printStringStatement(body); + break; + + case STRUCT_STATEMENT: + printStructStatement(body); + break; + + case TARGET_STATEMENT: + printTargetStatement(body); + break; + + case UNDEFINE_STATEMENT: + printUndefineStatement(body); + break; + + case VARIABLE_STATEMENT: + printVariableStatement(body); + break; + + case WHILE_STATEMENT: + printWhileStatement(body); + break; + + case WORD_STATEMENT: + printWordStatement(body); + break; + + default: + printf("Say what? statement kind=%d\n", kind); + break; + } +} + + void +printStatement(statement) + statementType *statement; +{ + nullPrint(statement); + tab(); printf("(statement["); + printStatementKind(statement->kindOfStatement); + printf("]: \n"); + tablevel++; + printLabelList(statement->labels); + printStatementBody(statement->kindOfStatement, + statement->statementBody); + tablevel--; + tab(); printf(")\n"); + if (statement->nextStatement != NULL) + printStatement(statement->nextStatement); +} + +/* + Other debug print routines. + */ + + void +printPendingFixupList(fixupList) + fixupListType *fixupList; +{ + printf("fixup list: ("); + tablevel++; + while (fixupList != NULL) { + printExpression(fixupList->theFixupExpression); + fixupList = fixupList->nextFixup; + } + tablevel--; + printf(")\n"); +} + + void +printCreateFixup(expression, location, kindOfFixup) + expressionType *expression; + addressType location; + fixupKindType kindOfFixup; +{ + static char *fixupStringTable[] = { + "BYTE FIXUP", + "WORD FIXUP", + "NO FIXUP", + "OPERAND FIXUP", + "BYTE RELATIVE FIXUP", + "DBYTE FIXUP", + "NO FIXUP (OK)", + "LONG FIXUP", + "WORD RELATIVE FIXUP", + }; + + printf("created fixup: expr=0x%x at 0x%x (%s)\n", expression, + location, fixupStringTable[(int)kindOfFixup]); +} + + +/* + Print internal code buffers. + */ + + void +printExpressionBuffer() +{ + int line; + int i; + + printf("expression length = %d:\n", expressionBufferSize); + for (line=0; linecodeStartAddress); + end = bufferPosition(codeSegment->codeEndAddress); + + printf("buffer 0x%x:\n", bufferNum*CODE_BUFFER_SIZE); + for (line=0; lineend){ + /* skip it -- no code here */ + } else { + printf(" %4x:", bufferNum*CODE_BUFFER_SIZE + line); + for (i=line; iend) + printf(" "); + else + printf(" %2x", (*(codeSegment->codeBuffer))[i]); + } + printf("\n"); + } + } +} + + void +printCodeBufferSection(codeBufferSection) + codeRegionType *codeBufferSection; +{ + bool anyCodeThereFlag; + int i; + + anyCodeThereFlag = FALSE; + for (i=0; icodeSegments[i] != NULL) { + printOneCodeBuffer(codeBufferSection->codeSegments[i], + i); + anyCodeThereFlag = TRUE; + } + if (!anyCodeThereFlag) + printf("no code in section\n"); + printf("\n"); +} + + void +printCodeBuffers() +{ + printf("absolute code:\n"); + printCodeBufferSection(&absoluteCodeRegion); + printf("relocatable code:\n"); + printCodeBufferSection(&relocatableCodeRegion); +} diff --git a/debugPrint.o b/debugPrint.o new file mode 100644 index 0000000..12aa40c Binary files /dev/null and b/debugPrint.o differ diff --git a/debugPrintSD.o b/debugPrintSD.o new file mode 100644 index 0000000..3b4d453 Binary files /dev/null and b/debugPrintSD.o differ diff --git a/debugPrintSD_6502.c b/debugPrintSD_6502.c new file mode 100644 index 0000000..5b3f5b0 --- /dev/null +++ b/debugPrintSD_6502.c @@ -0,0 +1,249 @@ +/* + debugPrintSD_6502.c -- Routines to print out things for debugging + purposes (system dependent routines, 6502 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 23-April-1985 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" + + +int tablevel; + +/* Fundamental nop print operation */ +#define nullPrint(thing) if (thing==NULL) { tab(); printf("()\n"); return; } + + void +printCondition(condition) + conditionType condition; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'conditionType'. */ + static char *conditionTable[] = { + "carry", + "zero", + "negative", + "overflow", + "lt", + "leq", + "slt", + "sleq", + "always", + "!carry", + "!zero", + "!negative", + "!overflow", + "geq", + "gt", + "sgeq", + "sgt", + "never", + }; + + printf("%s", conditionTable[(int)condition]); +} + + void +printOperandKind(kind) + operandKindType kind; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'operandKindType'. */ + static char *operandKindTable[] = { + "expression opnd", + "immediate opnd", + "indirect opnd", + "a register opnd", + "x register opnd", + "y register opnd", + "post indexed y opnd", + "pre indexed x opnd", + "x indexed opnd", + "y indexed opnd", + "x selected opnd", + "y selected opnd", + "pre selected x opnd", + "string opnd", + "block opnd", + }; + + printf("%s", operandKindTable[(int)kind]); +} + + void +printToken(token) + int token; +{ +/* This table MUST be maintained congruently with the set of '#define's in + the file 'y.tab.h' as produced by yacc. */ + static char *tokenTable[] = { + "A", + "ALIGN", + "ASSERT", + "BLOCK", + "BYTE", + "CONSTRAIN", + "DBYTE", + "DEFINE", + "DO", + "ELSE", + "ELSEIF", + "ENDFILE", + "EOL", + "EXTERN", + "FRETURN", + "FUNCTION", + "HERE", + "IF", + "INCLUDE", + "LONG", + "MACRO", + "MCASE", + "MDEFAULT", + "MDEFINE", + "MDO", + "MELSE", + "MELSEIF", + "MFOR", + "MIF", + "MSWITCH", + "MUNTIL", + "MVARIABLE", + "MWHILE", + "ORG", + "REL", + "START", + "STRING", + "STRUCT", + "TARGET", + "UNDEFINE", + "UNTIL", + "VARIABLE", + "WHILE", + "WORD", + "X", + "Y", + "ConditionCode", + "Identifier", + "MacroName", + "Number", + "Opcode", + "TextString", + "ASSIGN", + "LOGICAL_OR", + "LOGICAL_XOR", + "LOGICAL_AND", + "BITWISE_OR", + "BITWISE_XOR", + "BITWISE_AND", + "EQUAL_TO", + "NOT_EQUAL_TO", + "LESS_THAN", + "LESS_THAN_OR_EQUAL_TO", + "GREATER_THAN", + "GREATER_THAN_OR_EQUAL_TO", + "LEFT_SHIFT", + "RIGHT_SHIFT", + "ADD", + "SUB", + "MUL", + "DIV", + "MOD", + "UNARY_MINUS", + "LOGICAL_NOT", + "BITWISE_NOT", + "HI_BYTE", + "LO_BYTE", + "SELECT", + "INCREMENT", + "DECREMENT", + }; + + if (token >= A) { + printf("%s", tokenTable[token - A]); + } else { + printf("'%c'", token); + } +} + + void +printOperand(operand) + operandType *operand; +{ + nullPrint(operand); + tab(); printf("(operand: ["); + printOperandKind(operand->kindOfOperand); + printf("]\n"); + tablevel++; + switch (operand->kindOfOperand) { + + case EXPRESSION_OPND: + printExpression(operand->theOperand); + break; + + case IMMEDIATE_OPND: + printExpression(operand->theOperand); + break; + + case INDIRECT_OPND: + printExpression(operand->theOperand); + break; + + case A_REGISTER_OPND: + break; + + case X_REGISTER_OPND: + break; + + case Y_REGISTER_OPND: + break; + + case POST_INDEXED_Y_OPND: + printExpression(operand->theOperand); + break; + + case PRE_INDEXED_X_OPND: + printExpression(operand->theOperand); + break; + + case X_INDEXED_OPND: + printExpression(operand->theOperand); + break; + + case Y_INDEXED_OPND: + printExpression(operand->theOperand); + break; + + case X_SELECTED_OPND: + printIdentifierList(operand->theOperand); + break; + + case Y_SELECTED_OPND: + printIdentifierList(operand->theOperand); + break; + + case PRE_SELECTED_X_OPND: + printIdentifierList(operand->theOperand); + break; + + case STRING_OPND: + tab(); printf("(string: \"%s\")\n", operand->theOperand); + break; + + case BLOCK_OPND: + printBlock(operand->theOperand); + break; + + default: + printf("fooey: bad operand kind %d\n", operand-> + kindOfOperand); + break; + } + tablevel--; + tab(); printf(")\n"); +} diff --git a/debugPrintSD_68000.c b/debugPrintSD_68000.c new file mode 100644 index 0000000..0196caf --- /dev/null +++ b/debugPrintSD_68000.c @@ -0,0 +1,309 @@ +/* + debugPrintSD_68000.c -- Routines to print out things for debugging + purposes (system dependent routines, 68000 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 26-April-1985 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" + + +int tablevel; + +/* Fundamental nop print operation */ +#define nullPrint(thing) if (thing==NULL) { tab(); printf("()\n"); return; } + + void +printCondition(condition) + conditionType condition; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'conditionType'. */ + static char *conditionTable[] = { + "carry", + "equal", + "overflow", + "minus", + "lt", + "leq", + "ls", + "always", + "!carry", + "!equal", + "!overflow", + "plus", + "geq", + "gt", + "high", + "never", + }; + + printf("%s", conditionTable[(int)condition]); +} + + void +printRegister(reg) + int reg; +{ + if (reg < 8) + printf(" a%d", reg); + else + printf(" d%d", reg - 8); +} + + void +printControlRegister(reg) + int reg; +{ + switch (reg) { + case SFC_REGISTER: printf("sfc"); break; + case DFC_REGISTER: printf("dfc"); break; + case VBR_REGISTER: printf("vbr"); break; + default: botch("Bad control register %d\n", reg); break; + } +} + + void +printOperandKind(kind) + operandKindType kind; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'operandKindType'. */ + static char *operandKindTable[] = { + "expression opnd", + "string opnd", + "block opnd", + "data register opnd", + "address register opnd", + "address register indirect opnd", + "postincrement opnd", + "predecrement opnd", + "displacement opnd", + "indexed opnd", + "program counter displacement opnd", + "program counter indexed opnd", + "immediate opnd", + "absolute short opnd", + "absolute long opnd", + "condition code register opnd", + "status register opnd", + "user stack pointer opnd", + "control register opnd", + }; + + printf("%s", operandKindTable[(int)operandKindField(kind)]); + if (isRegisterOperand(kind)) + printRegister(getRegister(kind)); + if (isControlRegisterOperand(kind)) + printControlRegister(getRegister(kind)); + if (isIndexedOperand(kind)) + printRegister(getIndexRegister(kind)); +} + + bool +isRegisterOperand(kind) + operandKindType kind; +{ + kind = operandKindField(kind); + return(kind==D_REGISTER_OPND || kind==A_REGISTER_OPND || + kind==A_REGISTER_INDIRECT_OPND || kind==POSTINCREMENT_OPND || + kind==PREDECREMENT_OPND || kind==DISPLACEMENT_OPND || + kind==INDEXED_OPND || kind==SELECTED_OPND || + kind==INDEX_SELECTED_OPND); +} + + bool +isIndexedOperand(kind) + operandKindType kind; +{ + kind = operandKindField(kind); + return(kind==INDEXED_OPND || kind==PC_INDEXED_OPND || kind== + INDEX_SELECTED_OPND); +} + + bool +isControlRegisterOperand(kind) + operandKindType kind; +{ + return(operandKindField(kind) == CONTROL_REGISTER_OPND); +} + + void +printToken(token) + int token; +{ +/* This table MUST be maintained congruently with the set of '#define's in + the file 'y.tab.h' as produced by yacc. */ + static char *tokenTable[] = { + "A0", + "A1", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "ALIGN", + "ASSERT", + "BLOCK", + "BYTE", + "CCR", + "CONSTRAIN", + "D0", + "D1", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "DBYTE", + "DEFINE", + "DFC", + "DO", + "ELSE", + "ELSEIF", + "ENDFILE", + "EOL", + "EXTERN", + "FRETURN", + "FUNCTION", + "HERE", + "IF", + "INCLUDE", + "L", + "LONG", + "MACRO", + "MCASE", + "MDEFAULT", + "MDEFINE", + "MDO", + "MELSE", + "MELSEIF", + "MFOR", + "MIF", + "MSWITCH", + "MUNTIL", + "MVARIABLE", + "MWHILE", + "ORG", + "PC", + "REL", + "SFC", + "SR", + "START", + "STRING", + "STRUCT", + "TARGET", + "UNDEFINE", + "UNTIL", + "USP", + "VARIABLE", + "VBR", + "W", + "WHILE", + "WORD", + "X", + "Y", + "ConditionCode", + "Identifier", + "MacroName", + "Number", + "Opcode", + "TextString", + "ASSIGN", + "LOGICAL_OR", + "LOGICAL_XOR", + "LOGICAL_AND", + "BITWISE_OR", + "BITWISE_XOR", + "BITWISE_AND", + "EQUAL_TO", + "NOT_EQUAL_TO", + "LESS_THAN", + "LESS_THAN_OR_EQUAL_TO", + "GREATER_THAN", + "GREATER_THAN_OR_EQUAL_TO", + "LEFT_SHIFT", + "RIGHT_SHIFT", + "ADD", + "SUB", + "MUL", + "DIV", + "MOD", + "UNARY_MINUS", + "LOGICAL_NOT", + "BITWISE_NOT", + "HI_BYTE", + "LO_BYTE", + "SELECT", + "INCREMENT", + "DECREMENT", + }; + + if (token >= A0) { + printf("%s", tokenTable[token - A0]); + } else { + printf("'%c'", token); + } +} + + void +printOperand(operand) + operandType *operand; +{ + nullPrint(operand); + tab(); printf("(operand: ["); + printOperandKind(operand->kindOfOperand); + printf("]\n"); + tablevel++; + switch (operand->kindOfOperand) { + + case EXPRESSION_OPND: + case DISPLACEMENT_OPND: + case INDEXED_OPND: + case PC_DISPLACEMENT_OPND: + case PC_INDEXED_OPND: + case IMMEDIATE_OPND: + case ABSOLUTE_SHORT_OPND: + case ABSOLUTE_LONG_OPND: + printExpression(operand->theOperand); + break; + + case D_REGISTER_OPND: + case A_REGISTER_OPND: + case A_REGISTER_INDIRECT_OPND: + case POSTINCREMENT_OPND: + case PREDECREMENT_OPND: + case CC_REGISTER_OPND: + case STATUS_REGISTER_OPND: + case USP_REGISTER_OPND: + case CONTROL_REGISTER_OPND: + break; + + case SELECTED_OPND: + case INDEX_SELECTED_OPND: + printIdentifierList(operand->theOperand); + break; + + case STRING_OPND: + tab(); printf("(string: \"%s\")\n", operand->theOperand); + break; + + case BLOCK_OPND: + printBlock(operand->theOperand); + break; + + default: + printf("fooey: bad operand kind %d\n", operand-> + kindOfOperand); + break; + } + tablevel--; + tab(); printf(")\n"); +} diff --git a/doc/genmacros.itr b/doc/genmacros.itr new file mode 100644 index 0000000..2e3efc7 --- /dev/null +++ b/doc/genmacros.itr @@ -0,0 +1,463 @@ +.TL +\s+9genmacros.m\s-9 +.AU +a macro library for use with the 6502 version of Macross +.AI +Lucasfilm Ltd. Games Division +\\*(DY +.ds LH genmacros.m +.ds CH \\*(DY +.ds RH Reference Manual +.ds LF Lucasfilm Ltd. Proprietary Information +.ds CF - % - +.ds RF CONFIDENTIAL +.PP +These macros have been concocted by various people for the convenience and +amusement of those programming the 6502 using \fIMacross\fR. The will be +found in the file \fB/u1/gg/lib/6502/genmacros.m\fR. To use them, insert the +following statement somewhere near the beginning of your \fIMacross\fR +program: +.nf + + \fBinclude "/u1/gg/lib/6502/genmacros.m"\fR + +.fi +Easy, no? What follows is a summary of the macros, grouped roughly by +category. +.sp 1 +.SH +\s+2Macros to save and restore registers\s-2 +.nf + +\fBphr\fR +.fi +.IP +Push all registers (i.e., the accumulator and the X and Y index registers) +onto the stack. +.LP +.nf + +\fBplr\fR +.fi +.IP +Pull the registers (the accumulator and the X and Y index registers) off the +stack. +.LP +.nf + +\fBphx\fR +.fi +.IP +Push the X register onto the stack. +.LP +.nf + +\fBplx\fR +.fi +.IP +Pull the X register off of the stack. +.LP +.nf + +\fBphy\fR +.fi +.IP +Push the Y register onto the stack. +.LP +.nf + +\fBply\fR +.fi +.IP +Pull the Y register off of the stack. +.LP +.nf + +\fBpushaddr \fIaddress\fR +.fi +.IP +Push \fIaddress\fR onto the stack to \fBrts\fR to. +.sp 1 +.SH +\s+2Macros to move data around with\s-2 +.PP +These macros provide an address mode independent method of moving bytes from +one place to another. The source and destination arguments of these macros +may, generally speaking, be in any address mode you desire (except, of course, +that the destination can't be immediate mode!). +.nf + +\fBmovm \fIn\fB, \fIdest\fB, \fIsrc\fR +.fi +.IP +Move multiple \(em move \fIn\fR bytes from \fIsrc\fR to \fIdest\fR. The bytes +are moved using the accumulator as an intermediary. +.LP +.nf + +\fBmovmx \fIn\fB, \fIdest\fB, \fIsrc\fR +.fi +.IP +Move multiple \(em move \fIn\fR bytes from \fIsrc\fR to \fIdest\fR. The bytes +are moved using the X register as an intermediary. +.LP +.nf + +\fBmovmy \fIn\fB, \fIdest\fB, \fIsrc\fR +.fi +.IP +Move multiple \(em move \fIn\fR bytes from \fIsrc\fR to \fIdest\fR. The bytes +are moved using the Y register as an intermediary. +.LP +.nf + +\fBmv2m \fIn\fB, \fIdest1\fB, \fIdest2\fB, \fIsrc\fR +.fi +.IP +Move multiple to two destinations \(em move \fIn\fR bytes from \fIsrc\fR to +both \fIdest1\fR and \fIdest2\fR. The bytes are moved using the acuumulator +as an intermediary. +.LP +.nf + +\fBmoveb \fIsrc\fB, \fIdest\fR +.fi +.IP +Move byte \(em move one byte from \fIsrc\fR to \fIdest\fR via the accumulator. +.LP +.nf + +\fBmovew \fIsrc\fB, \fIdest\fR +.fi +.IP +Move word \(em move one word from \fIsrc\fR to \fIdest\fR via the accumulator. +.LP +.nf + +\fBmovexb \fIsrc\fB, \fIdest\fR +.fi +.IP +Move byte \(em move one byte from \fIsrc\fR to \fIdest\fR via the X register. +.LP +.nf + +\fBmovexw \fIsrc\fB, \fIdest\fR +.fi +.IP +Move word \(em move one word from \fIsrc\fR to \fIdest\fR via the X register. +.LP +.nf + +\fBmoveyb \fIsrc\fB, \fIdest\fR +.fi +.IP +Move byte \(em move one byte from \fIsrc\fR to \fIdest\fR via the Y register. +.LP +.nf + +\fBmoveyw \fIsrc\fB, \fIdest\fR +.fi +.IP +Move word \(em move one word from \fIsrc\fR to \fIdest\fR via the Y register. +.LP +.nf + +\fBmovb \fIdest\fB, \fIsrc\fR +.fi +.IP +Move byte \(em move one byte from \fIsrc\fR to \fIdest\fR via the accumulator. +This is distinguished from \fBmoveb\fR in that it has the order of the +operands reversed. This confusing feature is provided for compatibility with +\fBa65\fR. +.LP +.nf + +\fBmovw \fIdest\fB, \fIsrc\fR +.fi +.IP +Move word \(em move one word from \fIsrc\fR to \fIdest\fR via the accumulator. +This is distinguished from \fBmovew\fR in that it has the order of the +operands reversed. This confusing feature is provided for compatibility with +\fBa65\fR. +.LP +.nf + +\fBclrm \fIn\fB, \fIdest\fR +.fi +.IP +Clear multiple \(em clears (zeros) \fIn\fR bytes starting at \fIdest\fR. +Leaves a zero in the accumulator. +.LP +.nf + +\fBclrb \fIdest\fR +\fBclearb \fIdest\fR +.fi +.IP +Clear byte \(em clears (zeros) one byte at \fIdest\fR. Leaves a zero in the +accumulator. +.LP +.nf + +\fBclrw \fIdest\fR +\fBclearw \fIdest\fR +.fi +.IP +Clear word \(em clears (zeros) one word at \fIdest\fR. Leaves a zero in the +accumulator. +.sp 1 +.SH +\s+2Arithmetic macros\s-2 +.nf + +\fBaddm \fIn\fB, \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Add multiple \(em adds the \fIn\fR byte numbers found at \fIsrc1\fR and +\fIsrc2\fR and puts the result at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBaddb \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Add byte \(em adds the one byte numbers \fIsrc1\fR and \fIsrc2\fR and puts the +one byte result in \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBaddw \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Add word \(em adds the two byte numbers \fIsrc1\fR and \fIsrc2\fR and puts the +two byte result in \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBsubm \fIn\fB, \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Subtract multiple \(em subtracts the \fIn\fR byte number found at \fIsrc2\fR +from the same sized number found at \fIsrc1\fR and puts the \fIn\fR byte +result in \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBsubb \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Subtract byte \(em subtracts the one byte number \fIsrc2\fR from \fIsrc1\fR +and puts the one byte result in \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBsubw \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Subtract word \(em subtracts the two byte numbers \fIsrc2\fR from \fIsrc1\fR +and puts the two byte result in \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBcmpm \fIn\fB, \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Compare multiple \(em compares the two \fIn\fR byte numbers found at +\fIsrc1\fR and \fIsrc2\fR. Clobbers the accumulator. +.LP +.nf + +\fBcmpb \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Compare byte \(em compares the one byte numbers \fIsrc1\fR and \fIsrc2\fR. +Clobbers the accumulator. +.LP +.nf + +\fBcmpw \fIsrc1\fB, \fIsrc2\fR +.fi +.IP +Compare word \(em compares the two byte numbers \fIsrc1\fR and \fIsrc2\fR. +Clobbers the accumulator. +.LP +.nf + +\fBnegm \fIn\fB, \fIdest\fR +.fi +.IP +Negate multiple \(em negates the \fIn\fR byte number at \fIdest\fR. Clobbers +the accumulator. +.LP +.nf + +\fBnegb \fIdest\fR +.fi +.IP +Negate byte \(em negates the one byte number at \fIdest\fR. Clobbers the +accumulator. +.LP +.nf + +\fBnegw \fIdest\fR +.fi +.IP +Negate word \(em negates the two byte number at \fIdest\fR. Clobbers the +accumulator. +.LP +.nf + +\fBasrm \fIn\fB, \fIdest\fR +.fi +.IP +Arithmetic shift right multiple \(em performs a rightward one-bit arithmetic +shift of the \fIn\fR byte number at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBasrb \fIdest\fR +.fi +.IP +Arithmetic shift right byte \(em performs a rightward one-bit arithmetic +shift of the byte at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBasrw \fIdest\fR +.fi +.IP +Arithmetic shift right word \(em performs a rightward one-bit arithmetic +shift of the word at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBaslm \fIn\fB, \fIdest\fR +.fi +.IP +Arithmetic shift left multiple \(em performs a leftward one-bit arithmetic +shift of the \fIn\fR byte number at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBaslb \fIdest\fR +.fi +.IP +Arithmetic shift left byte \(em performs a leftward one-bit arithmetic +shift of the byte at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBaslw \fIdest\fR +.fi +.IP +Arithmetic shift left word \(em performs a leftward one-bit arithmetic +shift of the word at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBlsrm \fIn\fB, \fIdest\fR +.fi +.IP +Logical shift right multiple \(em performs a rightward one-bit logical shift +of the \fIn\fR byte number at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBlsrb \fIdest\fR +.fi +.IP +Logical shift right byte \(em performs a rightward one-bit logical shift of +the byte at \fIdest\fR. Clobbers the accumulator. +.LP +.nf + +\fBlsrw \fIdest\fR +.fi +.IP +Logical shift right word \(em performs a rightward one-bit logical shift of +the word at \fIdest\fR. Clobbers the accumulator. +.SH +.sp 1 +\s+2Flow-of-control macros\s-2 +.nf + +\fBrepeat \fIn\fB { \fIcode\fB }\fR +.fi +.IP +Replicates the block of \fIMacross\fR statements \fIcode\fR \fIn\fR times. +.LP +.nf + +\fBloop \fIcounter\fB, \fIstart\fB, \fIend\fB { \fIcode\fB }\fR +.fi +.IP +Generic ``do-loop'' \(em generates 6502 code for a loop that initializes +\fIcounter\fR to \fIstart\fR, and then repeatedly executes \fIcode\fR, +incrementing \fIcounter\fR until it reaches the value \fIend\fR. +\fICounter\fR may be ``\fBx\fR'' to denote the X index register, ``\fBy\fR'' +to denote the Y index register, or a memory location. \fIStart\fR and +\fIend\fR may be referenced in any 6502 address mode. +.SH +.sp 1 +\s+2Miscellaneous macros\s-2 +.nf + +\fBmbyte \fIn\fR +.fi +.IP +Generates \fIn\fR zero data bytes. +.bp +.CD +\s+5\fBAppendix \*- Summary of the macros\fR\s-5 +.DE +.LP +.nf + \fBaddb \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR + \fBaddm \fIn\fB, \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR + \fBaddw \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR + \fBaslb \fIdest\fR + \fBaslm \fIn\fB, \fIdest\fR + \fBaslw \fIdest\fR + \fBasrb \fIdest\fR + \fBasrm \fIn\fB, \fIdest\fR + \fBasrw \fIdest\fR + \fBclearb \fIdest\fR + \fBclearw \fIdest\fR + \fBclrb \fIdest\fR + \fBclrm \fIn\fB, \fIdest\fR + \fBclrw \fIdest\fR + \fBcmpb \fIsrc1\fB, \fIsrc2\fR + \fBcmpm \fIn\fB, \fIsrc1\fB, \fIsrc2\fR + \fBcmpw \fIsrc1\fB, \fIsrc2\fR + \fBloop \fIcounter\fB, \fIstart\fB, \fIend\fB, \fIcode\fR + \fBlsrb \fIdest\fR + \fBlsrm \fIn\fB, \fIdest\fR + \fBlsrw \fIdest\fR + \fBmbyte \fIn\fR + \fBmovb \fIdest\fB, \fIsrc\fR + \fBmoveb \fIsrc\fB, \fIdest\fR + \fBmovew \fIdest\fB, \fIsrc\fR + \fBmovexb \fIsrc\fB, \fIdest\fR + \fBmovexw \fIsrc\fB, \fIdest\fR + \fBmoveyb \fIsrc\fB, \fIdest\fR + \fBmoveyw \fIsrc\fB, \fIdest\fR + \fBmovm \fIn\fB, \fIdest\fB, \fIsrc\fR + \fBmovmx \fIn\fB, \fIdest\fB, \fIsrc\fR + \fBmovmy \fIn\fB, \fIdest\fB, \fIsrc\fR + \fBmovw \fIsrc\fB, \fIdest\fR + \fBmv2m \fIn\fB, \fIdest1\fB, \fIdest2\fB, \fIsrc\fR + \fBnegb \fIdest\fR + \fBnegm \fIn\fB, \fIdest\fR + \fBnegw \fIdest\fR + \fBphr\fR + \fBphx\fR + \fBphy\fR + \fBplr\fR + \fBplx\fR + \fBply\fR + \fBpushaddr \fIaddress\fR + \fBrepeat \fIn\fB, \fIcode\fR + \fBsubb \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR + \fBsubm \fIn\fB, \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR + \fBsubw \fIdest\fB, \fIsrc1\fB, \fIsrc2\fR +.fi diff --git a/doc/handyHelpfulHints.t b/doc/handyHelpfulHints.t new file mode 100644 index 0000000..c0d95dd --- /dev/null +++ b/doc/handyHelpfulHints.t @@ -0,0 +1,85 @@ +Handy Helpful Hints for using make/macross/slinky + +1. You need two header files: a header and a sub-header. The sub-header +declares 'define' symbols, zero page labels (as local labels), macros, +functions, and so on. The header includes the sub-header and then +additionally contains 'extern' declarations for all program-space labels and +non-zero page variable-space labels plus 'define' declarations which refer to +externals. + +Non-zero page variable-space should be laid out in one file that includes just +the sub-header. The rest of the program should be spread among files each of +which includes the header. + +2. In any given Macross assembly (usually one source file plus all of the +other files that it 'include's), you can classify each symbol in two different +orthogonal ways: whether it is global or local on the one hand and whether it +is defined in this assembly or defined in some other assembly. + +Being defined means that the symbol has a value which is known and can +therefore be used to generate code. If a symbol has a value when it is +encountered during assembly, then that value can be used immediately. +If not, then we must wait until linking when (presumably) the value will be +known. + +Being global means that the symbol's value is known outside of the assembly in +which the symbol is defined (i.e., that the value is "published" in the object +file for use by the linker). Conversely, being local means that the value is +known only in the one assembly. + +Let's look at the four possible cases when a symbol is encountered during +assembly: + +LOCAL, DEFINED: this is the usual case. The value is used at assembly time. +Multiple independent assemblies can define local symbols with the same names +without conflicting with each other when they are linked. + +LOCAL, UNDEFINED: this shouldn't happen. You will get a complaint from the +assembler. + +GLOBAL, DEFINED: during assembly, the symbol is treated just like a defined +local symbol. However, the value is "published" in the object file for use by +the linker. The symbol value can be made global either or both of two +different ways: with an 'extern' declaration + extern foo ; makes the symbol 'foo' global +or, if the symbol is a label, by using two colons instead of one + foo:: word 123 ; 'foo' is global + bar: word 456 ; 'bar' is local +If a global symbol is defined in more than one object file, the linker will +complain. + +GLOBAL, UNDEFINED: this means that the assembler assumes that the value of the +symbol will be defined at link time. You still have to tell the assembler +that the symbol is global with an 'extern' statement. + +Note that all macro, function and variable (Macross variables, not 6502 +storage locations used as variables) names MUST be local, as must be struct +names and struct fields. The assembler will complain if you try to declare +one of these 'extern'. + +A 'define' symbol must be local if it refers to any global symbols in its +definition. + +3. The fewer global symbols there are, the faster the link will run. + +4. When juggling a program that consists of multiple source and object files, +only a very foolish person would not use 'make'. + +5. Emacs has a very nice feature whereby you can run 'make' under emacs and +then get taken automagically to the errors: + +The emacs function 'compile' (or 'new-compile' on some systems), which is +usually bound to ^X^C (also to the shift-F5 key on my Concept terminal; I +don't know about others), will run make and put the output from make (error +messages and so on) in a buffer with a new window. + +After compiling with make, the emacs function 'next-error', which is usually +bound to ^X^N (also to the the F5 key on my Concept) will search in the error +message buffer for the first C-compiler-style error message (which is what +Macross outputs), read the file name and line number from the error message +and then (in another window) position the cursor at that line of that file. +Entering this command again takes you to the next error message, and then the +next, and so on. The wonderful thing about this is that if you edit your +source file, emacs keeps track of how you have shifted things around so that +it will always take you to the location of the next error, even if your +editing has invalidated the line numbers in the error messages! diff --git a/doc/linkerReleaseNotes b/doc/linkerReleaseNotes new file mode 100644 index 0000000..32396f0 --- /dev/null +++ b/doc/linkerReleaseNotes @@ -0,0 +1,224 @@ + An informal introduction to + code relocation + and + multi-file linking + using + Macross and Slinky + +To use: + +First, let me explain that if you don't want to use the linker and assemble +your programs in pieces, you need do nothing. Macross will continue to +operate for you just as it always has (except that it will be somewhat faster +since it no longer will be keeping track of some stuff internally that only +matters to the linker). If you're not interested stop reading this right now. + +There is a new command line option for Macross, '-c'. This signals to the +assembler that, rather than generating a plain old ordinary object file, you +want it to produce a special linkable object file that contains all kinds of +information that the linker will need later. (I know it's obscure, but I'm +running out of letters and the C compiler uses this flag to signal the same +thing (maybe it should be '-m' or would that be even more obscure?)). E.g.: + + macross -c -o foo foo.m + +To link object files together, you use Slinky. The command is + + slinky file1 file2 file3 ... + +where file1, file2, etc. were generated by Macross using the '-c' option +described in the previous paragraph. By default the output will go in the +file 's.out' but the aesthetically enlightened will use the '-o' option to +slinky that will name the output file whatever you want. E.g.: + + slinky -o foobar file1 file2 file3 ... + +will name the output 'foobar' (just like the '-o' option to Macross). The +output file from Slinky will be a standard a65-style object file suitable for +downloading to your Atari or whatever. *Don't* try to directly download an +unlinked object that was produced by Macross using '-c'. Doing so will make +the downloader choke, puke and die (actually, I haven't tried this, but in any +case it will be wrong and the result will most likely be ugly). + +Simple, no? Actually no, because... + +You need to write your Macross programs in a way that can allow the various +files to be assembled separately. This requires an understanding of two +important concepts: 1. relocation and 2. external symbols. + +A Macross relocatable object file consists of a bunch of little pieces of +object code (called 'segments') plus some other bookkeeping info. Each of +these little pieces of object code is either 'absolute' or 'relocatable'. +Being absolute means that a segment is given a fixed, pre-specified location +in memory. Being relocatable means that the segment can go wherever the +linker finds room to put it. + +All right, you ask, how do my pieces of code get to be absolute or +relocatable? Well, at any given time, Macross is assembling in either +absolute-mode or relocatable-mode (it starts out in relocatable-mode (always +did, bet you didn't even notice!)). It gets into absolute-mode using the +'org' statement with an absolute-value as the address to org to, i.e., + + org 0x1000 + +This starts an absolute segment at location 0x1000. The segment continues +until the next 'org' or 'rel' statement. Macross gets into relocatable-mode +via the 'rel' statement: + + rel + +or by an 'org' statement with a relocatable value as the address to org to +(actually, using an org in this way is, as of the current implementation, +somewhat questionable). The relocatable segment continues until the next +'org' kicks Macross out of relocatable-mode or you use a 'constrain' or +'align' statement. Each of the latter two (in relocatable-mode but not in +absolute-mode) starts a new relocatable segment which is aligned or +constrained appropriately at link-time. Also, a new relocatable segment +starts at the end of the block that is the argument of a 'constrain' +statement (again, in relocatable mode only). + +It is important for you to know where (in your source code) relocatable +segments begin and end, because each segment is relocated by the linker +independently of all the others. Thus, even though two segments might be +adjacent in your Macross source, in the eventual linked object they might not +be. Thus relative branches across segment boundaries may go out of range and +you cannot expect the flow of program execution to be continuous from one +segment to another, i.e., that the last instruction in a segment will be +followed immediately by the first instruction of the segment that follows it +in the source. For example, in the following: + + ...stuff... + and 123 + constrain (0x100) { + sta foobar + ...more stuff... + +you can't assume that the 'sta' will follow the 'and'. So + +RULE #1 -- Don't allow program flow of control to fall through from one +segment to the next. + +RULE #2 -- Don't do relative branches across segment boundaries ('jmp's and +'jsr's are OK). + +COROLLARY -- You can't put an 'align' or 'constrain' statement inside an 'if', +'while', 'do while' or 'do until' statement, and putting one inside a macro is +very likely to result in a weird program bug unless you really understand what +you are doing. + +As with segments, a symbol in your Macross program is either absolute or +relocatable. The value of an absolute symbol (called an 'absolute value') is +a location in an absolute segment (or simply a fixed number like 42 or 137). +A relocatable symbol has a value (called a 'relocatable value') which is a +location in a relocatable segment. The important point to note is that the +value of a relocatable symbol is not known until the program is linked and the +relocatable segment to which it refers is given an actual location in memory. + +This in turn means that Macross can't do any assembly-time arithmetic with the +symbol since it doesn't know what value to compute with. Since storing away +whole expressions in the object file would be both costly and messy we don't +even try. The only arithmetic operation that the linker knows how to do is +simple addition. Thus, the only operation you can perform with a relocatable +symbol or value is simple addition, and then only in contexts where the result +of the computation will get stored in the resultant object somewhere, such as +the argument to an instruction or a 'byte' or 'word' statement. Thus the +following are OK, for example (let's say 'foo' and 'bar' are relocatable +symbols): + + and foo+3 + ora bar-10 ; OK since this is just adding -10 + word foo+bar + +but these are not + + and foo*3 ; not addition + ora 10-bar ; can't subtract 'bar' + lda (bar+10)/7 ; even though 'bar' gets added, the result of + ; the addition is needed for the division + +So, + +RULE #3 -- No arithmetic more complicated than simple addition is allowed with +relocatable symbols or values. + +Now to explain external symbols... + +First of all, you need to understand about symbols being *defined*. When we +say that a symbol is 'defined' we mean that it has a value that the assembler +or linker can use. A symbol gets defined by the Macross 'define' statement or +by being used as a label. In order to actually use a symbol, e.g. as part of +the operand of an instruction, the symbol must be defined *somewhere*. + +Now let's say you have a subroutine that is defined in one file (actually, the +label which is associated with the entry point to the subroutine is defined in +that file, but let's not quibble), but which is called (using a 'jsr') from a +second file. Two pieces of information need to be given to Macross when it +assembles these files. In the first file, where the subroutine label is +defined, you need to tell Macross, "Hey, this label is going to be used +outside of this file, so put something in the object file that will tell the +linker that it's here." In the second file, where the label is used (but not +defined), you need to tell Macross, "Yes, I know this symbol isn't defined +here. Don't worry about it. It's defined elsewhere and the linker will worry +about it." Both of these pieces of information are conveyed by declaring the +symbol to be external using the Macross 'extern' statement. E.g., in the +first file: + + extern foo + ...stuff... + foo: ...more stuff... + rts + +and in the second file: + + extern foo + ...stuff... + jsr foo + ...more stuff... + +In addition to this, a shorthand form of declaring a label to be external when +it is defined is supported: you simply use two colons instead of one. In our +example above, then, the first file could be: + + ...stuff... + foo:: ...more stuff... + rts + +and the result would be exactly the same. So, + +RULE #4 -- If you want a symbol's value to be carried across multiple files, +that symbol MUST be declared external in the file where it is defined and in +all files in which it is used. + +Note that, as with relocatable symbols, symbols which are defined externally +do not have a value which is known to Macross at assembly-time (though symbols +which are external but which are defined in a given file do have such a value +presuming that they are not also relocatable). This means that the same +restrictions about arithmetic on relocatable symbols apply to externally +defined symbols: + +RULE #3a -- No arithmetic more complicated than simple addition is allowed +with externally defined symbols. + +Not to belabor the obvious, but it is of course an error to define an external +symbol in more than one file. The linker will catch this and complain if you +try. + +In summary then: + +RULE #1 -- Don't allow program flow of control to fall through from one +segment to the next. + +RULE #2 -- Don't do relative branches across segment boundaries ('jmp's and +'jsr's are OK). + +COROLLARY -- You can't put an 'align' or 'constrain' statement inside an 'if', +'while', 'do while' or 'do until' statement, and putting one inside a macro is +very likely to result in a weird program bug unless you really understand what +you are doing. + +RULE #3 -- No arithmetic more complicated than simple addition is allowed with +relocatable symbols or values or symbols which are defined externally. + +RULE #4 -- If you want a symbol's value to be carried across multiple files, +that symbol MUST be declared external in the file in which it is defined and +in all files in which it is used. diff --git a/doc/macros.itr b/doc/macros.itr new file mode 100644 index 0000000..da11387 --- /dev/null +++ b/doc/macros.itr @@ -0,0 +1,315 @@ +; +; potentially popular macros for the macross assembler +; +; 11-Jan-85 cbm converted for Macross from original a65 +; + +mif (!isDefined(_macros_)) { + define _macros_ = 1 +; +; push and pop X and Y registers +; +macro phx { + txa + pha +} +macro plx { + pla + tax +} +macro phy { + tya + pha +} +macro ply { + pla + tay +} + +macro call arg { + jsr arg +} + +macro return { + rts +} + +macro callret arg { + jmp arg ; same as jsr arg; rts +} + +macro save arg { + lda arg + pha +} + +macro restore arg { + pla + sta arg +} + +; ================================================================ +; some auxiliary functions for the macros that follow +; + +; MAKE-FIRST-BYTE - access low byte for any addressing mode +function makeFirstByte(operand) { + mif (isImmediateMode(operand)) { + freturn(/operand) + } melse { + freturn(operand) + } +} + +; MAKE-SECOND-BYTE - access high byte for any addr mode except (post y zzz) +function makeSecondByte(operand) { + mif (isImmediateMode(operand)) { + freturn(?operand) + } melse { + freturn(operand + 1) + } +} + +; MAKE-NTH-BYTE - similarly access arbitrary byte +function makeNthByte(operand, n) { + mif (isImmediateMode(operand)) { + freturn((operand >> (8 * (n - 1))) & 0xFF) + } melse { + freturn(operand + n - 1) + } +} + +; ================================================================ +; MOVM, MOVEB, MOVB, MOVEW, MOVW, CLEARB, and CLEARW +; Note that the args on MOVEx are src,dst as opposed to +; MOVx, which uses dst,src. +; + +; MOVM - move multiple +macro movm n, dst, src { + mvariable i + mfor (i=1, i<=n, i++) { + lda makeNthByte(src, i) + sta makeNthByte(dst, i) + } +} + +; MOVEB - move byte from src to dst +macro moveb src, dst { + lda src + sta dst +} + +; MOVB - for those who like their destination before their source +macro movb dst, src { + lda src + sta dst +} + +; MOVEW - move word from src to dst +; works for all addressing moves EXCEPT (post y zzz) +macro movew src, dst { + lda makeFirstByte(src) + sta makeFirstByte(dst) + lda makeSecondByte(src) + sta makeSecondByte(dst) +} + +; MOVW - and another with destination before source +; works for all addressing moves EXCEPT (post y zzz) +macro movw dst, src { + lda makeFirstByte(src) + sta makeFirstByte(dst) + lda makeSecondByte(src) + sta makeSecondByte(dst) +} + +; CLEARB - zero byte dst +macro clearb dst { + lda #0 + sta dst +} + +; CLEARW - zero word dst +; works for all addressing modes EXCEPT (post y dst) +macro clearw dst { + lda #0 + sta makeFirstByte(dst) + sta makeSecondByte(dst) +} + +; ================================================================ +; the general macros +; + +; MOVWB - move byte SRC to word DST +; works for all addressing modes EXCEPT (post y zzz) +macro movwb dst, src { + lda src + sta makeFirstByte(dst) + lda #0 + sta makeSecondByte(dst) +} + +; ADDM - add multiple +macro addm n, dst, src, src1 { + mvariable i + clc + mfor (i=1, i<=n, i++) { + lda makeNthByte(src, i) + adc makeNthByte(src1, i) + sta makeNthByte(dst, i) + } +} + +; ADDB - byte dst = byte src0 + byte src1 +macro addb dst, src0, src1 { + clc + lda src0 + adc src1 + sta dst +} + +; ADDW - word dst = word src0 + word src1 +; works for all addressing modes EXCEPT (post y zzz) +macro addw dst, src0, src1 { + clc + lda makeFirstByte(src0) + adc makeFirstByte(src1) + sta makeFirstByte(dst) + lda makeSecondByte(src0) + adc makeSecondByte(src1) + sta makeSecondByte(dst) +} + +; ADDWWB - word dst = word src0 + byte src1 +; works for all addressing modes EXCEPT (post y zzz) +macro addwwb dst, src0, src1 { + clc + lda makeFirstByte(src0) + adc src1 + sta makeFirstByte(dst) + lda makeSecondByte(src0) + adc #0 + sta makeSecondByte(dst) +} + +; SUBB - byte dst = byte src0 - byte src1 +macro subb dst, src0, src1 { + sec + lda src0 + sbc src1 + sta dst +} + +; SUBW - word dst = word src0 - word src1 +; works for all addressing modes EXCEPT (post y zzz) +macro subw dst, src0, src1 { + sec + lda makeFirstByte(src0) + sbc makeFirstByte(src1) + sta makeFirstByte(dst) + lda makeSecondByte(src0) + sbc makeSecondByte(src1) + sta makeSecondByte(dst) +} + +; SUBWWB - word dst = word src0 - byte src1 +; works for all addressing modes EXCEPT (post y zzz) +macro subwwb dst, src0, src1 { + sec + lda makeFirstByte(src0) + sbc src1 + sta makeFirstByte(dst) + lda makeSecondByte(src0) + sbc #0 + sta makeSecondByte(dst) +} + +; ================================================================ +; cmpm, cmpb, cmpw +; compare two quantities (arbitrary length, byte, and word) +; set the condition flags following s0-s1 +; +macro cmpm n, s0, s1 { + mvariable i + mfor (i=1, i<=n, i++) { + lda makeNthByte(s0, i) + sbc makeNthByte(s1, i) + } +} + +macro cmpb s0, s1 { + sec + lda s0 + sbc s1 +} + +macro cmpw s0, s1 { + sec + lda makeFirstByte(s0) + sbc makeFirstByte(s1) + lda makeSecondByte(s0) + sbc makeSecondByte(s1) +} + +; +; ASLM - multiply all by 2 +macro aslm n, s0 { + mvariable i + asl s0 + mfor (i = 2, i <= n, i++) { + rol makeNthByte(s0, i) + } +} + +; ================================================================ +; asrm, asrb, asrw +; Arithmetic Shift Right (with sign extend). +; +macro asrm n, s0 { + mvariable i = n + lda makeNthByte(s0, i) + cmp #0x80 + mwhile (i > 0) { + ror makeNthByte(s0, i--) + } +} + +macro asrb s0 { + lda s0 + cmp #0x80 + ror s0 +} + +macro asrw s0 { + lda makeSecondByte(s0) + cmp #0x80 + ror makeSecondByte(s0) + ror makeFirstByte(s0) +} + +; ================================================================ +; repeat n {code. . .} +; repeat n instances of code. e.g., +; repeat 6 { +; lda x[foo] +; sta x[bar] +; inx +; } +; will generate inline code to move 6 bytes +; +macro repeat count, blockToRepeat { + mvariable i = count + mwhile (i-- > 0) { + blockToRepeat + } +} + +macro includef fname { + printf("Including %s\n", fname) + include fname +} + + +} ; *** end -- mif (!isDefined(_macros_)) *** diff --git a/doc/macross.1 b/doc/macross.1 new file mode 100644 index 0000000..acd1e17 --- /dev/null +++ b/doc/macross.1 @@ -0,0 +1,108 @@ +.TH MACROSS 1 "27 November 1985" +.UC 4 +.SH NAME +macross \- Macross assembler +.SH SYNOPSIS +.B macross +[ option ] ... file ... +.SH DESCRIPTION +.I Macross +is a fancy macro cross assembler for the 6502. +.I Macross +assembles the given files in the order specified on the command line. Macross +source file names must end with ``\fB.m\fR''. +.PP +The following options are interpreted by +.IR macross . +.TP +.BI \-l " listfile" +Produce an assembler listing in the file +.IR listfile +showing the object code generated. If +.IR listfile +is ``\fB-\fR'' the listing will be printed on the standard output. +.TP +.B \-m +When listing is enabled, causes the assembler to include in the listing +synthesized lines showing the code generated by macros. +.TP +.B \-g +Suppress assembly-time garbage collection of unused dynamic storage space +(may speed up small assemblies). +.TP +.B \-d +Print esoteric debug information showing parse trees generated by the parser. +(Generally not of interest to the casual user). +.TP +.B \-D +Print even more esoteric debug information showing parser states. (Almost +certainly not of interest to the casual user). +.TP +.B \-e +Print esoteric debug information showing emitted binary as it is generated. +(Even duller than parser states). +.TP +.BI \-s " dumpfile" +Place a symbol table dump in the file +.IR dumpfile +at the end of assembly. If +.IR dumpfile +is ``\fB-\fR'', the symbol table dump will go to the standard output. +.TP +.BI \-S " dumpfile" +As \fB-s\fR, except also dump internal symbols normally not of interest. +.TP +.BI \-h " dumpfile" +As \fB-s\fR, except that the symbols are dumped in the form of Macross +\fBdefine\fR statements. +.TP +.BI \-H " dumpfile" +As \fB-h\fR, except that it only dumps defined external symbols. +.TP +.B \-a +If a symbol dump has been specified, have it include unreferenced \fBdefine\fR +symbols (these are not normally displayed in a symbol table dump listing). +.TP +.BI \-o " output" +Name the final output file +.IR output . +If this option is not used the output will be placed in the file `m.out'. +.TP +.BI \-P " processor" +Assemble for the target processor +.IR processor . +The allowed values are \fB6502\fR and \fB68000\fR. If this option is not +used \fB6502\fR will be assumed. +.TP +.B \-c +Make the object file produced be a linkable object suitable for use with the +\fIslinky\fR linker. +.TP +.B \-p +Produce position independent code for the \fBelse\fP clause of +\fBif-then-else\fP statements. This is accomplished by emitting a +\fBbcc/bcs\fP branch pair instead of a \fBjmp\fP instruction. +.TP +.B \-t +Be terse about error messages. Output no more than one error message for a +given line. +.TP +.B \-u +Don't discard the temporary intermediate files generated during the listing +process when the assemble exits (used for debugging the listing facility). +.TP +.B \-v +Print the \fImacross\fP version number on the standard output before beginning +assembly. +.TP +.B \-B +When generating branches for nested \fBif-then-else\fR constructs, generate +code like that generated by \fBa65\fR. This code will be slightly less +efficient but will be completely backwards compatible. +.SH "SEE ALSO" +slinky(1), the Macross manual +.SH DIAGNOSTICS +The diagnostics produced by Macross are \fIintended\fR to be self-explanatory. +.SH BUGS +Errors in the input may sometimes produce bizarre and unexpected results. +There are probably lots of bugs that are as yet undetected. diff --git a/doc/slinky.1 b/doc/slinky.1 new file mode 100644 index 0000000..102c6f9 --- /dev/null +++ b/doc/slinky.1 @@ -0,0 +1,66 @@ +.TH SLINKY 1 "28 February 1986" +.UC 4 +.SH NAME +slinky \- slinky linker +.SH SYNOPSIS +.B slinky +[ option ] ... file ... +.SH DESCRIPTION +.I Slinky +is a multi-file relocating object linker designed to be used in conjunction +with the +.I Macross +assembler. +.I Slinky +links the given +.I Macross +object files in the order specified on the command line together into one +executable object file. +.PP +The following options are interpreted by +.IR slinky . +.TP +.B \-d +Print esoteric debug information (you don't want to use this). +.TP +.B \-e +Print different esoteric debug information (you don't want to use this +either). +.TP +.B \-v +Print the \fIslinky\fP version number on the standard output before linking. +.TP +.BI \-l " hexaddress" +By default, \fIslinky\fP starts putting relocatable modules at location 0x100. +The \fB-l\fR option lets you tell it to put things anywhere. This option can +be used more than once in a single link command and can be interspersed with +the names of the object files being linked. Thus +.br + \fBslinky foo.obj -l 0x3800 bar.obj baz.obj -l 0x5000 snood.obj\fP +.br +loads `foo.obj' starting at location 0x100, `bar.obj' and `baz.obj' +consecutively starting at location 0x3800 and `snood.obj' starting at location +0x5000. +.TP +.BI \-o " output" +Name the final output file +.IR output . +If this option is not used the output will be placed in the file `s.out'. +.TP +.BI \-m " mapfile" +Generate a load map listing, showing the values of all symbols after linking +and put it in the file +.IR mapfile . +If +.IR mapfile +is ``\fB-\fR'', the load map will go to the standard output. +.TP +.B \-n +If generating a load map, suppress the printing of the names of the files that +reference each symbol. +.SH "SEE ALSO" +macross(1), the Macross manual +.SH DIAGNOSTICS +The diagnostics produced by Slinky are \fIintended\fR to be self-explanatory. +.SH BUGS +Who knows what bugs lurk there? Nobody's used it yet! diff --git a/doc/writeup_6502.itr b/doc/writeup_6502.itr new file mode 100644 index 0000000..e76fc2d --- /dev/null +++ b/doc/writeup_6502.itr @@ -0,0 +1,2124 @@ +.ds [ \s+1\z[\h'1p'\z[\h'-1p'\s-1\0 +.ds ] \s+1\z]\h'-1p'\z]\s-1\0 +.ds Z \s+1\z]\h'-1p'\z]\h'3p'\z*\s-1\0 +.ds Da July 7, 1986 +.TL +\s+6Macross 6502\s-6 +\"Macross +.AU +an assembler for people who hate assembly language +by +Chip Morningstar +.AI +Lucasfilm Ltd. Games Division +\\*(Da +.ds LH Macross +.ds CH \\*(Da +.ds RH 6502 Version +.ds LF Lucasfilm Ltd. Proprietary Information +.ds CF - % - +.ds RF CONFIDENTIAL +.AB +This document describes the 6502 version of \fIMacross\fR, a super-duper +cross-assembler that has actually been used! +.AE +.SH +\s+3Introduction\s-3 +\"Introduction +.PP +\fIMacross\fR is a generic cross assembler for a variety of different +microprocessors. This document describes the 6502 version of \fIMacross\fR. +\fIMacross\fR differs from many macro assemblers in that it provides a number +of ``higher level'' constructs not traditionally found in assembly language. +These include block-structured flow-of-control statements (\fCif\fR, +\fCwhile\fR, etc.) and the ability to define record-oriented data structures +(\fCstruct\fR). In addition, it contains a powerful macro capability that is +based on syntactic structural manipulations rather than simple text +substitution. \fIMacross\fR is, in fact, a complete block-structured +programming language in its own right which is interpreted at assembly time. +.SH +\s+3General Form of \fIMacross\fP Statements\s-3 +\"General Form of \fIMacross\fP Statements +.PP +Stylistically, much of \fIMacross\fR is patterned after \fBC\fR. In +particular, the form of many keywords and of block structured entities is +derived from \fBC\fR. Unlike \fBC\fR however, \fIMacross\fR follows the +convention of more traditional assemblers that statements are delimited by +line boundaries (i.e., one statement per line, with the end of a line ending a +statement). +.PP +In general, spaces and tabs are treated as whitespace characters and are +ignored. Therefore, such characters may be used as the assembly language +programmer desires to format his or her program according to personal taste. +For the convenience of the programmer, \fIMacross\fR relaxes the syntax rule +that newlines always end a statement: newlines may also be treated as +whitespace characters (again, for purposes of formatting) in places where it +would be syntactically unambiguous to do so (i.e., where a statement obviously +cannot terminate, such as after a comma). For example: +.nf + + \fCbyte 1, 2, 3, 4, + 5, 6, 7, 8\fR + +.fi +is allowed and is equivalent to +.nf + + \fCbyte 1, 2, 3, 4, 5, 6, 7, 8 + +.fi +.PP +Comments begin with a semicolon (``\fC;\fR'') and continue to the end of the +line, as is common in many assemblers. In addition, \fIMacross\fR supports +\fBC\fR style comments bracketed by ``\fC/*\fR'' and ``\fC*/\fR''. +.PP +As with most assemblers, \fIMacross\fR statements are allowed to begin with a +label (or several labels, if you like). A label is denoted by an identifier +followed by a colon (``\fC:\fR''). There is no requirement that the label +start in column 1, or anything like that. Labels, if present, merely must +precede anything else in a statement. +.PP +An identifier is just what you'd expect from all your years of programming +experience: a string of letters and digits that must begin with a letter. As +is traditional in Unix* +.FS * +Unix is a footnote of Bell Laboratories. +.FE +land, the underscore character (``\fC_\fR'') is considered to be a letter +(smacks of hubris that, but tradition is tradition). Departing from Unix +tradition, upper- and lower-case characters are not distinct from each other +for purposes of distinguishing identifiers. If you use mixed case for +stylistic reasons, \fIMacross\fR will remember the case of the letters in an +identifier when it was first defined, so that symbol table dumps and +cross-reference listings will retain whatever case usage style you've adopted. +There is, in principle, no restriction imposed upon the length of identifiers. +.SH +\s+3The Language\s-3 +.PP +In what follows, things in \fCthis typewriter like typeface\fR are keywords +and characters that are used literally. Things in \fIitalics\fR are other +kinds of syntactic entities. Double brackets (``\*['' and ``\*]'') enclose +things that are optional, while brackets followed by an asterisk (``*'') +enclose things that may be optionally repeated zero or more times. +.NH 1 +The Instruction Statement +.PP +The most elementary \fIMacross\fR statement is the instruction statement, +wherein the programmer specifies a machine instruction to be assembled. The +instruction statement is +.nf + +\*[ \fIlabel\fR \*Z \fIopcode\fR \*[ \fIoperand\fR \*[ \fC,\fR \fIoperand\fR \*Z \*] + +.fi +just like every assembler ever made (except \fBa65\fR, of course). +\fIOpcode\fR is an identifier which is either a machine instruction mnemonic +(a list of which mnemonics are accepted by \fIMacross\fR is given in +\fBAppendix F\fR at the end of this document) or a macro name. For example: +.nf + + \fCand foobar\fR + \fCsomeMacro foo, bar, baz, bletch\fR + +.fi +.PP +The operands of an instruction may be any of the various types of operands +allowed by the various addressing modes of the target processor. In the case +of the 6502, these are: +.NH 2 +\fRDirect addressing +.PP +Direct addresses take the form +.nf + + \fIexpression\fR + +.fi +and are used both for instructions that use direct addressing and ones that +use relative addressing (the offset is computed automatically by +\fIMacross\fR). +.NH 2 +\fRIndirect addressing +.PP +Indirect addresses take the form +.nf + + \fC@\fR \fIexpression\fR + +.fi +Of course, the only 6502 instruction which accepts an indirectly addressed +operand is \fCjmp\fR. +.NH 2 +\fRImmediate operands +.PP +Immediate operands take the form +.nf + + \fC#\fR \fIexpression\fR + +.fi +In the 6502, immediate mode operands are restricted to eight bit quantities. +\fIMacross\fR will give an error message if the operand value is larger than +this. +.NH 2 +\fRIndexed addressing +.PP +Indexed addressing operands take the forms +.nf + + \fCx\fR \fC\s-1[\s+1\fR \fIexpression\fR \fC\s-1]\s+1\fR + \fCy\fR \fC\s-1[\s+1\fR \fIexpression\fR \fC\s-1]\s+1\fR + +.fi +An alternate form of indexed addressing which is supported by \fIMacross\fR +allows the symbolic selection of a field of a \fCstruct\fR pointed to by an +index register +.nf + + \fCx\fR \fC.\fR \fIidentifier\fR \*[ \fC.\fR \fIidentifier\fR \*Z + \fCy\fR \fC.\fR \fIidentifier\fR \*[ \fC.\fR \fIidentifier\fR \*Z + +.fi +This is explained in greater detail in the sections on \fCstruct\fRs and +expressions below. +.NH 2 +\fRPre-indexed indirect addressing +.PP +Pre-indexed indirect addressing is specified by operands of the form +.nf + + \fC@\fR \fCx\fR \fC\s-1[\s+1\fR \fIexpression\fR \fC\s-1]\s+1\fR + +.fi +As with ordinary indexed addressing, there is a form of pre-indexed indirect +addressing which uses \fCstruct\fR fields +.nf + + \fC@\fR \fCx\fR \fC.\fR \fIidentifier\fR \*[ \fC.\fR \fIidentifier\fR \*Z +.fi +.NH 2 +\fRPost-indexed indirect addressing +.PP +Post-indexed indirect addressing is specified by operands of the form +.nf + + \fCy\fR \fC\s-1[\s+1\fR \fC@\fR \fIexpression\fR \fC\s-1]\s+1\fR + +.fi +There is no \fCstruct\fR-oriented form of post-indexed indirect addressing +since there doesn't seem to be any consistent interpretation of such a thing +that makes sense. +.NH 2 +\fRRegister addressing +.PP +The only register in the 6502 which is used as an operand in its own right is +the accumulator +.nf + + \fCa\fR + +.fi +For the sake of completeness, so that macros may have them as operands, +\fIMacross\fR also allows either of the index registers to be used as operands +.nf + + \fCx\fR + \fCy\fR + +.fi +These are equivalent to +.nf + + \fCx[0]\fR + \fCy[0]\fR + +.fi +Note that \fCa\fR, \fCx\fR and \fCy\fR are reserved words in the \fIMacross\fR +language and so cannot be used as labels, variable names, etc. It might seem +natural to call a variable \fCx\fR but you can't. Sorry. +.NH 2 +\fRText operands +.PP +For the sake of macros, text strings may also be used as operands +.nf + + \fC"\fIany string you like\fC"\fR + +.fi +The same conventions regarding escaped characters (using ``\fC\\\fR'') that +are followed by \fBC\fR are followed by \fIMacross\fR. These are documented +in \fBAppendix E\fR. Note that on many target machines the codes that these +escape sequences stand for are meaningless. They are provided primarily as a +convenience for writing calls to \fCprintf()\fR. +.NH 1 +The Flow of Control Statements +.PP +\fIMacross\fR provides a number of statements which allow program flow of +control to be specified in a \fBC\fR-like block structured fashion. This +include a conditional execution statement (\fCif\fR) and three conditional +loop statements (\fCwhile\fR, \fCdo-while\fR and \fCdo-until\fR). These +statements assemble into the appropriate conditional branches and jumps to +realize the desired construct. +.NH 2 +If\fR statement +.PP +The \fCif\fR statement has the following form +.nf + +\*[ \fIlabel\fR \*Z \fCif\fR \fC(\fR \fIcondition\fR \fC)\fR \fC{\fR + \*[ \fIstatement\fR \*Z + \fC}\fR \*[ \fCelseif\fR \fC(\fR \fIcondition\fR \fC)\fR \fC{\fR + \*[ \fIstatement\fR \*Z + \fC}\fR \*Z \*[ \fCelse\fR \fC{\fR + \*[ \fIstatement\fR \*Z + \fC}\fR \*] + +.fi +\fIcondition\fR is either the name of one of the target processor's hardware +condition codes such as can be tested for in a conditional branch instruction +(e.g., \fCcarry\fR, \fCoverflow\fR, etc.\(em the complete list is in +\fBAppendix B\fR) or one either of these negated using the ``logical not'' +operator (``\fC!\fR'') or the name of one of the more complex conditions +which \fIMacross\fR understands (\fCgeq\fR, \fClt\fR, etc., discussed +shortly). The condition is used to determine the appropriate type of branch +instruction(s) to use. For example, +.nf + + \fCif (plus) {\fR + \fIstatements-1\fR + \fC} elseif (carry) {\fR + \fIstatements-2\fR + \fC} else {\fR + \fIstatements-3\fR + \fC}\fR + +.fi +expands into this (the labels are made up for illustrative purposes only): +.nf + + \fCbmi temp1 + \fIstatements-1 + \fCjmp temp3 +temp1: bcc temp2 + \fIstatements-3 + \fCjmp temp3 +temp2: \fIstatements-3 +\fCtemp3: \fIwhatever follows\fR + +.fi +The keyword \fCelseif\fR may be used as shown, or specified as two separate +keywords, \fCelse if\fR, depending on the programmer's whim. +.PP +\fIMacross\fR knows about certain conditions which are more complex than those +than can be realized with single conditional branch instructions. These +conditions correspond to the results of comparison operations (such as +\fCgeq\fR \(em ``greater than or equal to'') that may require rather +complicated sequences of conditional branches to implement. These may be used +in any location where an ordinary condition may be used. One simply should +keep in mind that they can result in a non-trivial amount of code being +generated, if one is concerned about speed of execution. The complete list of +these complex conditions along with the object code that they produce is given +in \fBAppendix B\fR. +.NH 2 +While\fR statement +.PP +The \fCwhile\fR statement has the following form +.nf + +\*[ \fIlabel\fR \*Z \fCwhile\fR \fC(\fR \fIcondition\fR \fC)\fR \fC{\fR + \*[ \fIstatement\fR \*Z + \fC}\fR + +.fi +\fIcondition\fR is as described above for the \fCif\fR statement. An example +of the \fCwhile\fR statement would be +.nf + + \fCwhile (!carry) {\fR + \fIstatements\fR + \fC}\fR + +.fi +which would turn into +.nf + + bcs temp1 +\fCtemp2: \fIstatements + \fCbcc temp2 +temp1: \fIwhatever follows\fR + +.fi +.NH 2 +Do-while\fR statement +.PP +The \fCdo-while\fR statement is similar to the \fCwhile\fR statement except +that the condition is tested at the bottom of the loop. It has the form +.nf + +\*[ \fIlabel\fR \*Z \fCdo\fR \fC{\fR + \*[ \fIstatement\fR \*Z + \fC}\fR \fCwhile\fR \fC(\fR \fIcondition\fR \fC)\fR + +.fi +For example +.nf + + \fCdo {\fR + \fIstatements\fR + \fC} while (equal)\fR + +.fi +which is equivalent to +.nf + +\fCtemp: \fIstatements + \fCbeq temp\fR + +.fi +.NH 2 +Do-until\fR statement +.PP +The \fCdo-until\fR statement is the same as the \fCdo-while\fR statement +except that the sense of the condition is negated. It has the form +.nf + +\*[ \fIlabel\fR \*Z \fCdo\fR \fC{\fR + \*[ \fIstatement\fR \*Z + \fC}\fR \fCuntil\fR \fC(\fR \fIcondition\fR \fC)\fR + +.fi +For example +.nf + + \fCdo {\fR + \fIstatements\fR + \fC} until (equal)\fR + +.fi +which is equivalent to +.nf + +\fCtemp: \fIstatements + \fCbne temp\fR + +.fi +.NH 1 +The Data Statements +.PP +The data statements allow the allocation of memory space and the storage of +constant data. These statements are like the ones found in most assemblers. +There are several different forms, each for a different type of data. +.NH 2 +Block\fR statement +.PP +The \fCblock\fR statement allocates blocks of memory without initializing the +bytes to any particular value (actually, the loader will in all likelihood +initialize these to 0, but it is probably not really wise to rely on this). +It has the form +.nf + +\*[ \fIlabel\fR \*Z \fCblock\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z + +.fi +The \fIexpression\fRs are the sizes of the blocks to reserve, expressed in +bytes. +.NH 2 +Align\fR statement +.PP +The \fCalign\fR statement aligns the current location counter to an integer +multiple of some value (e.g., to align with a word boundary). It has the form +.nf + +\*[ \fIlabel\fR \*Z \fCalign\fR \fIexpression\fR + +.fi +The \fIexpression\fR is the multiple to which the current location counter is +to be aligned. For example, +.nf + + \fCalign 2\fR + +.fi +would align the current location to a word boundary, while +.nf + + \fCalign 0x100\fR + +.fi +would align to a page boundary. +.NH 2 +Constrain\fR statement +.PP +The \fCconstrain\fR statement provides a means of constraining a portion of +code or data to be located within a region of memory bounded by addresses of +integer multiples of some value (e.g., within a page). Its form is +.nf + + \fCconstrain\fR \fC(\fR \fIboundary\fR \fC)\fR \fC{\fR + \*[ \fIstatement\fR \*Z + \fC}\fR + +.fi +\fIBoundary\fR may be any expression which evaluates to a number. The +\fIstatement\fRs are assembled normally. If assembling in absolute mode, an +error message is issued if the current location counter crosses an integer +multiple of \fIboundary\fR. If assembling in relocatable mode, information +about the constraint will be output in the object file and the contents of the +constrained block will be relocated as needed to satisfy the constraint (note +that this means that it is unsafe to assume that the things in the assembly +source immediately before the \fCconstrain\fR statement, the contents of the +constrain block itself, and the things in the assembly source immediately +after the \fCconstrain\fR statement will be located in contiguous locations in +the eventual target machine address space). For example, +.nf + + \fCconstrain (0x100) {\fR + \fIstatements\fR + \fC}\fR + +.fi +constrains the given statements to all fit within a page. +.NH 2 +Word\fR statement +.PP +The \fCword\fR statement allocates words, i.e., two byte chunks, of memory. +It takes the form +.nf + +\*[ \fIlabel\fR \*Z \fCword\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z + +.fi +The \fIexpression\fRs must evaluate to quantities that can be contained in 16 +bits, of course. For example, +.nf + + \fCword 0x1234, foobar\fR + +.fi +would allocate two words, the first of which would be initialized to the +hexadecimal value \fC0x1234\fR and the second to whatever the value of +\fCfoobar\fR is. +.NH 2 +Dbyte\fR statement +.PP +The \fCdbyte\fR statement is just like the \fCword\fR statement, except that +the word is byte-swapped in memory. Its form is +.nf + +\*[ \fIlabel\fR \*Z \fCdbyte\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z +.fi +.NH 2 +Long\fR statement +.PP +The \fClong\fR statement allocates longwords, i.e., four byte chunks, of +memory. It takes the form +.nf + +\*[ \fIlabel\fR \*Z \fClong\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z + +.fi +The \fIexpression\fRs must evaluate to quantities that can be contained in 32 +bits, of course. For example, +.nf + + \fClong 0x12345678, foobar\fR + +.fi +would allocate two longwords, the first of which would be initialized to the +hexadecimal value \fC0x12345678\fR and the second to whatever the value of +\fCfoobar\fR is. +.NH 2 +Byte\fR statement +.PP +The \fCbyte\fR statement is similar to the \fCword\fR and \fCdbyte\fR +statements, except that it allocates single byte chunks. Its form is +.nf + +\*[ \fIlabel\fR \*Z \fCbyte\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z + +.fi +An \fIexpression\fR, in this case, is either an ordinary expression (see +\fBExpressions\fR, below) which must evaluate to an 8-bit quantity, indicating +the value for a single byte to be reserved, or a string (see above, under the +discussion of text operands), indicating that the characters in the string +should be placed in memory at the current location. +.NH 2 +String\fR statement +.PP +The \fCstring\fR statement is much like the \fCbyte\fR statement, except that +the values indicated are followed in memory by a zero byte. This enables the +convenient declaration and allocation of NULL terminated character strings. +This feature is of little use in the 6502 version of \fIMacross\fR but is +provided for compatability with future versions targeted at more sophisticated +processors. The form of the \fCstring\fR statement is +.nf + +\*[ \fIlabel\fR \*Z \fCstring\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z +.fi +.NH 2 +Struct\fR statement +.PP +The \fCstruct\fR statement enables the declaration and allocation of +record-oriented data structures. There are two forms of the \fCstruct\fR +statement, the first of which declares a \fCstruct\fR record type, and the +second of which causes space to be set aside in memory for a \fCstruct\fR that +has already been declared. The form of the first type of \fCstruct\fR +statement is +.nf + +\*[ \fIlabel\fR \*Z \fCstruct\fR \fC{\fR + \*[ \fIdataStatement\fR \*Z + \fC}\fR \fIname\fR + +.fi +\fIdataStatement\fRs are any of the data statements described in this section +(section 3). \fIName\fR becomes the name of the \fCstruct\fR. Any labels +inside the \fCstruct\fR become \fIfields\fR of the data structure which may be +referred to later in expressions using the ``\fC.\fR'' operator, as in +\fBC\fR. A more complete description of the semantics of \fCstruct\fRs is +given in the section below on expressions. +.PP +The first form of the \fCstruct\fR statement, called a ``\fCstruct\fR +definition'', lays out the constituent parts of a data structure and gives +those names to those parts. The second form of the \fCstruct\fR statement, +called a ``\fCstruct\fR instantiation'', +.nf + +\*[ \fIlabel\fR \*Z \fCstruct\fR \fIname\fR + +.fi +causes storage for the \fCstruct\fR named by \fIname\fR to be allocated. A +\fCstruct\fR definition \fImay not\fR contain another \fCstruct\fR definition, +but it \fImay\fR contain a \fCstruct\fR instantiation. For example, +.nf + + \fCstruct { + pointer: block 2 + class: block 1 + } fooThing\fR + +.fi +would create a \fCstruct\fR called \fCfooThing\fR. Then, +.nf + +\fCfooLabel: struct fooThing\fR + +.fi +would allocate one at the current location at the address labeled +\fCfooLabel\fR. This could then be used as follows: +.nf + + \fCand fooLabel.class + jmp @fooLabel.pointer\fR + +.fi +which would AND the accumulator with the \fCclass\fR field of the \fCstruct\fR +and then jump to wherever the \fCpointer\fR field pointed to. If the \fCx\fR +index register already contained the address of this \fCstruct\fR, then one +could say +.nf + + \fCand x.class\fR + +.fi +.NH 1 +The Symbol Definition Statements +.PP +The various symbol definition statements allow the declaration of symbolic +variables and values and the definition of macros and functions. +.NH 2 +Define\fR statement +.PP +The \fCdefine\fR statement enables the programmer to create symbolic names for +values. It has two forms. The first +.nf + + \fCdefine\fR \fIsymbolname\fR + +.fi +creates a new symbol, \fIsymbolname\fR (an identifier), and gives it the +special value \fCunassigned\fR. Any attempt to take the value of an +unassigned symbol will cause an error message from the assembler. The symbol +will, however, cause the \fCisDefined()\fR built-in function (see +\fBExpressions\fR, below) to return \fCTRUE\fR if passed as an argument. It +is also an error to \fCdefine\fR a symbol that has already been \fCdefine\fRd. +.PP +The second form of the \fCdefine\fR statement +.nf + + \fCdefine\fR \fIsymbolname\fR \fC=\fR \fIexpression\fR + +.fi +creates the symbol and gives it the value obtained by evaluating +\fIexpression\fR (see \fBExpressions\fR, below). Actually, what \fCdefine\fR +does is create a symbolic name for \fIexpression\fR and the save this +expression away in a secret place. This means that symbols in +\fIexpression\fR may be forward references, e.g., labels that haven't been +encountered yet. It is also possible to forward reference to symbols that are +defined by future \fCdefine\fR statements, for example: +.nf + + \fCdefine foo = bar + 2 + define bar = 47\fR + +.fi +effectively defines \fCfoo\fR to be \fC49\fR. Beware, however, as there is no +way for the assembler to detect mutually recursive references of this sort, so +that +.nf + + \fCdefine foo = bar + 2 + define bar = foo + 2\fR + +.fi +will be happily swallowed without complaint, until you actually try to use +\fCfoo\fR or \fCbar\fR in an instruction, whereupon \fIMacross\fR's expression +evaluator will go into infinite recursion until it runs out of stack space and +crashes the assembler (it looks to see what \fCfoo\fR is and sees that it's +\fCbar + 2\fR, so it looks to see what \fCbar\fR and see that it's \fCfoo + +2\fR, so it looks to see what \fCfoo\fR is... To have the assembler detect +and signal this error would, in the general case, add much complication and +inefficiency (read: make your programs assemble a lot more slowly) for little +return). +.PP +The scope of symbols defined in either of these two ways extends in time from +the definition itself to the end of the assembly. +.NH 2 +Variable\fR statement +.PP +The \fCvariable\fR statement enables the programmer to declare symbolic +variables for future use. Similar to the \fCdefine\fR statement, it has two +forms. The first +.nf + + \fCvariable\fR \fIsymbolname\fR + +.fi +creates a variable named \fIsymbolname\fR and gives it the special value +\fCunassigned\fR, just like the analogous \fCdefine\fR statement. +.PP +The second form of the \fCvariable\fR statement +.nf + + \fCvariable \fIsymbolname\fR \fC=\fR \fIexpression\fR + +.fi +creates the variable and gives it the value obtained by evaluating +\fIexpression\fR. The scope of variables defined in either of these two ways +extends from the \fCvariable\fR statement itself to the end of the assembly +(i.e., the variable is global). +.PP +The difference between the \fCdefine\fR statement and the \fCvariable\fR +statement is that the \fCdefine\fR statement creates what is in essence a +constant whereas the \fCvariable\fR statement creates a true variable. The +value of a variable may change (e.g., it may be assigned to) during the course +of assembly. In addition, the expression which establishes a symbol's value +in a \fCdefine\fR statement may contain forward references (i.e., labels whose +values are unknown because they haven't been encountered yet) whereas the +expression assigning an initial value to a variable must be made up of terms +all of whose values are known at the time the \fCvariable\fR statement is +encountered in the assembly. +.PP +A variable may also be declared as an array, using the form +.nf + + \fCvariable \fIsymbolname \fC[ \fIlength \fC]\fR + +.fi +where \fIlength\fP is an expression that indicates the number of elements the +array is to have. \fIMacross\fR arrays are zero-based, so the elements are +indexed from 0 to \fIlength\fP-1. As with ordinary variables, the elements of +the array may be initialized in the \fCvariable\fR statement using a statement +of the form +.nf + + \fCvariable \fIsymbolname \fC[ \fIlength \fC] = \fIexpression +\fR\*[ \fC, \fIexpression \fR\*Z + +.fi +The \fIexpression\fPs are assigned sequentially into the elements of the +array. If the array length is greater than the number of \fIexpression\fPs +given, the remaining elements are filled with zeroes. Of course, you should +not specify more than \fIlength\fP expressions or the assembler will complain +at you. +.NH 2 +Macro\fR statement +.PP +The \fCmacro\fR statement is used to define macros (surprise!). Its syntax is +.nf + + \fCmacro\fR \fImacroname\fR \*[ \fIargumentname\fR \*[ \fC,\fR \fIargumentname\fR \*Z \*] \fC{\fR + \*[ \fIstatement\fR \*Z + \fC}\fR + +.fi +where \fImacroname\fR is just that and the \fIargumentname\fRs are identifiers +corresponding to the formal parameters of the macro (in the classical +fashion). When the macro is called, the call arguments are bound to these +symbols and then \fIMacross\fR assembles the \fIstatement\fRs which form the +macro body. The scope of these symbols is limited to the inside of the macro +body and their values go away when the macro expansion is completed. The +\fIstatement\fRs may be any valid \fIMacross\fR statements except for +\fCmacro\fR statements and \fCfunction\fR statements (i.e., macro and function +definitions may not be nested). +.PP +Statement labels used inside macros can be made local to the macro by +preceding the label identifier with a dollar sign (``\fC$\fR''). For +example, +.nf + + \fCmacro fooMac arg { + jmp $foo + word arg + $foo: nop + }\fR + +.fi +defines a macro named \fCfooMac\fR that emits a word of data that gets jumped +over. The label \fC$foo\fR is local to the macro: both the reference to it +in the first line of the macro and its definition on the third will only be +seen inside the macro. Each time the macro is called, the \fCjmp\fR will +refer to the location two instructions ahead, and any other macros that might +contain \fC$foo\fR will not affect this nor will they be affected by this. +.PP +It is possible to define macros which take a variable number of arguments. +This is accomplished by following the last argument in the \fCmacro\fP +statement by \fC[ ]\fR. This declares the argument to be an array, which gets +assigned a list of all of the parameters not accounted for by the other +declared arguments. This array may be interrogated with the +\fCarrayLength()\fR built-in function (to find out how many extra parameters +there were) and accessed just like a regular array. For example, +.nf + + \fCmacro enfoon precision, args[] { + mvariable len = arrayLength(args) + mvariable i + word precision + mfor (i=0, i\fR'' \(em not relevant here. +.LP +All of the assignment operators (``\fC+=\fR'', ``\fC-=\fR'', etc.) +\fIare\fR supported by \fIMacross\fR. +.LP +\fIMacross\fR reinterprets the \fC.\fR operator in that ``\fIexpression\fC . +\fIstructfieldname\fR'' is interpreted as adding the offset value implied by +\fIstructfieldname\fR (i.e., the distance in bytes into a \fCstruct\fR to +reach the named field) to the address that is the value of \fIexpression\fR. +.LP +\fIMacross\fR adds to the operator set the following: +.IP +[1] ``\fC?\fR'' \(em as a unary operator, takes the high order byte of the +word value that is its argument. +.IP +[2] ``\fC/\fR'' \(em as a unary operator, takes the low order byte of the +word value that is its argument. +.IP +[3] ``\fC^^\fR'' \(em a binary operator, denotes logical exclusive-OR. This +is simply an orthogonal extension for the sake of completeness. +.LP +Of course, parenthesis can be used at any point to override the normal +precedence of the various operators. A full list of all the operators that +\fIMacross\fR understands is given in \fBAppendix D\fR. +.NH 1 +\fRExpression evaluation +.PP +In order to make the most effective use of expressions in the \fIMacross\fR +environment, it is helpful (and at times necessary) to understand how and when +\fIMacross\fR evaluates them. +.PP +When \fIMacross\fR evaluates an expression, it may have one of three sorts of +results. These are \fIsuccess\fR, \fIundefined\fR, and \fIfailure\fR. A +\fIsuccess\fR result means that \fIMacross\fR encountered no problems +evaluating the expression, and whatever value it evaluated to is just used as +needed. A \fIfailure\fR result indicates that there was a problem of some +sort. Usually this is a result of some user error. In any case, an +appropriate diagnostic message will be issued by the assembler and the +statement in which the expression was found will not be assembled. +.PP +An \fIundefined\fR result is where the complications, if any, arise. An +expression will evaluate to an \fIundefined\fR result if one or more of the +terms of the expression are undefined symbols. Usually these are labels which +simply haven't been encountered yet (i.e., they are forward references). In +certain contexts, such as the operand of a machine instruction, this is a +legitimate thing to do, and in certain others, such as the condition of a +\fCmif\fR statement, this is not allowed at all. In the latter case, an +\fIundefined\fR result is just like a \fIfailure\fR result. In the former +case, the assembler is forced to get fancy in order to make it all work right. +.PP +What \fIMacross\fR does is squirrel away a copy of the expression along with a +pointer as to where in the object code the value of the expression is supposed +to go. At the end of assembly, the undefined label will presumably now be +defined, and \fIMacross\fR evaluates the saved expression and pokes the result +into the appropriate location. (If, at this point, the undefined label is +still undefined, an error message to that effect is issued). Clearly, if an +expression has side effects (such as changing the value of some global +variable), this can result in some confusing behavior. The \fIMacross\fR +assembler is smart enough to not let you do anything that has overt side +effects in an expression that is being saved away for future evaluation. The +things which are disallowed in such a case are assignments and uses of the +post- and pre-increment and decrement operators (``\fC++\fR'' and +``\fC--\fR''). Functions, however, may have side effects and \fIMacross\fR +does not try to prevent you from using function calls in expressions that get +saved for later evaluation. It can, and will, detect some, but not all, side +effects during the later evaluation and give a suitable error message. This +is because it is perfectly legitimate to use a function call to a function +that doesn't have side effects in an expression containing forward references. +.PP +If you are now totally confused, the only thing you need remember is: \fBDon't +ever use a call to a function that has side effects in an expression +containing a forward reference.\fR +.bp +.CD +\s+5\fBAppendix A \(em Macross 6502 Grammar\fR\s-5 +\"\s+4\fBAppendix A \(em Macross 6502 Grammar\fR\s-4 +.fi +.LP +.nf +\fR\fIprogram\fR: + \*[ \fIstatement\fR Newline \*Z Endfile + +\fIstatement\fR: +\*[ \fIlabel\fR \*Z \fIopcode\fR \*[ \fIoperand\fR \*[ \fC,\fR \fIoperand\fR \*Z \*] +\*[ \fIlabel\fR \*Z \fCif\fR \fC(\fR \fIcondition\fR \fC)\fR \fIblock\fR + \*[ \fCelseif\fR \fC(\fR \fIcondition\fR \fC)\fR \fIblock\fR \*Z + \*[ \fCelse\fR \fIblock\fR \*] +\*[ \fIlabel\fR \*Z \fCwhile\fR \fC(\fR \fIcondition\fR \fC)\fR \fIblock\fR +\*[ \fIlabel\fR \*Z \fCdo\fR \fIblock\fR \fCwhile\fR \fC(\fR \fIcondition\fR \fC)\fR +\*[ \fIlabel\fR \*Z \fCdo\fR \fIblock\fR \fCuntil\fR \fC(\fR \fIcondition\fR \fC)\fR + \fIdataStatement\fR + \fCdefine\fR \fIidentifier\fR \*[ \fC=\fR \fIexpression\fR \*] + \fCvariable\fR \fIidentifier\fR \*[ \fC=\fR \fIexpression\fR \*] + \fCmacro\fR \fIidentifier\fR \*[ \fIidentifier\fR \*[ \fC,\fR \fIidentifier\fR \*Z \*] \fIblock\fR + \fCfunction\fR \fIidentifier\fR \fC(\fR \*[ \fIidentifier\fR \*[ \fC,\fR \fIidentifier\fR \*Z \*] \fC)\fR \fIblock\fR + \fCundefine\fR \fIidentifier\fR \*[ \fC,\fR \fIidentifier\fR \*Z +\*[ \fIlabel\fR \*Z \fIblock\fR + \fCmdefine\fR \fIidentifier\fR \*[ \fC=\fR \fIexpression\fR \*] + \fCmif\fR \fC(\fR \fIexpression\fR \fC)\fR \fIblock\fR + \*[ \fCmelseif\fR \fC(\fR \fIexpression\fR \fC)\fR \fIblock\fR \*Z + \*[ \fCmelse\fR \fIblock\fR \*] + \fCmwhile\fR \fC(\fR \fIexpression\fR \fC)\fR \fIblock\fR + \fCmdo\fR \fIblock\fR \fCwhile\fR \fC(\fR \fIexpression\fR \fC)\fR + \fCmdo\fR \fIblock\fR \fCuntil\fR \fC(\fR \fIexpression\fR \fC)\fR + \fCfreturn\fR \*[ \fIexpression\fR \*] + \fCmfor\fR \fC(\fR \fIexpression\fR \fC,\fR \fIexpression\fR \fC,\fR \fIexpression\fR \fC)\fR \fIblock\fR + \fCmswitch ( \fIselectionExpression \fC) {\fR + \*[ \fCmcase ( \fIexpression\fR \*[ \fC,\fI expression\fR \*Z \fC)\fI block\fR \*Z + \*[ \fCmdefault\fI block\fR \*] + \fC}\fR + \fCconstrain\fR \fC(\fR \fIexpression\fR \fC)\fR \fIblock\fR + \fCassert\fR \fC(\fR \fIexpression\fR \fC)\fR \*[ \fIexpression\fR \*] + \fCinclude\fR \fItextString\fR + \fCextern\fR \fIidentifier\fR \*[ \fC,\fR \fIidentifier\fR \*Z + \fCstart\fR \fIexpression\fR + \fCorg\fR \fIexpression\fR + \fCtarget\fR \fIexpression\fR + \fIexpression\fR + +\fIdataStatement\fR: +\*[ \fIlabel\fR \*Z \fCblock\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fCalign\fR \fIexpression\fR +\*[ \fIlabel\fR \*Z \fCword\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fClong\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fCdbyte\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fCbyte\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fCstring\fR \fIexpression\fR \*[ \fC,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fCstruct\fR \fC{\fR \*[ \fIdataStatement\fR \*Z \fC}\fR \fIidentifier\fR +\*[ \fIlabel\fR \*Z \fCstruct\fR \fIidentifier\fR + +\fIlabel\fR: \fIidentifier\fR \fC:\fR + +\fIoperand\fR: + \fIexpression\fR + \fC@\fR \fIexpression\fR + \fC#\fR \fIexpression\fR + \fCa\fR + \fCx\fR + \fCy\fR + \fCx\fR \fC\s-1[\s+1\fR \fIexpression\fR \fC\s-1]\s+1\fR + \fCx\fR \fC.\fR \fIidentifier\fR \*[ \fC.\fR \fIidentifier\fR \*Z + \fCy\fR \fC\s-1[\s+1\fR \fIexpression\fR \fC\s-1]\s+1\fR + \fCy\fR \fC.\fR \fIidentifier\fR \*[ \fC.\fR \fIidentifier\fR \*Z + \fC@\fR \fCx\fR \fC\s-1[\s+1\fR \fIexpression\fR \fC\s-1]\s+1\fR + \fC@\fR \fCx\fR \fC.\fR \fIidentifier\fR \*[ \fC.\fR \fIidentifier\fR \*Z + \fCy\fR \fC\s-1[\s+1\fR \fC@\fR \fIexpression\fR \fC\s-1]\s+1\fR + \fItextString\fR + +\fIblock\fR: \fC{\fR \*[ \fIstatement\fR Newline \*Z \fC}\fR + +\fItextString\fR: + \fC" \fIany string you like \fC"\fR + +\fIcondition\fR: + \fIconditionCode\fR + \fC!\fR \fIconditionCode\fR + +\fIexpression\fR: + \fIidentifier\fR + \fIidentifier\fR \fC(\fR \*[ \fIoperand\fR \*[ \fC,\fR \fIoperand\fR \*Z \*] \fC)\fR + \fInumber\fR + \fChere\fR + \fItextString\fR + \fC(\fR \fIexpression\fR \fC)\fR + \fC-\fR \fIexpression\fR + \fC!\fR \fIexpression\fR + \fC~\fR \fIexpression\fR + \fC?\fR \fIexpression\fR + \fC/\fR \fIexpression\fR + \fIexpression\fR \fC*\fR \fIexpression\fR + \fIexpression\fR \fC/\fR \fIexpression\fR + \fIexpression\fR \fC%\fR \fIexpression\fR + \fIexpression\fR \fC-\fR \fIexpression\fR + \fIexpression\fR \fC+\fR \fIexpression\fR + \fIexpression\fR \fC<<\fR \fIexpression\fR + \fIexpression\fR \fC>>\fR \fIexpression\fR + \fIexpression\fR \fC<\fR \fIexpression\fR + \fIexpression\fR \fC>\fR \fIexpression\fR + \fIexpression\fR \fC<=\fR \fIexpression\fR + \fIexpression\fR \fC>=\fR \fIexpression\fR + \fIexpression\fR \fC==\fR \fIexpression\fR + \fIexpression\fR \fC!=\fR \fIexpression\fR + \fIexpression\fR \fC&\fR \fIexpression\fR + \fIexpression\fR \fC|\fR \fIexpression\fR + \fIexpression\fR \fC^\fR \fIexpression\fR + \fIexpression\fR \fC&&\fR \fIexpression\fR + \fIexpression\fR \fC||\fR \fIexpression\fR + \fIexpression\fR \fC^^\fR \fIexpression\fR + \fIexpression\fR \fC.\fR \fIidentifier\fR + \fIidentifier\fR \fC=\fR \fIexpression\fR + \fIidentifier\fR \fC+=\fR \fIexpression\fR + \fIidentifier\fR \fC-=\fR \fIexpression\fR + \fIidentifier\fR \fC*=\fR \fIexpression\fR + \fIidentifier\fR \fC/=\fR \fIexpression\fR + \fIidentifier\fR \fC%=\fR \fIexpression\fR + \fIidentifier\fR \fC&=\fR \fIexpression\fR + \fIidentifier\fR \fC|=\fR \fIexpression\fR + \fIidentifier\fR \fC^=\fR \fIexpression\fR + \fIidentifier\fR \fC<<=\fR \fIexpression\fR + \fIidentifier\fR \fC>>=\fR \fIexpression\fR + \fIidentifier\fR \fC++\fR + \fIidentifier\fR \fC--\fR + \fC++\fR \fIidentifier\fR + \fC--\fR \fIidentifier\fR + +\fIidentifier\fR: + \*[\fCa\fR-\fCzA\fR-\fCZ_\fR\*]\*[\fCa\fR-\fCzA\fR-\fCZ_0\fR-\fC9\fR\*Z + +\fInumber\fR: + \fIdecimalNumber\fR + \fIoctalNumber\fR + \fIbinaryNumber\fR + \fIhexadecimalNumber\fR + \fIquarter\fR + +\fIdecimalNumber\fR: + \*[\fC1\fR-\fC9\fR\*]\*[\fC0\fR-\fC9\fR\*Z + +\fIoctalNumber\fR: + \fC0\fR\*[\fC0\fR-\fC7\fR\*Z + +\fIbinaryNumber\fR: + \fC0b\fR\*[\fC01\fR\*]\*[\fC01\fR\*Z + +\fIhexadecimalNumber\fR: + \fC0x\fR\*[\fC0\fR-\fC9a\fR-\fCf\fR\*]\*[\fC0\fR-\fC9a\fR-\fCf\fR\*Z + +\fIquarter\fR: + \fC0q\fR\*[\fC0\fR-\fC3\fR\*]\*[\fC0\fR-\fC3\fR\*Z + +.fi +.bp +.CD +\s+5\fBAppendix B \(em Condition Codes\fR\s-5 +\"\s+4\fBAppendix B \(em Condition Codes\fR\s-4 +.sp 1 +\s+3\fB(6502 version)\fR\s-3 +.fi +.PP +The \fIMacross\fR \fCif\fR, \fCwhile\fR, \fCdo-while\fR and \fCdo-until\fR +statements make use of symbols denoting the hardware condition codes of the +target processor which may be used as the conditions upon which conditional +branches are base. In the 6502 version of \fIMacross\fR, these are the +recognized condition code symbols: +.SH +\s+2\fBConditions which generate simple branches\fR\s-2 +.nf + \fCcarry\fR tests carry bit + + \fCequal\fR tests zero bit + \fCzero\fR + + \fCneq\fR (equivalent to, e.g., \fC!equal\fR) + + \fCminus\fR tests negative bit + \fCnegative\fR + + \fCplus\fR (equivalent to, e.g., \fC!minus\fR) + \fCpositive\fR + + \fCoverflow\fR tests overflow bit + +.fi +.SH +\s+2\fBConditions which generate complex branches\fR\s-2 +.NH 0 +lt\fR \(em less than (valid after \fCcmp\fR or \fCsbc\fR) +.PP +For example, +.nf + + \fCif (lt) {\fR + \fI...stuff...\fR + \fC}\fR + + generates + + \fCbcs temp\fR + \fI...stuff...\fR + \fCtemp:\fR +.fi +.NH 1 +leq\fR \(em less than or equal to (valid after \fCcmp\fR or \fCsbc\fR) +.PP +For example, +.nf + + \fCif (leq) {\fR + \fI...stuff...\fR + \fC}\fR + + generates + + \fCbeq temp1\fR + \fCbcs temp2\fR + \fCtemp1:\fR + \fI...stuff...\fR + \fCtemp2:\fR +.fi +.NH 1 +geq\fR \(em greater than or equal to (valid after \fCcmp\fR or \fCsbc\fR) +.PP +For example, +.nf + + \fCif (geq) {\fR + \fI...stuff...\fR + \fC}\fR + + generates + + \fCbcc temp\fR + \fI...stuff...\fR + \fCtemp:\fR +.fi +.NH 1 +gt\fR \(em greater than (valid after \fCcmp\fR or \fCsbc\fR) +.PP +For example, +.nf + + \fCif (gt) {\fR + \fI...stuff...\fR + \fC}\fR + + generates + + \fCbcc temp\fR + \fCbeq temp\fR + \fI...stuff...\fR + \fCtemp:\fR +.fi +.NH 1 +slt\fR \(em signed less than (valid after \fCsbc\fR only) +.PP +For example, +.nf + + \fCif (slt) {\fR + \fI...stuff...\fR + \fC}\fR + + generates + + \fCbvs temp1\fR + \fCbpl temp3\fR + \fCbmi temp2\fR + \fCtemp1: bmi temp3\fR + \fCtemp2:\fR + \fI...stuff...\fR + \fCtemp3:\fR +.fi +.NH 1 +sleq\fR \(em signed less than or equal to (valid after \fCsbc\fR only) +.PP +For example, +.nf + + \fCif (sleq) {\fR + \fI...stuff...\fR + \fC}\fR + + generates + + \fCbeq temp2\fR + \fCbvs temp1\fR + \fCbpl temp3\fR + \fCbmi temp2\fR + \fCtemp1: bmi temp3\fR + \fCtemp2:\fR + \fI...stuff...\fR + \fCtemp3:\fR +.fi +.NH 1 +sgt\fR \(em signed greater than (valid after \fCsbc\fR only) +.PP +For example, +.nf + + \fCif (sgt) {\fR + \fI...stuff...\fR + \fC}\fR + + generates + + \fCbeq temp3\fR + \fCbvs temp1\fR + \fCbmi temp3\fR + \fCbpl temp2\fR + \fCtemp1: bpl temp3\fR + \fCtemp2:\fR + \fI...stuff...\fR + \fCtemp3:\fR +.fi +.NH 1 +sgeq\fR \(em signed greater than or equal to (valid after \fCsbc\fR only) +.PP +For example, +.nf + + \fCif (sgeq) {\fR + \fI...stuff...\fR + \fC}\fR + + generates + + \fCbvs temp1\fR + \fCbmi temp3\fR + \fCbpl temp2\fR + \fCtemp1: bpl temp3\fR + \fCtemp2:\fR + \fI...stuff...\fR + \fCtemp3:\fR +.fi +.bp +.CD +\s+5\fBAppendix C \(em Built-In Functions\fR\s-5 +\"\s+4\fBAppendix C \(em Built-In Functions\fR\s-4 +.fi +.PP +Certain predefined built-in functions are supported by \fIMacross\fR for +reasons of convenience or syntactic or semantic irregularity. They are: +.LP +\fCaddressMode(\fIoperand\fC)\fR +.IP +Returns a number whose value indicates which addressing mode \fIoperand\fR +represents \fI((define these values))\fR. +.LP +\fCapply(\fImacname\fR \*[ \fC, \fIarg\fR \*Z \fC)\fR +.IP +Assembles the macro whose name is specified by the \fCstring\fR \fImacname\fR +with the macro arguments (if any) given by the \fIarg\fRs. +.LP +\fCarrayLength(\fIarray\fC)\fR +.IP +Returns the number of elements in the array \fIarray\fP. +.LP +\fCatascii(\fIstring\fC)\fR +.IP +Returns a string which is \fIstring\fR with each character mapped through an +ASCII to ATASCII (Atari's ASCII deviant character code) conversion table. +.LP +\fCatasciiColor(\fIstring\fC, \fIcolor\fC)\fR +.IP +Returns a string which is \fIstring\fR with each character mapped through the +ASCII to ATASCII conversion table, and then the two-bit value specified by +\fIcolor\fR OR'ed into the high order two bits of each character. +.LP +\fCisAbsoluteValue(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is an absolute (i.e., +non-relocatable) value, otherwise \fCFALSE\fR. +.LP +\fCisARegister(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is \fCa\fR (i.e., the +accumulator), otherwise \fCFALSE\fR. +.LP +\fCisBlock(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is a block, otherwise +\fCFALSE\fR. +.LP +\fCisBuiltInFunction(\fIsymbol\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIsymbol\fR is a built-in function, +otherwise \fCFALSE\fR. +.LP +\fCisConditionCode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is a condition code, +otherwise \fCFALSE\fR. +.LP +\fCisDefined(\fIsymbol\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIsymbol\fR has been defined, otherwise +\fCFALSE\fR. +.LP +\fCisDirectMode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if the address mode of \fIoperand\fR is +\fIdirect\fR, otherwise \fCFALSE\fR. +.LP +\fCisExternal(\fIsymbol\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIsymbol\fR is external (i.e., visible +outside the file in which it is defined), otherwise \fCFALSE\fR. +.LP +\fCisField(\fIsymbol\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIsymbol\fR is a field of a struct, +otherwise \fCFALSE\fR. +.LP +\fCisFunction(\fIsymbol\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIsymbol\fR is a user defined function, +otherwise \fCFALSE\fR. +.LP +\fCisImmediateMode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if the address mode of \fIoperand\fR is +\fIimmediate\fR, otherwise \fCFALSE\fR. +.LP +\fCisIndexedMode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if the address mode of \fIoperand\fR is an +indexed mode, otherwise \fCFALSE\fR. +.LP +\fCisIndirectMode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if the address mode of \fIoperand\fR is +\fIindirect\fR, otherwise \fCFALSE\fR. +.LP +\fCisPostIndexedMode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if the address mode of \fIoperand\fR is +\fIpost-indexed\fR, otherwise \fCFALSE\fR. +.LP +\fCisPreIndexedMode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if the address mode of \fIoperand\fR is +\fIpre-indexed\fR, otherwise \fCFALSE\fR. +.LP +\fCisRelocatableValue(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is a relocatable value, +otherwise \fCFALSE\fR. +.LP +\fCisString(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is a string, otherwise +\fCFALSE\fR. +.LP +\fCisStruct(\fIsymbol\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIsymbol\fR is the name of a struct, +otherwise \fCFALSE\fR. +.LP +\fCisSymbol(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is a symbol (as opposed to an +expression or a number, for example), otherwise \fCFALSE\fR. +.LP +\fCisXIndexedMode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if the address mode of \fIoperand\fR is +\fIx-indexed\fR, otherwise \fCFALSE\fR. +.LP +\fCisXRegister(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is \fCx\fR, otherwise +\fCFALSE\fR. +.LP +\fCisYIndexedMode(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if the address mode of \fIoperand\fR is +\fIy-indexed\fR, otherwise \fCFALSE\fR. +.LP +\fCisYRegister(\fIoperand\fC)\fR +.IP +Returns \fCTRUE\fR if and only if \fIoperand\fR is \fCy\fR, otherwise +\fCFALSE\fR. +.LP +\fClistingOff()\fR +.IP +If assembly listing has been enabled using the \fC-l\fR command line flag, +turn listing off temporarily. Otherwise, no effect. +.LP +\fClistingOn()\fR +.IP +If assembly listing was turned off using the \fClistingOff()\fR function, turn +it back on again. If listings have been globally disabled by not specifying +the \fC-l\fR command line flag, this function has no effect. The +\fClistingOff()\fR and \fClistingOn()\fR functions are intended to be used to +together to control assembly listings of large programs. They can be used to +suppress listing of large and uninteresting sections such as header files full +of definitions of global values. These functions may nest: in effect +\fClistingOff()\fR increments a counter and \fClistingOn()\fR decrements it. +Only when the counter is zero (i.e., the number of \fClistingOn()\fRs matches +the number of \fClistingOff()\fRs) does listing actually occur. +.LP +\fCmakeArray(\fIlength\fR \*[ \fC, \fIelement\fR \*Z \fC)\fR +.IP +Creates an array of length \fIlength\fP and returns it. Optionally fills the +array with the values specified by the \fIelement\fP expressions. If the +number of \fIelement\fPs given is greater than \fIlength\fP, an error results. +.LP +\fCnthChar(\fIstring\fR \*[ \fC, \fIposition\fR \*] \fC)\fR +.IP +Returns the \fIposition\fPth character of the string \fIstring\fP (position +zero being the first character in the string). If \fIposition\fP is omitted +it defaults to zero. If \fIposition\fP is greater than the length of +\fIstring\fP, an error results. +.LP +\fCprintf(\fIformat\fR \*[ \fC, \fIarg\fR \*Z \fC)\fR +.IP +A formatted print routine just like the Unix system subroutine of the same +name. +.LP +\fCstrcat(\fIstring1\fC, \fIstring2\fC)\fR +.IP +Returns a string which is the concatenation of the two operands, which must +themselves be strings. +.LP +\fCstrcmp(\fIstring1\fC, \fIstring2\fC)\fR +.IP +Returns a number which is less than, equal to, or greater than 0 depending +upon whether \fIstring1\fR is lexically less than, equal to, or greater than +\fIstring2\fR. The ASCII character set is used. The two operands, of course, +must be strings. +.LP +\fCstrcmplc(\fIstring1\fC, \fIstring2\fC)\fR +.IP +Essentially the same as \fCstrcmp()\fR except that alphabetic characters are +converted to lower case before being compared. The result is a +case-independent string comparison. This is useful for comparing two +identifier name strings to see if they represent the same symbols. +.LP +\fCstrlen(\fIstring\fC)\fR +.IP +Returns a number which is the length, in characters, of \fIstring\fR. +.LP +\fCsubstr(\fIstring\fC, \fIstartPos\fR \*[\fC , \fIlength\fR \*] \fC)\fR +.IP +Returns a substring of the string \fIstring\fR starting from the character at +start position \fIstartPos\fR (counting the first character from 0) and +continuing for \fIlength\fR characters. If \fIstartPos\fR is negative, the +start position is counted from right to left (with the rightmost character +position being indicated by -1) instead of the more usual left to right. If +\fIlength\fR is negative, \fIstartPos\fR in essence denotes the end of the +desired substring and \fIlength\fR characters up to that position are +returned. If \fIlength\fR is omitted, the substring from \fIstartPos\fR to +the end of the string is returned, if \fIstartPos\fR is positive, or to the +beginning of the string, if \fIstartPos\fR is negative. If any of the indices +cause the substring bounds to go off the end of \fIstring\fR an error results. +For example, +.nf + \fCsubstr("hello there", 6, 3)\fR yields \fC"the"\fR + \fCsubstr("hello there", -8, 2)\fR yields \fC"lo"\fR + \fCsubstr("hello there", 6, -3)\fR yields \fC"o t"\fR + \fCsubstr("hello there", -8, -4)\fR yields \fC"hell"\fR + \fCsubstr("hello there", 6)\fR yields \fC"there"\fR + \fCsubstr("hello there", -7)\fR yields \fC"hello"\fR +.fi +.LP +\fCsymbolDefine(\fIstring\fR \*[ \fC, \fIvalue\fR \*] \fC)\fR +.IP +Defines the symbol named by \fIstring\fP (with optional value \fIvalue\fP) as +if it had been defined with a \fCdefine\fR statement. For example: +.nf + \fCsymbolDefine(strcat("foon", "farm"), 47)\fR +.fi +is equivalent to +.nf + \fCdefine foonfarm = 47\fR +.fi +.LP +\fCsymbolLookup(\fIstring\fC)\fR +.IP +A call to this function with a string operand is equivalent to a reference to +the symbol that the string represents. For example, +.nf + \fCand symbolLookup("foo")\fR +.fi +is equivalent to +.nf + \fCand foo\fR +.fi +.LP +\fCsymbolName(\fIsymbol\fC)\fR +.IP +Returns a string which is the name of the symbol \fIsymbol\fR. For example, +\fCsymbolName(foo)\fR would return \fC"foo"\fR. This can be used in +conjunction with the \fCsymbolLookup\fR function so that the following: +.nf + \fCand symbolLookup(strcat(symbolName(foo), "bar"))\fR +.fi +is equivalent to +.nf + \fCand foobar\fR +.fi +.LP +\fCsymbolUsage(\fIsymbol\fC)\fR +.IP +Returns a number whose value indicates what sort of symbol \fIsymbol\fR is +(i.e., label, function, struct field, etc.). \fI((define these values))\fR +.LP +\fCvalueType(\fIthing\fC)\fR +.IP +Returns a number whose value indicates the type of \fIthing\fR (i.e., symbol, +condition code, number, block, etc.). \fI((define these values))\fR +.bp +.CD +\s+5\fBAppendix D \(em Operator Set\fR\s-5 +\"\s+4\fBAppendix D \(em Operator Set\fR\s-4 +.fi +.PP +This appendix describes the (\fBC\fR derived) operators supported by +\fIMacross\fR. +.nf + + \fC-\fR \fIexpression\fR integer negation + \fC!\fR \fIexpression\fR logical negation (0 goes to 1, all other values go to 0) + \fC~\fR \fIexpression\fR bitwise negation (ones complement) + \fC?\fR \fIexpression\fR high byte + \fC/\fR \fIexpression\fR low byte + \fIexpression\fR \fC*\fR \fIexpression\fR integer multiplication + \fIexpression\fR \fC/\fR \fIexpression\fR integer division + \fIexpression\fR \fC%\fR \fIexpression\fR integer modulus (remainder) + \fIexpression\fR \fC-\fR \fIexpression\fR integer subtraction + \fIexpression\fR \fC+\fR \fIexpression\fR integer addition + \fIexpression\fR \fC<<\fR \fIexpression\fR left shift + \fIexpression\fR \fC>>\fR \fIexpression\fR right shift + \fIexpression\fR \fC<\fR \fIexpression\fR less than + \fIexpression\fR \fC>\fR \fIexpression\fR greater than + \fIexpression\fR \fC<=\fR \fIexpression\fR less than or equal to + \fIexpression\fR \fC>=\fR \fIexpression\fR greater than or equal to + \fIexpression\fR \fC==\fR \fIexpression\fR equal to + \fIexpression\fR \fC!=\fR \fIexpression\fR not equal to + \fIexpression\fR \fC&\fR \fIexpression\fR bitwise AND + \fIexpression\fR \fC|\fR \fIexpression\fR bitwise OR + \fIexpression\fR \fC^\fR \fIexpression\fR bitwise XOR + \fIexpression\fR \fC&&\fR \fIexpression\fR logical AND + \fIexpression\fR \fC||\fR \fIexpression\fR logical OR + \fIexpression\fR \fC^^\fR \fIexpression\fR logical XOR + \fIexpression\fR \fC.\fR \fIidentifier\fR struct field selection + \fIidentifier\fR \fC=\fR \fIexpression\fR assignment + \fIidentifier\fR \fC+=\fR \fIexpression\fR assignment with addition + \fIidentifier\fR \fC-=\fR \fIexpression\fR assignment with subtraction + \fIidentifier\fR \fC*=\fR \fIexpression\fR assignment with multiplication + \fIidentifier\fR \fC/=\fR \fIexpression\fR assignment with division + \fIidentifier\fR \fC%=\fR \fIexpression\fR assignment with modulus + \fIidentifier\fR \fC&=\fR \fIexpression\fR assignment with AND + \fIidentifier\fR \fC|=\fR \fIexpression\fR assignment with OR + \fIidentifier\fR \fC^=\fR \fIexpression\fR assignment with XOR + \fIidentifier\fR \fC<<=\fR \fIexpression\fR assignment with left shift + \fIidentifier\fR \fC>>=\fR \fIexpression\fR assignment with right shift + \fIidentifier\fR \fC++\fR post-increment + \fIidentifier\fR \fC--\fR post-decrement + \fC++\fR \fIidentifier\fR pre-increment + \fC--\fR \fIidentifier\fR pre-decrement + +.fi +.bp +.CD +\s+5\fB Appendix E \(em Character Escape Codes\fR\s-5 +\"\s+4\fB Appendix E \(em Character Escape Codes\fR\s-4 +.fi +.PP +Like \fBC\fR, \fIMacross\fR enables you to use the ``\fC\\\fR'' character as +an escape to embed quotation marks, formatting characters (such as newline) +and other non-printing characters in character strings and character +constants. The recognized codes are: +.nf + + \fC\\n\fR newline + \fC\\t\fR horizontal tab + \fC\\b\fR backspace + \fC\\r\fR carriage return + \fC\\f\fR form feed + \fC\\e\fR escape + \fC\\\\\fR backslash + \fC\\'\fR apostrophe + \fC\\"\fR quote + \fC\\^\fIc\fR CONTROL-\fIc\fR (where \fIc\fR is any character). + \fC\\\fIddd\fR arbitrary byte (where \fIddd\fR is one, two or three octal digits). +.fi +.bp +.CD +\s+5\fBAppendix F \(em Recognized Opcode Mnemonics\fR\s-5 +\"\s+4\fBAppendix F \(em Recognized Opcode Mnemonics\fR\s-4 +.sp 1 +\s+3\fB(6502 version)\fR\s-3 +.fi +.PP +These are the 6502 opcode mnemonics recognized by \fIMacross\fR: +.2C +.nf +\fCadc +and +asl +bcc +bcs +beq +bit +bmi +bne +bpl +brk +bvc +bvs +clc +cld +cli +clv +cmp +cpx +cpy +dec +dex +dey +eor +inc +inx +iny +jmp +jsr +lda +ldx +ldy +lsr +nop +ora +pha +php +pla +plp +rol +ror +rti +rts +sbc +sec +sei +sta +stx +sty +tax +tay +tsx +txa +txs +tya +.fi +.1C diff --git a/doc/writeup_68000.itr b/doc/writeup_68000.itr new file mode 100644 index 0000000..0736e97 --- /dev/null +++ b/doc/writeup_68000.itr @@ -0,0 +1,2262 @@ +.ds [ \s+1\z[\h'1p'\z[\h'-1p'\s-1\0 +.ds ] \s+1\z]\h'-1p'\z]\s-1\0 +.ds Z \s+1\z]\h'-1p'\z]\h'3p'\z*\s-1\0 +.TL +\s+6Macross 68000\s-6 +\"Macross +.AU +an assembler for people who hate assembly language +by +Chip Morningstar +.AI +Lucasfilm Ltd. Games Division +\\*(DY +.ds LH Macross +.ds CH \\*(DY +.ds RH 68000 Version +.ds LF Lucasfilm Ltd. Proprietary Information +.ds CF - % - +.ds RF CONFIDENTIAL +.AB +This document describes the 68000 version of \fIMacross\fR, a super-duper +cross-assembler that has but to be used! +.AE +.SH +\s+3Introduction\s-3 +\"Introduction +.PP +\fIMacross\fR is a generic cross assembler for a variety of different +microprocessors. This document describes the 68000 version of \fIMacross\fR. +\fIMacross\fR differs from many macro assemblers in that it provides a number +of ``higher level'' constructs not traditionally found in assembly language. +These include block-structured flow-of-control statements (\fBif\fR, +\fBwhile\fR, etc.) and the ability to define record-oriented data structures +(\fBstruct\fR). In addition, it contains a powerful macro capability that is +based on syntactic structural manipulations rather than simple text +substitution. \fIMacross\fR is, in fact, a complete block-structured +programming language in its own right which is interpreted at assembly time. +.SH +\s+3General Form of \fIMacross\fP Statements\s-3 +\"General Form of \fIMacross\fP Statements +.PP +Stylistically, much of \fIMacross\fR is patterned after \fBC\fR. In +particular, the form of many keywords and of block structured entities is +derived from \fBC\fR. Unlike \fBC\fR however, \fIMacross\fR follows the +convention of more traditional assemblers that statements are delimited by +line boundaries (i.e., one statement per line, with the end of a line ending a +statement). +.PP +In general, spaces and tabs are treated as whitespace characters and are +ignored. Therefore, such characters may be used as the assembly language +programmer desires to format his or her program according to personal taste. +For the convenience of the programmer, \fIMacross\fR relaxes the syntax rule +that newlines always end a statement: newlines may also be treated as +whitespace characters (again, for purposes of formatting) in places where it +would be syntactically unambiguous to do so (i.e., where a statement obviously +cannot terminate, such as after a comma). For example: +.nf + + \fBbyte 1, 2, 3, 4, + 5, 6, 7, 8\fR + +.fi +is allowed and is equivalent to +.nf + + \fBbyte 1, 2, 3, 4, 5, 6, 7, 8 + +.fi +.PP +Comments begin with a semicolon (``\fB;\fR'') and continue to the end of the +line, as is common in many assemblers. In addition, \fIMacross\fR supports +\fBC\fR style comments bracketed by ``\fB/*\fR'' and ``\fB*/\fR''. +.PP +As with most assemblers, \fIMacross\fR statements are allowed to begin with a +label (or several labels, if you like). A label is denoted by an identifier +followed by a colon (``\fB:\fR''). There is no requirement that the label +start in column 1, or anything like that. Labels, if present, merely must +precede anything else in a statement. +.PP +An identifier is just what you'd expect from all your years of programming +experience: a string of letters and digits that must begin with a letter. As +is traditional in Unix* +.FS * +Unix is a footnote of Bell Laboratories. +.FE +land, the underscore character (``\fB_\fR'') is considered to be a letter +(smacks of hubris that, but tradition is tradition). Departing from Unix +tradition, upper- and lower-case characters are not distinct from each other +for purposes of distinguishing identifiers. If you use mixed case for +stylistic reasons, \fIMacross\fR will remember the case of the letters in an +identifier when it was first defined, so that symbol table dumps and +cross-reference listings will retain whatever case usage style you've adopted. +There is, in principle, no restriction imposed upon the length of identifiers. +.SH +\s+3The Language\s-3 +.PP +In what follows, things in \fBboldface\fR are keywords and characters that are +used literally. Things in \fIitalics\fR are other kinds of syntactic +entities. Double brackets (``\*['' and ``\*]'') enclose things that are +optional, while brackets followed by an asterisk (``*'') enclose things that +may be optionally repeated zero or more times. +.NH 1 +The Instruction Statement +.PP +The most elementary \fIMacross\fR statement is the instruction statement, +wherein the programmer specifies a machine instruction to be assembled. The +instruction statement is +.nf + +\*[ \fIlabel\fR \*Z \fIopcode\fR \*[ \fIoperand\fR \*[ \fB,\fR \fIoperand\fR \*Z \*] + +.fi +just like every assembler ever made (except \fBa65\fR, of course). +\fIOpcode\fR is an identifier which is either a machine instruction mnemonic +(a list of which mnemonics are accepted by \fIMacross\fR is given in +\fBAppendix B\fR at the end of this document) or a macro name. For example: +.nf + + \fBandb foobar, d3\fR + \fBsomeMacro foo, bar, baz, bletch\fR + +.fi +.PP +The operands of an instruction may be any of the various types of operands +allowed by the various address modes of the target processor. In the case +of the 68000, these are: +.NH 2 +\fRRegister mode +.PP +Register operands take one of the forms +.nf + + \fBd\fIn\fR + \fBa\fIn\fR + \fBsp\fR + +.fi +where \fIn\fR is a digit from \fB0\fR to \fB7\fR. \fBd\fIn\fR of course +represents a data register and \fBa\fIn\fR represents an address register. +\fBsp\fR is equivalent to \fBa7\fR. +.NH 2 +\fRRegister indirect mode +.PP +Register indirect mode operands take the form +.nf + + \fB\s-1[\s+1\fBa\fIn\fB\s-1]\s+1\fR + +.fi +where \fBa\fIn\fR is some address register. +.NH 2 +\fRPostincrement mode +.PP +Postincrement mode operands take the form +.nf + + \fB\s-1[\s+1\fBa\fIn\fB\s-1]\s+1+\fR + +.fi +where \fBa\fIn\fR is some address register. +.NH 2 +\fRPredecrement mode +.PP +Predecrement mode operands take the form +.nf + + \fB-\s-1[\s+1\fBa\fIn\fB\s-1]\s+1\fR + +.fi +where \fBa\fIn\fR is some address register. +.NH 2 +\fRNormal mode +.PP +Normal mode addresses take the form +.nf + + \fIexpression\fR + +.fi +and are used in a couple of different ways. First, normal mode addresses are +used by instructions that require relative addresses (such as branch +instructions; the offset is computed automatically by \fIMacross\fR). Second, +the normal mode form of addresses is a shorthand way of refering to locations +for which \fIMacross\fR selects an appropriate address mode to use (PC +relative if it can, otherwise absolute). +.NH 2 +\fRAbsolute mode +.PP +Absolute addresses take one of these two forms +.nf + + \fIexpression\fB . w\fR + \fIexpression\fB . l\fR + +.fi +with the \fBw\fR or \fBl\fR indicating whether to generate a short (16 bit) or +a long (32 bit) address. +.NH 2 +\fRImmediate mode +.PP +Immediate mode operands take the form +.nf + + \fB#\fR \fIexpression\fR + +.fi +Generally speaking, in the 68000 immediate mode operands are restricted to +sixteen bit quantities. Depending upon the particular instruction involved, +the size may be even more restricted. \fIMacross\fR will give an error +message if the operand value is larger than allowed. +.NH 2 +\fRDisplacement mode +.PP +Displacement mode operands take the form +.nf + + \fIexpression\fR \fB\s-1[\s+1\fR \fBa\fIn\fR \fB\s-1]\s+1\fR + +.fi +where \fIexpression\fR is an offset off of the address register \fBa\fIn\fR. +These displacement values are limited to 16 bit quantities in the 68000. +.PP +An alternate form of displacment mode addressing which is supported by +\fIMacross\fR allows the symbolic selection of a field of a \fBstruct\fR +pointed to by an address register +.nf + + \fBa\fIn\fR \fB.\fR \fIidentifier\fR \*[ \fB.\fR \fIidentifier\fR \*Z + +.fi +This is explained in greater detail in the sections on \fBstruct\fRs and +expressions below. +.NH 2 +\fRIndexed mode +.PP +Indexed mode addressing is specified by operands of the form +.nf + + \fIexpression\fR \fB\s-1[\s+1\fR \fBa\fIn\fR \fB,\fR \fIrn\fR \fB. w \s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBa\fIn\fR \fB,\fR \fIrn\fR \fB. l \s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBa\fIn\fR \fB,\fR \fIrn\fR \fB\s-1]\s+1\fR + +.fi +where \fIexpression\fR is an offset off of address register \fBa\fIn\fR and +another register \fIrn\fR which may be any data or address register. The +Offset is restricted to an 8-bit quantity. The \fBw\fR or \fBl\fR indicates +whether the offset value in \fIrn\fR is to be taken as a word (16 bit) value +or as a long (32 bit) value (if omitted it defaults to long). +.PP +As with ordinary displacment addressing, there is a form of indexed addressing +which uses \fBstruct\fR fields +.nf + + \fBa\fIn\fR \fB\s-1[\s+1\fR \fIrn\fR \fB. w \fB\s-1]\s+1\fR \fB.\fR \fIidentifier\fR \*[ \fB.\fR \fIidentifier\fR \*Z + \fBa\fIn\fR \fB\s-1[\s+1\fR \fIrn\fR \fB. l \fB\s-1]\s+1\fR \fB.\fR \fIidentifier\fR \*[ \fB.\fR \fIidentifier\fR \*Z + \fBa\fIn\fR \fB\s-1[\s+1\fR \fIrn\fR \fB\s-1]\s+1\fR \fB.\fR \fIidentifier\fR \*[ \fB.\fR \fIidentifier\fR \*Z + +.fi +.NH 2 +\fRProgram counter displacement mode +.PP +Program counter displacement mode operands take the form +.nf + + \fIexpression\fR \fB\s-1[\s+1\fR \fBpc\fR \fB\s-1]\s+1\fR + +.fi +where \fIexpression\fR is an offset off of the program counter. These +displacement values are limited to 16 bit quantities in the 68000. +.NH 2 +\fRProgram counter indexed mode +.PP +Program counter indexed mode addressing is specified by operands of the form +.nf + + \fIexpression\fR \fB\s-1[\s+1\fR \fBpc\fR \fB,\fR \fIrn\fR \fB. w \s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBpc\fR \fB,\fR \fIrn\fR \fB. l \s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBpc\fR \fB,\fR \fIrn\fR \fB\s-1]\s+1\fR + +.fi +where \fIexpression\fR is an offset off of the program counter and another +register \fIrn\fR which may be any data or address register. The Offset is +restricted to an 8-bit quantity. The \fBw\fR or \fBl\fR indicates whether the +offset value in \fIrn\fR is to be taken as a word (16 bit) value or as a long +(32 bit) value (if omitted it defaults to long). +.NH 2 +\fRControl register mode +.PP +The various control register of the 68000 are sometimes used as operands +.nf + + \fBccr\fR + \fBsr\fR + \fBusp\fR + \fBsfc\fR + \fBdfc\fR + \fBvbr\fR + +.fi +where \fBccr\fR represents the condition code register, \fBsr\fR represents +the status register, \fBusp\fR represents the user stack pointer, \fBsfc\fR +represents the source function code register, \fBdfc\fR represents the +destination function code register, and \fBvbr\fR represents the vector base +register. +.NH 2 +\fRText operands +.PP +For the sake of macros, text strings may also be used as operands +.nf + + \fB"\fIany string you like\fB"\fR + +.fi +The same conventions regarding escaped characters (using ``\fB\\\fR'') that +are followed by \fBC\fR are followed by \fIMacross\fR. These are documented +in \fBAppendix F\fR. Note that on many target machines the codes that these +escape sequences stand for are meaningless. They are provided primarily as a +convenience for writing calls to \fBprintf()\fR. +.NH 1 +The Flow of Control Statements +.PP +\fIMacross\fR provides a number of statements which allow program flow of +control to be specified in a \fBC\fR-like block structured fashion. This +include a conditional execution statement (\fBif\fR) and three conditional +loop statements (\fBwhile\fR, \fBdo-while\fR and \fBdo-until\fR). These +statements assemble into the appropriate conditional branches and jumps to +realize the desired construct. +.NH 2 +If\fR statement +.PP +The \fBif\fR statement has the following form +.nf + +\*[ \fIlabel\fR \*Z \fBif\fR \fB(\fR \fIcondition\fR \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \*[ \fBelseif\fR \fB(\fR \fIcondition\fR \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \*Z \*[ \fBelse\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \*] + +.fi +\fIcondition\fR is either the name of one of the target processor's hardware +condition codes such as can be tested for in a conditional branch instruction +(e.g., \fBcarry\fR, \fBoverflow\fR, etc.\*- the complete list is in +\fBAppendix C\fR) or one either of these negated using the ``logical not'' +operator (``\fB!\fR''). The condition is used to determine the appropriate +type of branch instruction to use. For example, +.nf + + \fBif (overflow) {\fR + \fIstatements-1\fR + \fB} elseif (carry) {\fR + \fIstatements-2\fR + \fB} else {\fR + \fIstatements-3\fR + \fB}\fR + +.fi +expands into this (the labels are made up for illustrative purposes only): +.nf + + \fBbvc temp1 + \fIstatements-1 + \fBjmp temp3 +temp1: bcc temp2 + \fIstatements-3 + \fBjmp temp3 +temp2: \fIstatements-3 +\fBtemp3: \fIwhatever follows\fR + +.fi +The keyword \fBelseif\fR may be used as shown, or specified as two separate +keywords, \fBelse if\fR, depending on the programmer's whim. +.NH 2 +While\fR statement +.PP +The \fBwhile\fR statement has the following form +.nf + +\*[ \fIlabel\fR \*Z \fBwhile\fR \fB(\fR \fIcondition\fR \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR + +.fi +\fIcondition\fR is as described above for the \fBif\fR statement. An example +of the \fBwhile\fR statement would be +.nf + + \fBwhile (!carry) {\fR + \fIstatements\fR + \fB}\fR + +.fi +which would turn into +.nf + +\fBtemp2: bcs temp1 + \fIstatements + \fBjmp temp2 +temp1: \fIwhatever follows\fR + +.fi +.NH 2 +Do-while\fR statement +.PP +The \fBdo-while\fR statement is similar to the \fBwhile\fR statement except +that the condition is tested at the bottom of the loop. It has the form +.nf + +\*[ \fIlabel\fR \*Z \fBdo\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \fBwhile\fR \fB(\fR \fIcondition\fR \fB)\fR + +.fi +For example +.nf + + \fBdo {\fR + \fIstatements\fR + \fB} while (equal)\fR + +.fi +which is equivalent to +.nf + +\fBtemp: \fIstatements + \fBbeq temp\fR + +.fi +.NH 2 +Do-until\fR statement +.PP +The \fBdo-until\fR statement is the same as the \fBdo-while\fR statement +except that the sense of the condition is negated. It has the form +.nf + +\*[ \fIlabel\fR \*Z \fBdo\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \fBuntil\fR \fB(\fR \fIcondition\fR \fB)\fR + +.fi +For example +.nf + + \fBdo {\fR + \fIstatements\fR + \fB} until (equal)\fR + +.fi +which is equivalent to +.nf + +\fBtemp: \fIstatements + \fBbne temp\fR + +.fi +.NH 1 +The Data Statements +.PP +The data statements allow the allocation of memory space and the storage of +constant data. These statements are like the ones found in most assemblers. +There are several different forms, each for a different type of data. +.NH 2 +Block\fR statement +.PP +The \fBblock\fR statement allocates blocks of memory without initializing the +bytes to any particular value (actually, the loader will in all likelihood +initialize these to 0, but it is probably not really wise to rely on this). +It has the form +.nf + +\*[ \fIlabel\fR \*Z \fBblock\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z + +.fi +The \fIexpression\fRs are the sizes of the blocks to reserve, expressed in +bytes. +.NH 2 +Align\fR statement +.PP +The \fBalign\fR statement aligns the current location counter to an integer +multiple of some value (e.g., to align with a word boundary). It has the form +.nf + +\*[ \fIlabel\fR \*Z \fBalign\fR \fIexpression\fR + +.fi +The \fIexpression\fR is the multiple to which the current location counter is +to be aligned. For example, +.nf + + \fBalign 2\fR + +.fi +would align the current location to a word boundary, while +.nf + + \fBalign 0x100\fR + +.fi +would align to a page boundary. +.NH 2 +Constrain\fR statement +.PP +The \fBconstrain\fR statement provides a means of constraining a portion of +code or data to be located within a region of memory bounded by addresses of +integer multiples of some value (e.g., within a page). Its form is +.nf + + \fBconstrain\fR \fB(\fR \fIboundary\fR \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR + +.fi +\fIBoundary\fR may be any expression which evaluates to a number. The +\fIstatement\fRs are assembled normally. If assembling in absolute mode, an +error message is issued if the current location counter crosses an integer +multiple of \fIboundary\fR. If assembling in relocatable mode, information +about the constraint will be output in the object file and the contents of the +constrained block will be relocated as needed to satisfy the constraint (note +that this means that it is unsafe to assume that the things in the assembly +source immediately before the \fBconstrain\fR statement, the contents of the +constrain block itself, and the things in the assembly source immediately +after the \fBconstrain\fR statement will be located in contiguous locations in +the eventual target machine address space). For example, +.nf + + \fBconstrain (0x100) {\fR + \fIstatements\fR + \fB}\fR + +.fi +constrains the given statements to all fit within a page. +.NH 2 +Word\fR statement +.PP +The \fBword\fR statement allocates words, i.e., two byte chunks, of memory. +It takes the form +.nf + +\*[ \fIlabel\fR \*Z \fBword\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z + +.fi +The \fIexpression\fRs must evaluate to quantities that can be contained in 16 +bits, of course. For example, +.nf + + \fBword 0x1234, foobar\fR + +.fi +would allocate two words, the first of which would be initialized to the +hexadecimal value 0x1234 and the second to whatever the value of \fBfoobar\fR +is. +.NH 2 +Dbyte\fR statement +.PP +The \fBdbyte\fR statement is just like the \fBword\fR statement, except that +the word is byte-swapped in memory. Its form is +.nf + +\*[ \fIlabel\fR \*Z \fBdbyte\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z +.fi +.NH 2 +Long\fR statement +.PP +The \fBlong\fR statement allocates longwords, i.e., four byte chunks, of +memory. It takes the form +.nf + +\*[ \fIlabel\fR \*Z \fBlong\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z + +.fi +The \fIexpression\fRs must evaluate to quantities that can be contained in 32 +bits, of course. For example, +.nf + + \fBword 0x12345678, foobar\fR + +.fi +would allocate two longwords, the first of which would be initialized to the +hexadecimal value 0x12345678 and the second to whatever the value of +\fBfoobar\fR is. +.NH 2 +Byte\fR statement +.PP +The \fBbyte\fR statement is similar to the \fBword\fR and \fBdbyte\fR +statements, except that it allocates single byte chunks. Its form is +.nf + +\*[ \fIlabel\fR \*Z \fBbyte\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z + +.fi +An \fIexpression\fR, in this case, is either an ordinary expression (see +\fBExpressions\fR, below) which must evaluate to an 8-bit quantity, indicating +the value for a single byte to be reserved, or a string (see above, under the +discussion of text operands), indicating that the characters in the string +should be placed in memory at the current location. +.NH 2 +String\fR statement +.PP +The \fBstring\fR statement is much like the \fBbyte\fR statement, except that +the values indicated are followed in memory by a zero byte. This enables the +convenient declaration and allocation of NULL terminated character strings. +This feature is of little use in the 68000 version of \fIMacross\fR but is +provided for compatability with future versions targeted at more sophisticated +processors. The form of the \fBstring\fR statement is +.nf + +\*[ \fIlabel\fR \*Z \fBstring\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z +.fi +.NH 2 +Struct\fR statement +.PP +The \fBstruct\fR statement enables the declaration and allocation of +record-oriented data structures. There are two forms of the \fBstruct\fR +statement, the first of which declares a \fBstruct\fR record type, and the +second of which causes space to be set aside in memory for a \fBstruct\fR that +has already been declared. The form of the first type of \fBstruct\fR +statement is +.nf + +\*[ \fIlabel\fR \*Z \fBstruct\fR \fB{\fR + \*[ \fIdataStatement\fR \*Z + \fB}\fR \fIname\fR + +.fi +\fIdataStatement\fRs are any of the data statements described in this section +(section 3). \fIName\fR becomes the name of the \fBstruct\fR. Any labels +inside the \fBstruct\fR become \fIfields\fR of the data structure which may be +referred to later in expressions using the ``\fB.\fR'' operator, as in +\fBC\fR. A more complete description of the semantics of \fBstruct\fRs is +given in the section below on expressions. +.PP +The first form of the \fBstruct\fR statement, called a ``\fBstruct\fR +definition'', lays out the constituent parts of a data structure and gives +those names to those parts. The second form of the \fBstruct\fR statement, +called a ``\fBstruct\fR instantiation'', +.nf + +\*[ \fIlabel\fR \*Z \fBstruct\fR \fIname\fR + +.fi +causes storage for the \fBstruct\fR named by \fIname\fR to be allocated. A +\fBstruct\fR definition \fImay not\fR contain another \fBstruct\fR definition, +but it \fImay\fR contain a \fBstruct\fR instantiation. For example, +.nf + + \fBstruct { + pointer: block 2 + class: block 1 + } fooThing\fR + +.fi +would create a \fBstruct\fR called \fBfooThing\fR. Then, +.nf + +\fBfooLabel: struct fooThing\fR + +.fi +would allocate one at the current location at the address labeled +\fBfooLabel\fR. This could then be used as follows: +.nf + + \fBandb fooLabel.class, d0 + jmp fooLabel.pointer\fR + +.fi +which would AND \fBd0\fR with the \fBclass\fR field of the \fBstruct\fR and +then jump to wherever the \fBpointer\fR field pointed to. If the \fBx\fR +address register \fBa4\fR already contained the address of this \fBstruct\fR, +then one could say +.nf + + \fBandb a4.class, d0\fR + +.fi +.NH 1 +The Symbol Definition Statements +.PP +The various symbol definition statements allow the declaration of symbolic +variables and values and the definition of macros and functions. +.NH 2 +Define\fR statement +.PP +The \fBdefine\fR statement enables the programmer to create symbolic names for +values. It has two forms. The first +.nf + + \fBdefine\fR \fIsymbolname\fR + +.fi +creates a new symbol, \fIsymbolname\fR (an identifier), and gives it the +special value \fBunassigned\fR. Any attempt to take the value of an +unassigned symbol will cause an error message from the assembler. The symbol +will, however, cause the \fBisDefined()\fR built-in function (see +\fBExpressions\fR, below) to return \fBTRUE\fR if passed as an argument. It +is also an error to \fBdefine\fR a symbol that has already been \fBdefine\fRd. +.PP +The second form of the \fBdefine\fR statement +.nf + + \fBdefine\fR \fIsymbolname\fR \fB=\fR \fIexpression\fR + +.fi +creates the symbol and gives it the value obtained by evaluating +\fIexpression\fR (see \fBExpressions\fR, below). Actually, what \fBdefine\fR +does is create a symbolic name for \fIexpression\fR and the save this +expression away in a secret place. This means that symbols in +\fIexpression\fR may be forward references, e.g., labels that haven't been +encountered yet. It is also possible to forward reference to symbols that are +defined by future \fBdefine\fR statements, for example: +.nf + + \fBdefine foo = bar + 2 + define bar = 47\fR + +.fi +effectively defines \fBfoo\fR to be \fB49\fR. Beware, however, as there is no +way for the assembler to detect mutually recursive references of this sort, so +that +.nf + + \fBdefine foo = bar + 2 + define bar = foo + 2\fR + +.fi +will be happily swallowed without complaint, until you actually try to use +\fBfoo\fR or \fBbar\fR in an instruction, whereupon \fIMacross\fR's expression +evaluator will go into infinite recursion until it runs out of stack space and +crashes the assembler (it looks to see what \fBfoo\fR is and sees that it's +\fBbar + 2\fR, so it looks to see what \fBbar\fR and see that it's \fBfoo + +2\fR, so it looks to see what \fBfoo\fR is... To have the assembler detect +and signal this error would, in the general case, add much complication and +inefficiency (read: make your programs assemble a lot more slowly) for little +return). +.PP +The scope of symbols defined in either of these two ways extends in time from +the definition itself to the end of the assembly. +.NH 2 +Variable\fR statement +.PP +The \fBvariable\fR statement enables the programmer to declare symbolic +variables for future use. Similar to the \fBdefine\fR statement, it has two +forms. The first +.nf + + \fBvariable\fR \fIsymbolname\fR + +.fi +creates a variable named \fIsymbolname\fR and gives it the special value +\fBunassigned\fR, just like the analogous \fBdefine\fR statement. +.PP +The second form of the \fBvariable\fR statement +.nf + + \fBvariable\fR \fIsymbolname\fR \fB=\fR \fIexpression\fR + +.fi +creates the variable and gives it the value obtained by evaluating +\fIexpression\fR. The scope of variables defined in either of these two ways +extends from the \fBvariable\fR statement itself to the end of the assembly +(i.e., the variable is global). +.PP +The difference between the \fBdefine\fR statement and the \fBvariable\fR +statement is that the \fBdefine\fR statement creates what is in essence a +constant whereas the \fBvariable\fR statement creates a true variable. The +value of a variable may change (e.g., it may be assigned to) during the course +of assembly. In addition, the expression which establishes a symbol's value +in a \fBdefine\fR statement may contain forward references (i.e., labels whose +values are unknown because they haven't been encountered yet) whereas the +expression assigning an initial value to a variable must be made up of terms +all of whose values are known at the time the \fBvariable\fR statement is +encountered in the assembly. +.NH 2 +Macro\fR statement +.PP +The \fBmacro\fR statement is used to define macros (surprise!). Its syntax is +.nf + + \fBmacro\fR \fImacroname\fR \*[ \fIargumentname\fR \*[ \fB,\fR \fIargumentname\fR \*Z \*] \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR + +.fi +where \fImacroname\fR is just that and the \fIargumentname\fRs are identifiers +corresponding to the formal parameters of the macro (in the classical +fashion). When the macro is called, the call arguments are bound to these +symbols and then \fIMacross\fR assembles the \fIstatement\fRs which form the +macro body. The scope of these symbols is limited to the inside of the macro +body and their values go away when the macro expansion is completed. The +\fIstatement\fRs may be any valid \fIMacross\fR statements except for +\fBmacro\fR statements and \fBfunction\fR statements (i.e., macro and function +definitions may not be nested). +.PP +Statement labels used inside macros can be made local to the macro by +preceding the label identifier with a dollar sign (``\fB$\fR''). For +example, +.nf + + \fBmacro fooMac arg { + jmp $foo + word arg + $foo: nop + }\fR + +.fi +defines a macro named \fBfooMac\fR that emits a word of data that gets jumped +over. The label \fB$foo\fR is local to the macro: both the reference to it +in the first line of the macro and its definition on the third will only be +seen inside the macro. Each time the macro is called, the \fBjmp\fR will +refer to the location two instructions ahead, and any other macros that might +contain \fB$foo\fR will not affect this nor will they be affected by this. +.NH 2 +Function\fR statement +.PP +The \fBfunction\fR statement is used to define functions. Its syntax is +.nf + + \fBfunction\fR \fIfuncname\fR \fB(\fR \*[ \fIargumentname\fR \*[ \fB,\fR \fIargumentname\fR \*Z \*] \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR + +.fi +where \fIfuncname\fR is the name of the function and the \fIargumentname\fRs +are identifiers corresponding to the formal parameters of the function. When +the function is called, the call arguments are evaluated and then bound to +these symbols and then \fIMacross\fR assembles the \fIstatement\fRs which form +the function body. The scope of these symbols is limited to the inside of the +function body and their values go away when the function evaluation is +completed. As with macro definitions, the \fIstatement\fRs may be any valid +\fIMacross\fR statements except for the \fBmacro\fR and \fBfunction\fR +statements. A function may return a value using the \fBfreturn\fR statement, +which is described below. +.NH 2 +Undefine\fR statement +.PP +The \fBundefine\fR statement allows symbol and macro definitions to be removed +from \fIMacross\fR' symbol table. It takes the form +.nf + + \fBundefine\fR \fIsymbolname\fR \*[ \fB,\fR \fIsymbolname\fR \*Z + +.fi +The named symbols go away as if they never were \*- they are free to be +defined again and the \fBisDefined()\fR built-in function will return +\fBFALSE\fR if passed one of them as an argument. +.NH 1 +Macro Body Statements +.PP +\fIMacross\fR provides several statements which are primarily intended to +manage the flow of control (or, rather, the ``flow of assembly'') within a +macro or function definition. Some of these statements are analogs to the +flow of control statements described above in section 2. However, one should +keep in mind that these statements are executed interpretively at assembly +time, whereas the previously described statements result in machine code in +the target-processor-executable output of the assembly process. +.PP +Although these statements are intended primarily for use within macros and +functions, their use is not restricted and they may be used at any point in a +program. In particular, the \fBmif\fR statement (to be described shortly) is +the means by which conditional assembly may be realized. +.NH 2 +\fRBlocks +.PP +The construct +.nf + + \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR + +.fi +is called a \fIblock\fR and is in fact a valid \fIMacross\fR statement type in +its own right. Blocks are used extensively in \fIMacross\fR to form the +bodies of flow-of-control statements, flow-of-assembly statements and macros. +.NH 2 +Mdefine\fR statement +.PP +The \fBmdefine\fR statement +.nf + + \fBmdefine\fR \fIsymbolname\fR +or + \fBmdefine\fR \fIsymbolname\fR \fB=\fR \fIexpression\fR + +.fi +operates like (and is syntactically congruent with) the \fBdefine\fR +statement, except that the scope of the symbol definition is restricted to the +body block of the macro or function in which the \fBmdefine\fR appears. The +symbol definition is invisible outside that block, though it \fIis\fR visible +inside any blocks that may themselves be contained within the macro or +function. +.NH 2 +Mvariable\fR statement +.PP +The \fBmvariable\fR statement +.nf + + \fBmvariable\fR \fIsymbolname\fR +or + \fBmvariable\fR \fIsymbolname\fR \fB=\fR \fIexpression\fR + +.fi +bears exactly the same relationship to the \fBvariable\fR statement that the +\fBmdefine\fR statement does to the \fBdefine\fR statement. It declares a +variable whose scope is limited to the function or macro in whose definition +it appears. +.NH 2 +Mif\fR statement +.PP +The \fBmif\fR statement conditionally assembles the statements contained in +the block following it: +.nf + + \fBmif\fR \fB(\fR \fIcondition\fR \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \*[ \fBmelseif\fR \fB(\fR \fIcondition\fR \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \*Z \*[ \fBmelse\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \*] + +.fi +unlike the \fBif\fR statement, the \fIcondition\fR may be any expression +whatsoever. \fIMacross\fR follows the \fBC\fR convention that the value 0 +represents \fBFALSE\fR and any other value represents \fBTRUE\fR (in fact, the +symbols \fBTRUE\fR and \fBFALSE\fR are ``predefined'' by the assembler to +have the values 1 and 0 respectively). The meaning of the \fBmif\fR construct +is the obvious one, but keep in mind that it is interpreted at assembly time +and has no direct bearing on the execution of the resulting assembled program. +.NH 2 +Mwhile\fR statement +.PP +The \fBmwhile\fR statement repetitively assembles a block of statements so +long as a given condition remains true. Its form is +.nf + + \fBmwhile\fR \fB(\fR \fIcondition\fR \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR + +.fi +As with \fBmif\fR, the \fIcondition\fR may be any valid \fIMacross\fR +expression and the interpretation is what it seems. +.NH 2 +Mdo-while\fR statement +.PP +The \fBmdo-while\fR statement provides an alternative to the \fBmwhile\fR +statement by testing at the bottom of the loop instead of at the top. Its +form is +.nf + + \fBmdo\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \fBwhile\fR \fB(\fR \fIcondition\fR \fB)\fR +.fi +.NH 2 +Mdo-until\fR statement +.PP +The \fBmdo-until\fR statement is the same as the \fBmdo-while\fR statement +except that the sense of the condition is negated. It has the form +.nf + + \fBmdo\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \fBuntil\fR \fB(\fR \fIcondition\fR \fB)\fR +.fi +.NH 2 +Mfor\fR statement +.PP +The \fBmfor\fR statement provides a more general looping construct analogous +to the \fBC\fR \fBfor\fR loop. Its form is +.nf + + \fBmfor\fR \fB(\fR \fIexpression-1\fR \fB,\fR \fIexpression-2\fR \fB,\fR \fIexpression-3\fR \fB)\fR \fB{\fR + \*[ \fIstatement\fR \*Z + \fB}\fR + +.fi +where \fIexpression-1\fR is an initialization expression, \fIexpression-2\fR +is a test to see if looping should continue, and \fIexpression-3\fR is +executed at the bottom of the loop to set up for the next time around, just as +in \fBC\fR. Note that, unlike \fBC\fR, the \fIexpression\fRs are separated by +commas, not semicolons. This is because semicolons are used to delimit line +comments. +.PP +The \fBmfor\fR statement is equivalent to +.nf + + \fIexpression-1\fR + \fBmwhile (\fIexpression-2\fB ) {\fR + \fIstatements\fR + \fIexpression-3\fR + \fB}\fR +.fi +.NH 2 +Mswitch\fR statement +.PP +The \fBmswitch\fR statement provides a means of selecting one of a number of +blocks of code for assembly depending upon the value of some expression. Its +form is: +.nf + + \fBmswitch ( \fIselectionExpression \fB) {\fR + \*[ \fBmcase ( \fIexpression\fR \*[ \fB,\fI expression\fR \*Z \fB) {\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \*Z + \*[ \fBmdefault {\fR + \*[ \fIstatement\fR \*Z + \fB}\fR \*] + \fB}\fR + +.fi +The way this works is as follows (it's actually easier to use than to +explain): \fIselectionExpression\fR is evaluated. Each of the +\fIexpression\fRs associated with the various \fBmcase\fR clauses (if any) is +then evaluated in turn and the resulting value compared to that of +\fIselectionExpression\fR. When and if one of these values ``matches'' the +value of \fIselectionExpression\fR the block of \fIstatement\fRs associated +with the corresponding \fBmcase\fR clause is immediately assembled and +execution of the \fBmswitch\fR statement is complete. If no such value +matches and there is an \fBmdefault\fR clause, the block of \fIstatement\fRs +associated with the \fBmdefault\fR clause is assembled. If no value matches +and there is no \fBmdefault\fR clause then nothing is assembled as a result of +the \fBmswitch\fR. When we say the values ``match'', we mean that either +the expressions evaluate to the same number or to strings which are identical +except for the case of alphabetic characters. For example: +.nf + + \fBmswitch (foo) { + mcase ("hello", "fnord") { + \fIstatements-1\fB + } + mcase ("ZAP!") { + \fIstatements-2\fB + } + mdefault { + \fIstatements-3\fR + } + }\fR + +.fi +would switch on the value of the symbol \fBfoo\fR. If the value of \fBfoo\fR +was \fB"hello"\fR, \fIstatements-1\fR would be assembled. If the value of +\fBfoo\fR was \fB"zap!"\fR, \fIstatements-2\fR would be assembled (since the +string comparison is done independent of case). If the value of \fBfoo\fR was +\fB"cromfelter"\fR or \fB47\fR, then \fIstatements-3\fR would be assembled by +default. +.NH 2 +Freturn\fR statement +.PP +A \fIMacross\fR function may (and probably will) be called from an expression +in the traditional manner of functions throughout the annals of computer +science. In such a situation, the programmer may wish to have a function +return a value. The \fBfreturn\fR statement enables this. Its form is +.nf + + \fBfreturn\fR \*[ \fIexpression\fR \*] + +.fi +where \fIexpression\fR is any permissible \fIMacross\fR expression as +described below under \fBExpressions\fR. If no \fIexpression\fR is given, the +macro simply returns without having a value as its result. Any attempt to use +the (non-existent) value returned by a call to function which doesn't return a +value will result in an error message from the assembler. Function calls will +automatically return without a value upon reaching the end of the block that +forms the body of the function. +.NH 1 +Miscellaneous Statements +.PP +Various useful statements don't fall into any of the above categories. +.NH 2 +Include\fR statement +.PP +The \fBinclude\fR statement allows the text in other files to be included in +the source program being assembled, in the time-honored fashion. Its form is +.nf + + \fBinclude\fR \fIfilename\fR + +.fi +where \fIfilename\fR is a string value giving the name of the file to be +included. \fBInclude\fRd files may themselves contain \fBinclude\fR +statements to any number of levels of recursion (within reason). +.NH 2 +Extern\fR statement +.PP +The \fBextern\fR statement allows you to declare symbols to be visible to the +linker outside of the file in which they are found. Its use: +.nf + + \fBextern\fR \fIsymbol\fR \*[ \fB,\fR \fIsymbol\fR \*Z +.fi +.NH 2 +Start\fR statement +.PP +The \fBstart\fR statement declares the starting address of a program. +.nf + + \fBstart\fR \fIexpression\fR + +.fi +where the \fIexpression\fR indicates the start address. There should be no +more than one \fBstart\fR statement in a program. If no start address is +specified, the object file will be produced without a start address entry. +.NH 2 +Assert\fR statement +.PP +The \fBassert\fR statement provides a means of testing assembly time +conditions and generating programmer specified error messages if those +conditions are not satisfied. Its syntax is: +.nf + + \fBassert (\fIcondition\fB)\fR \*[ \fItextString\fR \*] + +.fi +where \fIcondition\fR is an expression such as those used in the \fBmif\fR +statement. This condition is evaluated and if \fBFALSE\fR then the message +\fItextString\fR, if given, is written to the standard output. The message is +written in the form of a conventional \fIMacross\fR error message, giving the +file and line number on which the failed assertion occured. If +\fItextString\fR is omitted then a simple error message to the effect that the +assert failed will be output. For example, +.nf + + \fBassert (foo == 1) "Hey! You blew it."\fR + +.fi +would check to see that the value of the symbol \fBfoo\fR is \fB1\fR, and if +it isn't would issue an error message containing the string \fB"Hey! You blew +it."\fR. +.NH 2 +Org\fR statement +.PP +The \fBorg\fR statement adjusts the current location counter and tells the +assembler to start locating instructions and data in absolute memory +locations. +.nf + + \fBorg\fR \fIexpression\fR + +.fi +The \fIexpression\fR indicates the new current location. If this is an +absolute address, \fIMacross\fR starts assembling at the specified +absolute memory location. If, on the other hand, it is relative to a +relocatable address or to the current location counter, the current location +counter is simply adjusting accordingly. +.NH 2 +Rel\fR statement +.PP +The \fBrel\fR statement restores \fIMacross\fR to assembling code in a +relocatable fashion, if it was not already doing so. The relocatable location +resumes from wherever it was left the last time an absolute \fBorg\fR stopped +relocatable code assembly. \fI((explain this better))\fR +.NH 2 +Target\fR statement +.PP +The \fBtarget\fR statement +.nf + + \fBtarget\fR \fIexpression\fR + +.fi +tells the assembler to assemble as if it had been \fBorg\fRed to a particular +address without actually performing the \fBorg\fR. The \fIexpression\fR +indicates the location to start assembling from. This must be an absolute +address (and the \fBtarget\fR statement may only be used when assembling in +absolute mode). +.PP +The result of the \fBtarget\fR statement is that assembly proceeds from the +current location but labels will be defined as if it was proceeding from the +location specified by \fIexpression\fR and references to the current location +counter will be offset by the difference between the actual current location +counter value and the value of \fIexpression\fR. This effect will persist until the next \fBorg\fR or \fBtarget\fR statement. For example +.nf + + \fBorg 0x1000 + target 0x0800 +foo: rts +bar: word 0x1234 + word here + org someplaceElse\fR + +.fi +would first set the current location counter to \fB0x1000\fR. At location +\fB0x1000\fR it would assemble an \fBrts\fR instruction while giving the label +\fBfoo\fR the value \fB0x800\fR. Then, at location \fB0x1002\fR it would +deposit the word value \fB0x1234\fR while giving the label \fBbar\fR the +value \fB0x802\fR. At location \fB0x1004\fR it would deposit the word value +\fB0x804\fR. Finally, the second \fBorg\fR would set the current location +counter to \fBsomeplaceElse\fR and the effects of the \fBtarget\fR statement +would cease. +.SH +\s+3Expressions\s-3 +.PP +The expression syntax of \fIMacross\fR was chosen to be as close to that of +\fBC\fR as possible. \fIMacross\fR recognizes the same set of operators as +\fBC\fR with few exceptions, and the operators have the same precedence with +respect to each other that everyone is used to. +.PP +Another important feature of expressions in \fIMacross\fR is that expressions +by themselves on a line are valid statements. Assignment expressions, uses of +the post- and pre-increment and decrement operators (``\fB++\fR'' and +``\fB--\fR''), and calls to functions used like procedures are the most +useful applications of this. For example +.nf + + \fBfoo = 5\fR + \fBbar++\fR + \fBprintf("Hello world\\n")\fR + +.fi +are all valid statements. +.NH 0 +\fRPrimitive expressions +.PP +The most primitive expressions are identifiers, numbers, characters, character +strings, and function calls. +.PP +Identifiers have already been described, in the section \fBGeneral Form of +\fIMacross\fB Statements\fR above. The only thing to add here is that the +special identifier \fBhere\fR denotes the value of the current location +counter. +.PP +Numbers may be decimal, octal, hexadecimal, binary or quarters. The form of +the first three of these is as in \fBC\fR: decimal numbers are denoted by a +sequence of decimal digits that does not begin with a ``\fB0\fR''; octal +numbers by a sequence of octal digits that \fIdoes\fR begin with a +``\fB0\fR''; and hexadecimal numbers by a sequence of hexadecimal digits +(the decimal digits plus the letters ``\fBa\fR'' through ``\fBf\fR'', in +either upper or lower case), preceded by ``\fB0x\fR'' or ``\fB0X\fR''. +Binary numbers and quarters are represented analogously. Binary numbers are +represented by a sequence of ``\fB0\fR''s and ``\fB1\fR''s preceded by +``\fB0b\fR'' or ``\fB0B\fR''. Quarters are base-four numbers (for two-bit +entities like Atari pixels) and are represented by the sequences of the digits +\fB0\fR through \fB3\fR preceded by ``\fB0q\fR'' or ``\fB0Q\fR'' (the +credit for this idea goes to Charlie Kellner). +.PP +Character constants are denoted the same as in \fBC\fR: by a single character +enclosed in apostrophes (``\fB'\fR''). The same conventions about +characters escaped with a backslash (``\fB\\\fR'') also apply. Strings may +be of varying lengths and are enclosed in quotation marks (``\fB"\fR''), +as discussed above in the explanation of instruction operands. +.PP +A function call, in \fIMacross\fR, is syntactically the same as in \fBC\fR: +the name of the function being called followed by a comma-separated argument +list in parenthesis. The argument list, as in \fBC\fR, may be empty. The +arguments themselves may be arbitrary instruction operands (described above in +section 1). A number of built-in functions are provided by \fIMacross\fR to +perform a variety of useful operations. These are discussed in \fBAppendix +D\fR. +.NH 1 +\fROperators +.PP +Expressions may be constructed from the primitive elements described above and +from other expressions using a variety of unary and binary operators. The +operator set is patterned after \fBC\fR's. The only \fBC\fR operators not +supported are: +.IP +[1] ``\fB?:\fR'' (arithmetic if) \*- not supported for reasons of syntactic +confusion on both the part of the parser attempting to parse it and the +programmer attempting to use it. +.IP +[2] ``\fB,\fR'' (comma) \*- used in \fIMacross\fR as an important separator +and thus not available. +.IP +[3] unary ``\fB*\fR'' and ``\fB&\fR'', \fBsizeof\fR, casts and +``\fB->\fR'' \*- not relevant here. +.LP +All of the assignment operators (``\fB+=\fR'', ``\fB-=\fR'', etc.) +\fIare\fR supported by \fIMacross\fR. +.LP +\fIMacross\fR reinterprets the \fB.\fR operator in that ``\fIexpression\fB . +\fIstructfieldname\fR'' is interpreted as adding the offset value implied by +\fIstructfieldname\fR (i.e., the distance in bytes into a \fBstruct\fR to +reach the named field) to the address that is the value of \fIexpression\fR. +.LP +\fIMacross\fR adds to the operator set the following: +.IP +[1] ``\fB?\fR'' \*- as a unary operator, takes the high order byte of the +word value that is its argument. +.IP +[2] ``\fB/\fR'' \*- as a unary operator, takes the low order byte of the +word value that is its argument. +.IP +[3] ``\fB^^\fR'' \*- a binary operator, denotes logical exclusive-OR. This +is simply an orthogonal extension for the sake of completeness. +.LP +Of course, parenthesis can be used at any point to override the normal +precedence of the various operators. A full list of all the operators that +\fIMacross\fR understands is given in \fBAppendix E\fR. +.NH 1 +\fRExpression evaluation +.PP +In order to make the most effective use of expressions in the \fIMacross\fR +environment, it is helpful (and at times necessary) to understand how and when +\fIMacross\fR evaluates them. +.PP +When \fIMacross\fR evaluates an expression, it may have one of three sorts of +results. These are \fIsuccess\fR, \fIundefined\fR, and \fIfailure\fR. A +\fIsuccess\fR result means that \fIMacross\fR encountered no problems +evaluating the expression, and whatever value it evaluated to is just used as +needed. A \fIfailure\fR result indicates that there was a problem of some +sort. Usually this is a result of some user error. In any case, an +appropriate diagnostic message will be issued by the assembler and the +statement in which the expression was found will not be assembled. +.PP +An \fIundefined\fR result is where the complications, if any, arise. An +expression will evaluate to an \fIundefined\fR result if one or more of the +terms of the expression are undefined symbols. Usually these are labels which +simply haven't been encountered yet (i.e., they are forward references). In +certain contexts, such as the operand of a machine instruction, this is a +legitimate thing to do, and in certain others, such as the condition of a +\fBmif\fR statement, this is not allowed at all. In the latter case, an +\fIundefined\fR result is just like a \fIfailure\fR result. In the former +case, the assembler is forced to get fancy in order to make it all work right. +.PP +What \fIMacross\fR does is squirrel away a copy of the expression along with a +pointer as to where in the object code the value of the expression is supposed +to go. At the end of assembly, the undefined label will presumably now be +defined, and \fIMacross\fR evaluates the saved expression and pokes the result +into the appropriate location. (If, at this point, the undefined label is +still undefined, an error message to that effect is issued). Clearly, if an +expression has side effects (such as changing the value of some global +variable), this can result in some confusing behavior. The \fIMacross\fR +assembler is smart enough to not let you do anything that has overt side +effects in an expression that is being saved away for future evaluation. The +things which are disallowed in such a case are assignments and uses of the +post- and pre-increment and decrement operators (``\fB++\fR'' and +``\fB--\fR''). Functions, however, may have side effects and \fIMacross\fR +does not try to prevent you from using function calls in expressions that get +saved for later evaluation. It can, and will, detect some, but not all, side +effects during the later evaluation and give a suitable error message. This +is because it is perfectly legitimate to use a function call to a function +that doesn't have side effects in an expression containing forward references. +.PP +If you are now totally confused, the only thing you need remember is: \fBDon't +ever use a call to a function that has side effects in an expression +containing a forward reference.\fR +.bp +.CD + \s+5\fBAppendix A \*- Macross 68000 Grammar\fR\s-5 +\"\s+4\fBAppendix A \*- Macross 68000 Grammar\fR\s-4 +.DE +.LP +.nf +\fR\fIprogram\fR: + \*[ \fIstatement\fR Newline \*Z Endfile + +\fIstatement\fR: +\*[ \fIlabel\fR \*Z \fIopcode\fR \*[ \fIoperand\fR \*[ \fB,\fR \fIoperand\fR \*Z \*] +\*[ \fIlabel\fR \*Z \fBif\fR \fB(\fR \fIcondition\fR \fB)\fR \fIblock\fR + \*[ \fBelseif\fR \fB(\fR \fIcondition\fR \fB)\fR \fIblock\fR \*Z + \*[ \fBelse\fR \fIblock\fR \*] +\*[ \fIlabel\fR \*Z \fBwhile\fR \fB(\fR \fIcondition\fR \fB)\fR \fIblock\fR +\*[ \fIlabel\fR \*Z \fBdo\fR \fIblock\fR \fBwhile\fR \fB(\fR \fIcondition\fR \fB)\fR +\*[ \fIlabel\fR \*Z \fBdo\fR \fIblock\fR \fBuntil\fR \fB(\fR \fIcondition\fR \fB)\fR + \fIdataStatement\fR + \fBdefine\fR \fIidentifier\fR \*[ \fB=\fR \fIexpression\fR \*] + \fBvariable\fR \fIidentifier\fR \*[ \fB=\fR \fIexpression\fR \*] + \fBmacro\fR \fIidentifier\fR \*[ \fIidentifier\fR \*[ \fB,\fR \fIidentifier\fR \*Z \*] \fIblock\fR + \fBfunction\fR \fIidentifier\fR \fB(\fR \*[ \fIidentifier\fR \*[ \fB,\fR \fIidentifier\fR \*Z \*] \fB)\fR \fIblock\fR + \fBundefine\fR \fIidentifier\fR \*[ \fB,\fR \fIidentifier\fR \*Z +\*[ \fIlabel\fR \*Z \fIblock\fR + \fBmdefine\fR \fIidentifier\fR \*[ \fB=\fR \fIexpression\fR \*] + \fBmif\fR \fB(\fR \fIexpression\fR \fB)\fR \fIblock\fR + \*[ \fBmelseif\fR \fB(\fR \fIexpression\fR \fB)\fR \fIblock\fR \*Z + \*[ \fBmelse\fR \fIblock\fR \*] + \fBmwhile\fR \fB(\fR \fIexpression\fR \fB)\fR \fIblock\fR + \fBmdo\fR \fIblock\fR \fBwhile\fR \fB(\fR \fIexpression\fR \fB)\fR + \fBmdo\fR \fIblock\fR \fBuntil\fR \fB(\fR \fIexpression\fR \fB)\fR + \fBfreturn\fR \*[ \fIexpression\fR \*] + \fBmfor\fR \fB(\fR \fIexpression\fR \fB,\fR \fIexpression\fR \fB,\fR \fIexpression\fR \fB)\fR \fIblock\fR + \fBmswitch ( \fIselectionExpression \fB) {\fR + \*[ \fBmcase ( \fIexpression\fR \*[ \fB,\fI expression\fR \*Z \fB)\fI block\fR \*Z + \*[ \fBmdefault\fI block\fR \*] + \fB}\fR + \fBconstrain\fR \fB(\fR \fIexpression\fR \fB)\fR \fIblock\fR + \fBassert\fR \fB(\fR \fIexpression\fR \fB)\fR \*[ \fIexpression\fR \*] + \fBinclude\fR \fItextString\fR + \fBextern\fR \fIidentifier\fR \*[ \fB,\fR \fIidentifier\fR \*Z + \fBstart\fR \fIexpression\fR + \fBorg\fR \fIexpression\fR + \fBtarget\fR \fIexpression\fR + \fIexpression\fR + +\fIdataStatement\fR: +\*[ \fIlabel\fR \*Z \fBblock\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fBalign\fR \fIexpression\fR +\*[ \fIlabel\fR \*Z \fBword\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fBlong\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fBdbyte\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fBbyte\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fBstring\fR \fIexpression\fR \*[ \fB,\fR \fIexpression\fR \*Z +\*[ \fIlabel\fR \*Z \fBstruct\fR \fB{\fR \*[ \fIdataStatement\fR \*Z \fB}\fR \fIidentifier\fR +\*[ \fIlabel\fR \*Z \fBstruct\fR \fIidentifier\fR + +\fIlabel\fR: \fIidentifier\fR \fB:\fR + +\fIoperand\fR: + \fBd\fIn\fR + \fBa\fIn\fR + \fBsp\fR + \fB\s-1[\s+1\fR \fBa\fIn\fR \fB\s-1]\s+1\fR + \fB\s-1[\s+1\fR \fBa\fIn\fR \fB\s-1]\s+1+\fR + \fB-\s-1[\s+1\fR \fBa\fIn\fR \fB\s-1]\s+1\fR + \fIexpression\fR + \fIexpression\fB . w\fR + \fIexpression\fB . l\fR + \fB#\fR \fIexpression\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBa\fIn\fR \fB\s-1]\s+1\fR + \fBa\fIn\fR \fB.\fR \fIidentifier\fR \*[ \fB.\fR \fIidentifier\fR \*Z + \fIexpression\fR \fB\s-1[\s+1\fR \fBa\fIn\fR \fB,\fR \fIrn\fR \fB. w \s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBa\fIn\fR \fB,\fR \fIrn\fR \fB. l \s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBa\fIn\fR \fB,\fR \fIrn\fR \fB\s-1]\s+1\fR + \fBa\fIn\fR \fB\s-1[\s+1\fR \fIrn\fR \fB. w \fB\s-1]\s+1\fR \fB.\fR \fIidentifier\fR \*[ \fB.\fR \fIidentifier\fR \*Z + \fBa\fIn\fR \fB\s-1[\s+1\fR \fIrn\fR \fB. l \fB\s-1]\s+1\fR \fB.\fR \fIidentifier\fR \*[ \fB.\fR \fIidentifier\fR \*Z + \fBa\fIn\fR \fB\s-1[\s+1\fR \fIrn\fR \fB\s-1]\s+1\fR \fB.\fR \fIidentifier\fR \*[ \fB.\fR \fIidentifier\fR \*Z + \fIexpression\fR \fB\s-1[\s+1\fR \fBpc\fR \fB\s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBpc\fR \fB,\fR \fIrn\fR \fB. w \s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBpc\fR \fB,\fR \fIrn\fR \fB. l \s-1]\s+1\fR + \fIexpression\fR \fB\s-1[\s+1\fR \fBpc\fR \fB,\fR \fIrn\fR \fB\s-1]\s+1\fR + \fBccr\fR + \fBsr\fR + \fBusp\fR + \fBsfc\fR + \fBdfc\fR + \fBvbr\fR + \fItextString\fR + +\fIblock\fR: \fB{\fR \*[ \fIstatement\fR Newline \*Z \fB}\fR + +\fItextString\fR: + \fB" \fIany string you like \fB"\fR + +\fIcondition\fR: + \fIconditionCode\fR + \fB!\fR \fIconditionCode\fR + +\fIexpression\fR: + \fIidentifier\fR + \fIidentifier\fR \fB(\fR \*[ \fIoperand\fR \*[ \fB,\fR \fIoperand\fR \*Z \*] \fB)\fR + \fInumber\fR + \fBhere\fR + \fItextString\fR + \fB(\fR \fIexpression\fR \fB)\fR + \fB-\fR \fIexpression\fR + \fB!\fR \fIexpression\fR + \fB~\fR \fIexpression\fR + \fB?\fR \fIexpression\fR + \fB/\fR \fIexpression\fR + \fIexpression\fR \fB*\fR \fIexpression\fR + \fIexpression\fR \fB/\fR \fIexpression\fR + \fIexpression\fR \fB%\fR \fIexpression\fR + \fIexpression\fR \fB-\fR \fIexpression\fR + \fIexpression\fR \fB+\fR \fIexpression\fR + \fIexpression\fR \fB<<\fR \fIexpression\fR + \fIexpression\fR \fB>>\fR \fIexpression\fR + \fIexpression\fR \fB<\fR \fIexpression\fR + \fIexpression\fR \fB>\fR \fIexpression\fR + \fIexpression\fR \fB<=\fR \fIexpression\fR + \fIexpression\fR \fB>=\fR \fIexpression\fR + \fIexpression\fR \fB==\fR \fIexpression\fR + \fIexpression\fR \fB!=\fR \fIexpression\fR + \fIexpression\fR \fB&\fR \fIexpression\fR + \fIexpression\fR \fB|\fR \fIexpression\fR + \fIexpression\fR \fB^\fR \fIexpression\fR + \fIexpression\fR \fB&&\fR \fIexpression\fR + \fIexpression\fR \fB||\fR \fIexpression\fR + \fIexpression\fR \fB^^\fR \fIexpression\fR + \fIexpression\fR \fB.\fR \fIidentifier\fR + \fIidentifier\fR \fB=\fR \fIexpression\fR + \fIidentifier\fR \fB+=\fR \fIexpression\fR + \fIidentifier\fR \fB-=\fR \fIexpression\fR + \fIidentifier\fR \fB*=\fR \fIexpression\fR + \fIidentifier\fR \fB/=\fR \fIexpression\fR + \fIidentifier\fR \fB%=\fR \fIexpression\fR + \fIidentifier\fR \fB&=\fR \fIexpression\fR + \fIidentifier\fR \fB|=\fR \fIexpression\fR + \fIidentifier\fR \fB^=\fR \fIexpression\fR + \fIidentifier\fR \fB<<=\fR \fIexpression\fR + \fIidentifier\fR \fB>>=\fR \fIexpression\fR + \fIidentifier\fR \fB++\fR + \fIidentifier\fR \fB--\fR + \fB++\fR \fIidentifier\fR + \fB--\fR \fIidentifier\fR + +\fIidentifier\fR: + \*[\fBa\fR-\fBzA\fR-\fBZ_\fR\*]\*[\fBa\fR-\fBzA\fR-\fBZ_0\fR-\fB9\fR\*Z + +\fInumber\fR: + \fIdecimalNumber\fR + \fIoctalNumber\fR + \fIbinaryNumber\fR + \fIhexadecimalNumber\fR + \fIquarter\fR + +\fIdecimalNumber\fR: + \*[\fB1\fR-\fB9\fR\*]\*[\fB0\fR-\fB9\fR\*Z + +\fIoctalNumber\fR: + \fB0\fR\*[\fB0\fR-\fB7\fR\*Z + +\fIbinaryNumber\fR: + \fB0b\fR\*[\fB01\fR\*]\*[\fB01\fR\*Z + +\fIhexadecimalNumber\fR: + \fB0x\fR\*[\fB0\fR-\fB9a\fR-\fBf\fR\*]\*[\fB0\fR-\fB9a\fR-\fBf\fR\*Z + +\fIquarter\fR: + \fB0q\fR\*[\fB0\fR-\fB3\fR\*]\*[\fB0\fR-\fB3\fR\*Z + +.fi +.bp +.CD +\s+5\fBAppendix B \*- Recognized Opcode Mnemonics\fR\s-5 +\"\s+4\fBAppendix B \*- Recognized Opcode Mnemonics\fR\s-4 +.sp 1 +\s+3\fB(68000 version)\fR\s-3 +.DE +.PP +These are the 68000 opcode mnemonics recognized by \fIMacross\fR: +.2C +.nf +\fBabcd +addb +addl +addqb +addql +addqw +addw +addxb +addxl +addxw +andb +andl +andw +aslb +asll +aslw +asrb +asrl +asrw +bcc +bchg +bclr +bcs +beq +bge +bgt +bhi +ble +bls +blt +bmi +bne +bpl +bra +bset +bsr +btst +bvc +bvs +chk +clrb +clrl +clrw +cmpb +cmpl +cmpmb +cmpml +cmpmw +cmpw +dbcc +dbcs +dbeq +dbf +dbge +dbgt +dbhi +dble +dbls +dblt +dbmi +dbne +dbpl +dbra +dbt +dbvc +dbvs +divs +divu +eorb +eorl +eorw +exg +extl +extw +illegal +jmp +jsr +lea +link +lslb +lsll +lslw +lsrb +lsrl +lsrw +movb +moveb +movel +moveml +movemw +movepl +movepw +moveq +movesb +movesl +movesw +movew +movl +movml +movmw +movpl +movpw +movq +movsb +movsl +movsw +movw +muls +mulu +nbcd +negb +negl +negw +negxb +negxl +negxw +nop +notb +notl +notw +orb +orl +orw +pea +reset +rolb +roll +rolw +rorb +rorl +rorw +roxlb +roxll +roxlw +roxrb +roxrl +roxrw +rtd +rte +rtr +rts +sbcd +scc +scs +seq +sf +sge +sgt +shi +sle +sls +slt +smi +sne +spl +st +stop +subb +subl +subqb +subql +subqw +subw +subxb +subxl +subxw +svc +svs +swap +tas +trap +trapv +tstb +tstl +tstw +unlk +.fi +.1C +.CD +\s+5\fBAppendix C \*- Condition Codes\fR\s-5 +\"\s+4\fBAppendix C \*- Condition Codes\fR\s-4 +.sp 1 +\s+3\fB(68000 version)\fR\s-3 +.DE +.PP +The \fIMacross\fR \fBif\fR, \fBwhile\fR, \fBdo-while\fR and \fBdo-until\fR +statements make use of symbols denoting the hardware condition codes of the +target processor which may be used as the conditions upon which conditional +branches are base. In the 68000 version of \fIMacross\fR, these are the +recognized condition code symbols: +.LP +.nf + \fBcarry\fR + \fBequal\fR + \fBgeq\fR + \fBgreater\fR + \fBgt\fR + \fBhigh\fR + \fBhigh_same\fR + \fBhs\fR + \fBless\fR + \fBleq\fR + \fBlow\fR + \fBlow_same\fR + \fBls\fR + \fBlt\fR + \fBminus\fR + \fBnegative\fR + \fBneq\fR + \fBoverflow\fR + \fBplus\fR + \fBpositive\fR + \fBzero\fR + +.fi +.bp +.CD +\s+5\fBAppendix D \*- Built-In Functions\fR\s-5 +\"\s+4\fBAppendix D \*- Built-In Functions\fR\s-4 +.DE +.PP +Certain predefined built-in functions are supported by \fIMacross\fR for +reasons of convenience or syntactic or semantic irregularity. They are: +.nf + +\fBaddressMode(\fIoperand\fB)\fR +.fi +.RS +Returns a number whose value indicates which addressing mode \fIoperand\fR +represents \fI((define these values))\fR. +.RE +.nf + +\fBapply(\fImacname\fR \*[ \fB, \fIarg\fR \*Z \fB)\fR +.fi +.RS +Assembles the macro whose name is specified by the \fBstring\fR \fImacname\fR +with the macro arguments (if any) given by the \fIarg\fRs. +.RE +.nf + +\fBgetAddressRegister(\fIoperand\fB)\fR +.fi +.RS +Returns a number from 0 to 7 indicating which address register is used in +\fIoperand\fR (assuming that the address mode of \fIoperand\fR is address +register, register indirect, postincrement, predecrement, displacement or +indexed). +.RE +.nf + +\fBgetDataRegister(\fIoperand\fB)\fR +.fi +.RS +Returns a number from 0 to 7 indicating which data register is used in +\fIoperand\fR (assuming that the address mode of \fIoperand\fR is data +register). +.RE +.nf + +\fBgetIndexRegister(\fIoperand\fB)\fR +.fi +.RS +Returns a number from 0 to 15 indicating which register is used as the index +register in \fIoperand\fR (assuming that the address mode of operand is +indexed or program counter indexed). The values 0 through 7 indicate the +address registers \fBa0\fR through \fBa7\fR and the values 8 through 15 +indicate the data registers \fBd0\fR through \fBd7\fR. +.RE +.nf + +\fBgetRegister(\fIoperand\fB)\fR +.fi +.RS +Returns a number from 0 to 15 indicating which register is used in +\fIoperand\fR. The values 0 through 7 indicate the address registers \fBa0\fR +through \fBa7\fR and the values 8 through 15 indicate the data registers +\fBd0\fR through \fBd7\fR. +.RE +.nf + +\fBgetWL(\fIoperand\fB)\fR +.fi +.RS +Returns a number 0 or 1 indicatng whether \fIoperand\fR is a word operand or a +long operand (assuming that the address mode of \fIoperand\fR is absolute, +indexed or program counter indexed). +.RE +.nf + +\fBisAbsoluteLongMode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if the address mode of \fIoperand\fR is +absolute long, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisAbsoluteMode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if the address mode of \fIoperand\fR is +absolute (short or long), otherwise \fBFALSE\fR. +.RE +.nf + +\fBisAbsoluteShortMode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if the address mode of \fIoperand\fR is +absolute short, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisAbsoluteValue(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is an absolute (i.e., +non-relocatable) value, otherwise \fBFALSE\fR. +.RE +.bp +.nf +\fBisARegister(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is an address register, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisBlock(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is a block, otherwise +\fBFALSE\fR. +.RE +.nf + +\fBisBuiltInFunction(\fIsymbol\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIsymbol\fR is a built-in function, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisCCRegister(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is the condition code +register, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisConditionCode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is a condition code, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisControlRegister(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is a control register +(\fBusp\fR, \fBdfc\fR, \fBsfc\fR, or \fBvbr\fR), otherwise \fBFALSE\fR. +.RE +.nf + +\fBisDefined(\fIsymbol\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIsymbol\fR has been defined, otherwise +\fBFALSE\fR. +.RE +.nf + +\fBisDFCRegister(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is the destination function +code register, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisDRegister(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is a data register, otherwise +\fBFALSE\fR. +.RE +.nf + +\fBisDisplacementMode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if the address mode of \fIoperand\fR +displacment, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisExternal(\fIsymbol\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIsymbol\fR is external (i.e., visible +outside the file in which it is defined), otherwise \fBFALSE\fR. +.RE +.nf + +\fBisField(\fIsymbol\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIsymbol\fR is a field of a struct, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisFunction(\fIsymbol\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIsymbol\fR is a user defined function, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisImmediateMode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if the address mode of \fIoperand\fR is +\fIimmediate\fR, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisIndexedMode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if the address mode of \fIoperand\fR is an +indexed mode, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisPostincrementMode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if the address mode of \fIoperand\fR is +postincrement, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisPredecrementMode(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if the address mode of \fIoperand\fR is +predecrement, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisRelocatableValue(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is a relocatable value, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisSFCRegister(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is the source function code +register, otherwise \fBFALSE\fR. +.RE +.nf + +\fBisStatusRegister(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is the status register, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisString(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is a string, otherwise +\fBFALSE\fR. +.RE +.nf + +\fBisStruct(\fIsymbol\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIsymbol\fR is the name of a struct, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisSymbol(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is a symbol (as opposed to an +expression or a number, for example), otherwise \fBFALSE\fR. +.RE +.nf + +\fBisUSP(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is the user stack pointer, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBisVBRegister(\fIoperand\fB)\fR +.fi +.RS +Returns \fBTRUE\fR if and only if \fIoperand\fR is the vector base register, +otherwise \fBFALSE\fR. +.RE +.nf + +\fBlistingOff()\fR +.fi +.RS +If assembly listing has been enabled using the \fB-l\fR command line flag, +turn listing off temporarily. Otherwise, no effect. +.RE +.nf + +\fBlistingOn()\fR +.fi +.RS +If assembly listing was turned off using the \fBlistingOff()\fR function, turn +it back on again. If listings have been globally disabled by not specifying +the \fB-l\fR command line flag, this function has no effect. The +\fBlistingOff()\fR and \fBlistingOn()\fR functions are intended to be used to +together to control assembly listings of large programs. They can be used to +suppress listing of large and uninteresting sections such as header files full +of definitions of global values. These functions may nest: in effect +\fBlistingOff()\fR increments a counter and \fBlistingOn()\fR decrements it. +Only when the counter is zero (i.e., the number of \fBlistingOn()\fRs matches +the number of \fBlistingOff()\fRs) does listing actually occur. +.RE +.nf + +\fBprintf(\fIformat\fR \*[ \fB, \fIarg\fR \*Z \fB)\fR +.fi +.RS +A formatted print routine just like the Unix system subroutine of the same +name. +.RE +.nf + +\fBstrcat(\fIstring1\fB, \fIstring2\fB)\fR +.fi +.RS +Returns a string which is the concatenation of the two operands, which must +themselves be strings. +.RE +.nf + +\fBstrcmp(\fIstring1\fB, \fIstring2\fB)\fR +.fi +.RS +Returns a number which is less than, equal to, or greater than 0 depending +upon whether \fIstring1\fR is lexically less than, equal to, or greater than +\fIstring2\fR. The ASCII character set is used. The two operands, of course, +must be strings. +.RE +.nf + +\fBstrcmplc(\fIstring1\fB, \fIstring2\fB)\fR +.fi +.RS +Essentially the same as \fBstrcmp()\fR except that alphabetic characters are +converted to lower case before being compared. The result is a +case-independent string comparison. This is useful for comparing two +identifier name strings to see if they represent the same symbols. +.RE +.nf + +\fBstrlen(\fIstring\fB)\fR +.fi +.RS +Returns a number which is the length, in characters, of \fIstring\fR. +.RE +.nf + +\fBsubstr(\fIstring\fB, \fIstartPos\fR \*[\fB , \fIlength\fR \*] \fB)\fR +.fi +.RS +Returns a substring of the string \fIstring\fR starting from the character at +start position \fIstartPos\fR (counting the first character from 0) and +continuing for \fIlength\fR characters. If \fIstartPos\fR is negative, the +start position is counted from right to left (with the rightmost character +position being indicated by -1) instead of the more usual left to right. If +\fIlength\fR is negative, \fIstartPos\fR in essence denotes the end of the +desired substring and \fIlength\fR characters up to that position are +returned. If \fIlength\fR is omitted, the substring from \fIstartPos\fR to +the end of the string is returned, if \fIstartPos\fR is positive, or to the +beginning of the string, if \fIstartPos\fR is negative. If any of the indices +cause the substring bounds to go off the end of \fIstring\fR an error results. +For example, +.nf + \fBsubstr("hello there", 6, 3)\fR yields \fB"the"\fR + \fBsubstr("hello there", -8, 2)\fR yields \fB"lo"\fR + \fBsubstr("hello there", 6, -3)\fR yields \fB"o t"\fR + \fBsubstr("hello there", -8, -4)\fR yields \fB"hell"\fR + \fBsubstr("hello there", 6)\fR yields \fB"there"\fR + \fBsubstr("hello there", -7)\fR yields \fB"hello"\fR +.fi +.RE +.nf + +\fBsymbolLookup(\fIstring\fB)\fR +.fi +.RS +A call to this function with a string operand is equivalent to a reference to +the symbol that the string represents. For example, +.nf + \fBand symbolLookup("foo")\fR +.fi +is equivalent to +.nf + \fBand foo\fR +.fi +.RE +.nf + +\fBsymbolName(\fIsymbol\fB)\fR +.fi +.RS +Returns a string which is the name of the symbol \fIsymbol\fR. For example, +\fBsymbolName(foo)\fR would return \fB"foo"\fR. This can be used in +conjunction with the \fBsymbolLookup\fR function so that the following: +.nf + \fBand symbolLookup(strcat(symbolName(foo), "bar"))\fR +.fi +is equivalent to +.nf + \fBand foobar\fR +.fi +.RE +.nf + +\fBsymbolUsage(\fIsymbol\fB)\fR +.fi +.RS +Returns a number whose value indicates what sort of symbol \fIsymbol\fR is +(i.e., label, function, struct field, etc.). \fI((define these values))\fR +.RE +.nf + +\fBvalueType(\fIthing\fB)\fR +.fi +.RS +Returns a number whose value indicates the type of \fIthing\fR (i.e., symbol, +condition code, number, block, etc.). \fI((define these values))\fR +.RE + +.fi +.bp +.CD +\s+5\fBAppendix E \*- Operator Set\fR\s-5 +\"\s+4\fBAppendix E \*- Operator Set\fR\s-4 +.DE +.PP +This appendix describes the (\fBC\fR derived) operators supported by +\fIMacross\fR. +.nf + + \fB-\fR \fIexpression\fR integer negation + \fB!\fR \fIexpression\fR logical negation (0 goes to 1, all other values go to 0) + \fB~\fR \fIexpression\fR bitwise negation (ones complement) + \fB?\fR \fIexpression\fR high byte + \fB/\fR \fIexpression\fR low byte + \fIexpression\fR \fB*\fR \fIexpression\fR integer multiplication + \fIexpression\fR \fB/\fR \fIexpression\fR integer division + \fIexpression\fR \fB%\fR \fIexpression\fR integer modulus (remainder) + \fIexpression\fR \fB-\fR \fIexpression\fR integer subtraction + \fIexpression\fR \fB+\fR \fIexpression\fR integer addition + \fIexpression\fR \fB<<\fR \fIexpression\fR left shift + \fIexpression\fR \fB>>\fR \fIexpression\fR right shift + \fIexpression\fR \fB<\fR \fIexpression\fR less than + \fIexpression\fR \fB>\fR \fIexpression\fR greater than + \fIexpression\fR \fB<=\fR \fIexpression\fR less than or equal to + \fIexpression\fR \fB>=\fR \fIexpression\fR greater than or equal to + \fIexpression\fR \fB==\fR \fIexpression\fR equal to + \fIexpression\fR \fB!=\fR \fIexpression\fR not equal to + \fIexpression\fR \fB&\fR \fIexpression\fR bitwise AND + \fIexpression\fR \fB|\fR \fIexpression\fR bitwise OR + \fIexpression\fR \fB^\fR \fIexpression\fR bitwise XOR + \fIexpression\fR \fB&&\fR \fIexpression\fR logical AND + \fIexpression\fR \fB||\fR \fIexpression\fR logical OR + \fIexpression\fR \fB^^\fR \fIexpression\fR logical XOR + \fIexpression\fR \fB.\fR \fIidentifier\fR struct field selection + \fIidentifier\fR \fB=\fR \fIexpression\fR assignment + \fIidentifier\fR \fB+=\fR \fIexpression\fR assignment with addition + \fIidentifier\fR \fB-=\fR \fIexpression\fR assignment with subtraction + \fIidentifier\fR \fB*=\fR \fIexpression\fR assignment with multiplication + \fIidentifier\fR \fB/=\fR \fIexpression\fR assignment with division + \fIidentifier\fR \fB%=\fR \fIexpression\fR assignment with modulus + \fIidentifier\fR \fB&=\fR \fIexpression\fR assignment with AND + \fIidentifier\fR \fB|=\fR \fIexpression\fR assignment with OR + \fIidentifier\fR \fB^=\fR \fIexpression\fR assignment with XOR + \fIidentifier\fR \fB<<=\fR \fIexpression\fR assignment with left shift + \fIidentifier\fR \fB>>=\fR \fIexpression\fR assignment with right shift + \fIidentifier\fR \fB++\fR post-increment + \fIidentifier\fR \fB--\fR post-decrement + \fB++\fR \fIidentifier\fR pre-increment + \fB--\fR \fIidentifier\fR pre-decrement + +.fi +.bp +.CD +\s+5\fB Appendix F \*- Character Escape Codes\fR\s-5 +\"\s+4\fB Appendix F \*- Character Escape Codes\fR\s-4 +.DE +.PP +Like \fBC\fR, \fIMacross\fR enables you to use the ``\fB\\\fR'' character as +an escape to embed quotation marks, formatting characters (such as newline) +and other non-printing characters in character strings and character +constants. The recognized codes are: +.nf + + \fB\\n\fR newline + \fB\\t\fR horizontal tab + \fB\\b\fR backspace + \fB\\r\fR carriage return + \fB\\f\fR form feed + \fB\\e\fR escape + \fB\\\\\fR backslash + \fB\\'\fR apostrophe + \fB\\"\fR quote + \fB\\^\fIc\fR CONTROL-\fIc\fR (where \fIc\fR is any character). + \fB\\\fIddd\fR arbitrary byte (where \fIddd\fR is one, two or three octal digits). +.fi diff --git a/driver.c b/driver.c new file mode 100644 index 0000000..e3404fd --- /dev/null +++ b/driver.c @@ -0,0 +1,47 @@ +/* + driver.c -- Top level driver program for all versions of Macross + + Chip Morningstar -- Lucasfilm Ltd. + + 3-May-1985 + +*/ + +#include + +#define MACROSS_6502 "/u1/gg/bin/macross_6502" +#define MACROSS_68000 "/u1/gg/bin/macross_68000" + +char *m6502 = "6502"; +char *m68000 = "68000"; + +char **mlist; + +main(argc, argv) + char **argv; +{ + char *processor = m6502; + int i; + int j; + + mlist = (char **)calloc(argc + 1, sizeof (char **)); + for (i=1, j=1; ikindOfValue != ABSOLUTE_VALUE) + noteAnonymousReference(); + emitWordValue(target); + } + } + return(result); +} + diff --git a/emitBranch_68000.c b/emitBranch_68000.c new file mode 100644 index 0000000..21e11c6 --- /dev/null +++ b/emitBranch_68000.c @@ -0,0 +1,116 @@ +/* + emitBranch_68000.c -- Routines to deal with code generation for + branches and jumps in the Macross assembler (68000 + version). + + Chip Morningstar -- Lucasfilm Ltd. + + 29-April-1985 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* emitRelativeBranch emits a relative branch instruction for the 68000, + branching from the current location given a condition to branch upon and a + target address. */ + + void +emitRelativeBranch(condition, target, fixupLocation) + conditionType condition; + valueType *target; + valueType *fixupLocation; +{ + int i; + +#define BCS_OPCODE 0x65 +#define BCC_OPCODE 0x64 +#define BEQ_OPCODE 0x67 +#define BGE_OPCODE 0x6C +#define BGT_OPCODE 0x6E +#define BHI_OPCODE 0x62 +#define BLE_OPCODE 0x6F +#define BLS_OPCODE 0x63 +#define BLT_OPCODE 0x6D +#define BMI_OPCODE 0x6B +#define BNE_OPCODE 0x66 +#define BPL_OPCODE 0x6A +#define BVC_OPCODE 0x68 +#define BVS_OPCODE 0x69 +#define BRA_OPCODE 0x60 + + static byte conditionalBranchOpcodes[] = { + /* CARRY_COND */ BCS_OPCODE, + /* EQUAL_COND */ BEQ_OPCODE, + /* OVERFLOW_COND */ BVS_OPCODE, + /* MINUS_COND */ BMI_OPCODE, + /* LT_COND */ BLT_OPCODE, + /* LEQ_COND */ BLE_OPCODE, + /* LOW_OR_SAME */ BLS_OPCODE, + /* ALWAYS_COND */ BRA_OPCODE, + /* NOT_CARRY_COND */ BCC_OPCODE, + /* NOT_EQUAL_COND */ BNE_OPCODE, + /* NOT_OVERFLOW_COND */ BVC_OPCODE, + /* PLUS_COND */ BPL_OPCODE, + /* GEQ_COND */ BGE_OPCODE, + /* GT_COND */ BGT_OPCODE, + /* HIGH_COND */ BHI_OPCODE, + /* NEVER_COND */ 0, + }; + + if (fixupLocation != NULL) + fixupLocation->value = -1; + if (condition == NEVER_COND) + return; + emitByte(conditionalBranchOpcodes[(int)condition]); + if (isByteOffset(target - (currentLocationCounter.value + 1))) { + if (fixupLocation != NULL) + *fixupLocation = currentLocationCounter; + emitRelativeByteOffset(target); + } else { + emitByte(0); + if (fixupLocation != NULL) + *fixupLocation = currentLocationCounter; + emitRelativeWordOffset(target); + } +} + + +/* emitJump emits a 68000 jump instruction given the target address */ + + simpleFixupListType * +emitJump(target, previousFixups) + valueType *target; + simpleFixupListType *previousFixups; +{ + simpleFixupListType *result; + + simpleFixupListType *buildSimpleFixupList(); + +#define JUMP_OPCODE_WORD 0x4EF8 +#define JUMP_OPCODE_LONG 0x4EF9 +#define JUMP_OPCODE_PC_REL 0x4EFA + + result = previousFixups; + if (target == NULL) { + emitWord(JUMP_OPCODE_LONG); + result = buildSimpleFixupList(currentLocationCounter, result); + emitWord(0); + } else if (target->kindOfValue != ABSOLUTE_VALUE) { + emitWord(JUMP_OPCODE_LONG); + noteAnonymousReference(); + emitLongValue(target); + } else if (isWordOffset(target->value-currentLocationCounter.value)) { + emitWord(JUMP_OPCODE_PC_REL); + emitWord(target->value - currentLocationCounter.value); + } else if (isWord(target)) { + emitWord(JUMP_OPCODE_WORD); + emitWord(target); + } else { + emitWord(JUMP_OPCODE_LONG); + emitLong(target); + } + return(result); +} + diff --git a/emitStuff.c b/emitStuff.c new file mode 100644 index 0000000..c97ed27 --- /dev/null +++ b/emitStuff.c @@ -0,0 +1,560 @@ +/* + emitStuff.c -- Routines to actually generate binary stuff for the + Macross assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 14-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* + Emitted code is stored in places that are allocated dynamically as they + are needed. This saves us from having to keep umpteenK of code buffer + around ALL the time and also lets us keep track of where code has actually + been put for purposes of generating the final object module. + + The structure of the code storage is: there are two code region structs + (type 'codeRegionType'), one each for absolute and relocatable code. These + are stored in the global array 'codeRegions' which is indexed by + 'currentCodeMode' which in turn indicates whether we are emitting aboslute + or relocatable code. Each of these region structs contains a vector of + [currently 64] pointers to code segment structs (type 'codeSegmentType'). + Each code segment represents a [currently 1Kbyte] piece of the target + processor address space; it contains the high and low addresses within + that space that have been occupied up until now and a pointer to a + [1Kbyte] buffer that actually contains the code. + + Initially, the code regions are filled with vectors of null pointers and + there are no code segments allocated. As code is emitted, the space for + the code segments and their associated buffers is allocated using 'malloc'. + Only the actual buffers needed are allocated, resulting in substantial + storage savings. + + A complication that can arise from Macross 'struct's. Structs are + assembled in a small scratch buffer and then transferred to the main code + buffers as needed. + */ + + +/* incarnateCodeBuffer causes code buffer space to actually be allocated */ + + void +incarnateCodeBuffer(bufferNum, bufferKind) + int bufferNum; + codeBufferKindType bufferKind; +{ + codeSegmentType *newCodeSegment; + codeBufferType *newCodeBuffer; + int i; + + newCodeSegment = typeAlloc(codeSegmentType); + newCodeBuffer = typeAlloc(codeBufferType); + for (i=0; icodeStartAddress = 0xFFFF + 1; + newCodeSegment->codeEndAddress = -1; + newCodeSegment->codeBuffer = newCodeBuffer; + codeRegions[(int)bufferKind]->codeSegments[bufferNum] = + newCodeSegment; +} + + +/* putByte actually puts a byte in code storage somewhere, given the address + and the byte itself. It tracks down the appropriate code buffer, taking + care to make sure said buffer actually exists before using it. */ + + void +putByte(address, byteValue) + addressType address; + byte byteValue; +{ + int bufferNum; + int bufferPos; + codeBufferType *theBuffer; + codeSegmentType *theSegment; + + bufferNum = bufferNumber(address); + bufferPos = bufferPosition(address); + if (bufferNum >= CODE_BUFFERS_IN_ADDRESS_SPACE) { + fatalError(ADDRESS_OUTSIDE_ADDRESS_SPACE_ERROR, address); + return; + } + theSegment = codeRegions[(int)currentCodeMode]->codeSegments[ + bufferNum]; + if (theSegment == NULL) { + incarnateCodeBuffer(bufferNum, currentCodeMode); + theSegment = codeRegions[(int)currentCodeMode]->codeSegments[ + bufferNum]; + } + theBuffer = theSegment->codeBuffer; + if (currentCodeMode == RELOCATABLE_BUFFER && address > + relocatableHighWaterMark) + relocatableHighWaterMark = address; + if (address > theSegment->codeEndAddress) + theSegment->codeEndAddress = address; + if (address < theSegment->codeStartAddress) + theSegment->codeStartAddress = address; + if (address > codeRegions[(int)currentCodeMode]->regionEndAddress) + codeRegions[(int)currentCodeMode]->regionEndAddress = address; + if (address < codeRegions[(int)currentCodeMode]->regionStartAddress) + codeRegions[(int)currentCodeMode]->regionStartAddress = + address; + (*theBuffer)[bufferPos] = byteValue; +} + + +/* mapByte is like 'putByte', but places its values in the struct assembly + buffer */ + + void +mapByte(address, byteValue) + int address; + byte byteValue; +{ + if (address < MAXIMUM_ALLOWED_STRUCT_SIZE) + structScratchBuffer[address] = byteValue; +} + + +/* emitByte outputs one byte at the current location in either the current + code buffer or the current struct assembly buffer */ + + void +emitByte(byteValue) + byte byteValue; +{ + if (debug || emitPrint) + if (structNestingDepth == 0) + printf("emitByte(%x: %x)\n", currentLocationCounter. + value, byteValue); + else + printf("emitByte in struct (%x: %x)\n", + currentFieldOffset, byteValue); + if (structNestingDepth == 0) { + putByte(currentLocationCounter.value++, byteValue); + } else { + mapByte(currentFieldOffset++, byteValue); + } +} + + +/* emitWord similarly emits a word */ + + void +emitWord(wordValue) + wordType wordValue; +{ + byteToWordType convert; + int loByte, hiByte; + +/* We hack around with this, even though it's less portable, so that we can + avoid doing a division and a modulo on every word we emit (since code + emission is in the inner loop). */ + +#ifdef BYTESWAPPED + loByte = 1; + hiByte = 0; +#else + loByte = 0; + hiByte = 1; +#endif + convert.wordPart = wordValue; + if (debug || emitPrint) + if (structNestingDepth == 0) + printf("emitWord(%x: %x)\n", currentLocationCounter. + value, wordValue); + else + printf("emitWord in struct (%x: %x)\n", + currentFieldOffset, wordValue); + if (structNestingDepth == 0) { +#if TARGET_CPU == CPU_6502 + putByte(currentLocationCounter.value++, + convert.bytePart[loByte]); + putByte(currentLocationCounter.value++, + convert.bytePart[hiByte]); +#else if TARGET_CPU == CPU_68000 + putByte(currentLocationCounter.value++, + convert.bytePart[hiByte]); + putByte(currentLocationCounter.value++, + convert.bytePart[loByte]); +#endif + } else { +#if TARGET_CPU == CPU_6502 + mapByte(currentFieldOffset++, convert.bytePart[loByte]); + mapByte(currentFieldOffset++, convert.bytePart[hiByte]); +#else if TARGET_CPU == CPU_68000 + mapByte(currentFieldOffset++, convert.bytePart[hiByte]); + mapByte(currentFieldOffset++, convert.bytePart[loByte]); +#endif + } +} + +/* emitLong similarly emits a long */ + + void +emitLong(longValue) + longType longValue; +{ + byteToLongType convert; + int loByte, secondByte, thirdByte, hiByte; + +/* We hack around with this, even though it's less portable, so that we can + avoid doing a division and a modulo on every long we emit (since code + emission is in the inner loop). */ + +#ifdef BYTESWAPPED + /* Sun workstation... */ + loByte = 3; + secondByte = 2; + thirdByte = 1; + hiByte = 0; +#else + /* Vax... */ + loByte = 0; + secondByte = 1; + thirdByte = 2; + hiByte = 3; +#endif + convert.longPart = longValue; + if (debug || emitPrint) + if (structNestingDepth == 0) + printf("emitLong(%x: %x)\n", currentLocationCounter. + value, longValue); + else + printf("emitLong in struct (%x: %x)\n", + currentFieldOffset, longValue); + if (structNestingDepth == 0) { +#if TARGET_CPU == CPU_6502 + putByte(currentLocationCounter.value++, + convert.bytePart[loByte]); + putByte(currentLocationCounter.value++, + convert.bytePart[secondByte]); + putByte(currentLocationCounter.value++, + convert.bytePart[thirdByte]); + putByte(currentLocationCounter.value++, + convert.bytePart[hiByte]); +#else if TARGET_CPU == CPU_68000 + putByte(currentLocationCounter.value++, + convert.bytePart[hiByte]); + putByte(currentLocationCounter.value++, + convert.bytePart[thirdByte]); + putByte(currentLocationCounter.value++, + convert.bytePart[secondByte]); + putByte(currentLocationCounter.value++, + convert.bytePart[loByte]); +#endif + } else { +#if TARGET_CPU == CPU_6502 + mapByte(currentFieldOffset++, convert.bytePart[loByte]); + mapByte(currentFieldOffset++, convert.bytePart[secondByte]); + mapByte(currentFieldOffset++, convert.bytePart[thirdByte]); + mapByte(currentFieldOffset++, convert.bytePart[hiByte]); +#else if TARGET_CPU == CPU_68000 + mapByte(currentFieldOffset++, convert.bytePart[hiByte]); + mapByte(currentFieldOffset++, convert.bytePart[thirdByte]); + mapByte(currentFieldOffset++, convert.bytePart[secondByte]); + mapByte(currentFieldOffset++, convert.bytePart[loByte]); +#endif + } +} + + +/* emitByteValue takes the byte to be emitted out of a 'valueType' */ + + void +emitByteValue(byteValue) + valueType *byteValue; +{ + if (byteValue->kindOfValue == ABSOLUTE_VALUE || byteValue->kindOfValue == + RELOCATABLE_VALUE || byteValue->kindOfValue == UNDEFINED_VALUE) { + if (byteCheck(byteValue->value) && byteValue->kindOfValue!=FAIL) { + if (debug || emitPrint) { + if (structNestingDepth == 0) + printf("emitByteValue(%x: ",currentLocationCounter.value); + else + printf("emitByteValue in struct (%x:",currentFieldOffset); + printValue(byteValue); + printf(")\n"); + } + emitByte(byteValue->value); + } + } else { + if (byteValue->kindOfValue != FAIL) + error(NON_ADDRESS_BYTE_VALUE_ERROR, valueKindString(byteValue-> + kindOfValue)); + } +} + + +/* emitString similarly spits out a string of bytes */ + + void +emitString(string) + stringType *string; +{ + if (debug || emitPrint) + if (structNestingDepth == 0) + printf("emitString(%x: \"%s\")\n", + currentLocationCounter.value, string); + else + printf("emitString in struct(%x: \"%s\")\n", + currentFieldOffset, string); +/* Horrible terrible no good very bad cretinous ugly hack, but no graceful + way to avoid it: a 0xFF byte in the string means output a 0x00 byte in + the object. This is so we can embed nuls in strings without embedding + nuls in strings, so to speak. We assume that the character 0xFF is not + likely to be needed since ASCII (and ATASCII) is a seven bit character + code. */ + while (*string != NULL) + if ((*string & 0xFF) == 0xFF) { + emitByte('\0'); + string++; + } else { + emitByte(*string++); + } +} + + +/* emitWordValue emits a word out of a 'valueType' */ + + void +emitWordValue(wordValue) + valueType *wordValue; +{ + if (wordValue->kindOfValue == ABSOLUTE_VALUE || wordValue->kindOfValue == + RELOCATABLE_VALUE || wordValue->kindOfValue == UNDEFINED_VALUE) { + if (wordCheck(wordValue->value) && wordValue->kindOfValue!=FAIL) { + if (debug || emitPrint) { + if (structNestingDepth == 0) + printf("emitWordValue(%x: ",currentLocationCounter.value); + else + printf("emitWordValue in struct (%x:",currentFieldOffset); + printValue(wordValue); + printf(")\n"); + } + emitWord(wordValue->value); + } + } else { + if (wordValue->kindOfValue != FAIL) + error(NON_ADDRESS_WORD_VALUE_ERROR, valueKindString(wordValue-> + kindOfValue)); + } +} + + +/* emitLongValue emits a long out of a 'valueType' */ + + void +emitLongValue(longValue) + valueType *longValue; +{ + if (longValue->kindOfValue == ABSOLUTE_VALUE || longValue->kindOfValue == + RELOCATABLE_VALUE || longValue->kindOfValue == UNDEFINED_VALUE) { + if (longValue->kindOfValue != FAIL) { + if (debug || emitPrint) { + if (structNestingDepth == 0) + printf("emitLongValue(%x: ",currentLocationCounter.value); + else + printf("emitLongValue in struct (%x:",currentFieldOffset); + printValue(longValue); + printf(")\n"); + } + emitLong(longValue->value); + } + } else { + if (longValue->kindOfValue != FAIL) + error(NON_ADDRESS_LONG_VALUE_ERROR, valueKindString(longValue-> + kindOfValue)); + } +} + + +/* pokeByteValue is like 'emitByte' but it's random access */ + + void +pokeByteValue(location, value) + addressType location; + valueType *value; +{ + currentLocationCounter.value = location; + emitByteValue(value); +} + + +/* ditto pokeWordValue */ + + void +pokeWordValue(location, value) + addressType location; + valueType *value; +{ + currentLocationCounter.value = location; + emitWordValue(value); +} + + +/* ditto pokeLongValue */ + + void +pokeLongValue(location, value) + addressType location; + valueType *value; +{ + currentLocationCounter.value = location; + emitLongValue(value); +} + + +/* ditto pokeRelativeByteValue. This is a special case used in fixing up + relative branches */ + + void +pokeRelativeByteValue(location, value) + addressType location; + valueType *value; +{ + int offset; + + currentLocationCounter.value = location; + offset = value->value - (location - targetOffset) - 1; + if (offset < 0) + offset--; +/* if (currentCodeMode == RELOCATABLE_BUFFER) + offset = 0;*/ + if (isByteOffset(offset)) { + emitByte(offset); + } else { + error(RELATIVE_OFFSET_TOO_LARGE_ERROR); + } +} + +/* ditto pokeRelativeWordValue. This is a special case used in fixing up + relative branches */ + + void +pokeRelativeWordValue(location, value) + addressType location; + valueType *value; +{ + int offset; + + currentLocationCounter.value = location; + offset = value->value - (location - targetOffset); + if (isWordOffset(offset)) { + emitWord(offset); + } else { + error(RELATIVE_OFFSET_TOO_LARGE_ERROR); + } +} + + +/* getByte fetches a byte back out of the labyrinth of code buffers */ + + byte +getByte(address) + addressType address; +{ + int bufferNum; + int bufferPos; + codeBufferType *theBuffer; + codeSegmentType *theSegment; + + bufferNum = bufferNumber(address); + bufferPos = bufferPosition(address); + theSegment = codeRegions[(int)currentCodeMode]->codeSegments[ + bufferNum]; + if (theSegment == NULL) + return(0); + else + return((*(theSegment->codeBuffer))[bufferPos]); +} + + void +emitRelativeByteOffset(target) + valueType *target; +{ + int saveTargetOffset; + + if (target == NULL) { + emitByte(0); + } else { + (target->value)++; + saveTargetOffset = targetOffset; + targetOffset = 0; + pokeRelativeByteValue(currentLocationCounter.value, target); + targetOffset = saveTargetOffset; + (target->value)--; + } +} + + void +emitRelativeWordOffset(target) + valueType *target; +{ + int saveTargetOffset; + + if (target == NULL) { + emitWord(0); + } else { + saveTargetOffset = targetOffset; + targetOffset = 0; + pokeRelativeWordValue(currentLocationCounter.value, target); + targetOffset = saveTargetOffset; + } +} + +/* fixupBranch repairs a previously undefined branch once the branch address + has become known. */ + + void +fixupBranch(location, target) + valueType location[COMPOUND_BRANCH_MAX]; + valueType target; +{ + valueType saveCurrentLocation; + int saveTargetOffset; + int i; + + saveCurrentLocation = currentLocationCounter; + saveTargetOffset = targetOffset; + targetOffset = 0; + for (i=0; i= 0) + pokeRelativeByteValue(location[i].value, &target); + } + targetOffset = saveTargetOffset; + currentLocationCounter = saveCurrentLocation; +} + + +/* fixupJump similarly repairs a jump */ + + void +fixupJump(locations, target) + simpleFixupListType *locations; + valueType target; +{ + valueType saveCurrentLocation; + simpleFixupListType *oldLocation; + + saveCurrentLocation = currentLocationCounter; + while (locations != NULL) { + currentLocationCounter = locations->locationToFixup; + noteAnonymousReference(); + target.value -= targetOffset; + if (positionIndependentCodeMode) + pokeRelativeByteValue(locations->locationToFixup. + value, &target); + else + pokeWordValue(locations->locationToFixup.value, + &target); + target.value += targetOffset; + oldLocation = locations; + locations = locations->nextFixup; + free(oldLocation); + } + currentLocationCounter = saveCurrentLocation; +} diff --git a/emitStuff.o b/emitStuff.o new file mode 100644 index 0000000..12dad71 Binary files /dev/null and b/emitStuff.o differ diff --git a/encode.c b/encode.c new file mode 100644 index 0000000..1e0dffb --- /dev/null +++ b/encode.c @@ -0,0 +1,674 @@ +/* WARNING: this file has not yet been separated into 6502 and non-6052 parts */ +/* + encode.c -- Routines to encode expressions for Macross object files. + + Chip Morningstar -- Lucasfilm Ltd. + + 8-November-1985 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" +#include "slinkyExpressions.h" + +#define nullEncode(thing) if (thing==NULL) return(TRUE); +#define byteOp(op) ((op)-256) + +bool encodingFunction; + + bool +encodeByte(aByte) + byte aByte; +{ + if (expressionBufferSize < EXPRESSION_BUFFER_LIMIT) { + expressionBuffer[expressionBufferSize++] = aByte; + return(TRUE); + } else { + error(EXPRESSION_TOO_BIG_TO_FIT_IN_OBJECT_ERROR); + return(FALSE); + } +} + + bool +encodeBigword(bigword) + int bigword; +{ + int i; + for (i=0; i>= 8; + } + return(TRUE); +} + + bool +encodeAssignmentTerm(assignmentTerm, kindOfFixup) + binopTermType *assignmentTerm; + fixupKindType kindOfFixup; +{ + nullEncode(assignmentTerm); + if ((assignmentKindType)assignmentTerm->binop != ASSIGN_ASSIGN) { + error(FUNNY_ASSIGNMENT_KIND_IN_OBJECT_EXPRESSION_ERROR); + return(FALSE); + } + return( + encodeByte(BINOP_TAG) && + encodeByte(byteOp(ASSIGN)) && + encodeIdentifier(assignmentTerm->leftArgument) && + encodeExpression(assignmentTerm->rightArgument) + ); +} + + bool +encodeBinopTerm(binopTerm, isTopLevel, kindOfFixup) + binopTermType *binopTerm; + bool isTopLevel; + fixupKindType kindOfFixup; +{ + bool encodeExpression(); + + nullEncode(binopTerm); + return ( + encodeByte(BINOP_TAG) && + encodeByte(byteOp(binopTerm->binop)) && + encodeExpression(binopTerm->leftArgument) && + encodeExpression(binopTerm->rightArgument) + ); +} + + bool +encodeCondition(condition) + conditionType condition; +{ + return( + encodeByte(CONDITION_CODE_TAG) && + encodeByte(condition) + ); +} + + int +functionNumber(function) + functionDefinitionType *function; +{ + if (function->ordinal == -1) { + function->ordinal = externalFunctionCount++; + if (externalFunctionList == NULL) { + externalFunctionList = endOfExternalFunctionList = + function; + } else { + endOfExternalFunctionList->nextExternalFunction = + function; + endOfExternalFunctionList = function; + } + } + return(function->ordinal); +} + + bool +encodeFunctionCall(functionCall) + functionCallTermType *functionCall; +{ + functionDefinitionType *theFunction; + int functionOrdinal; + symbolInContextType *workingContext; + operandListType *parameterList; + + symbolInContextType *getWorkingContext(); + + nullEncode(functionCall); + workingContext = getWorkingContext(functionCall->functionName); + if (isFunction(workingContext)) { + if (!encodeByte(FUNCTION_CALL_TAG)) + return(FALSE); + theFunction = (functionDefinitionType *)workingContext-> + value->value; + if (!encodeBigword(functionNumber(theFunction))) + return(FALSE); + } else if (isBuiltInFunction(workingContext)) { + functionOrdinal = workingContext->value->value; + if (builtInFunctionTable[functionOrdinal].isSpecialFunction) + return(encodeValue((*builtInFunctionTable[ + functionOrdinal].functionEntry)(functionCall-> + parameters, NO_FIXUP))); + if (!encodeByte(BUILTIN_FUNCTION_CALL_TAG)) + return(FALSE); + if (builtInFunctionTable[functionOrdinal].ordinal < 0) { + error(BUILT_IN_FUNCTION_NOT_AVAILABLE_IN_OBJECT_ERROR, + builtInFunctionTable[functionOrdinal]. + functionName); + return(FALSE); + } else if (!encodeBigword(builtInFunctionTable[ + functionOrdinal].ordinal)) { + return(FALSE); + } + } else { + error(NOT_A_FUNCTION_ERROR, symbName(functionCall-> + functionName)); + return(FALSE); + } + parameterList = functionCall->parameters; + if (!encodeByte(countParameters(parameterList))) + return(FALSE); + while (parameterList != NULL) + if (!encodeOperand(parameterList)) + return(FALSE); + else + parameterList = parameterList->nextOperand; + return(TRUE); +} + + bool +encodeHere() +{ + return(encodeByte(HERE_TAG)); +} + + bool +encodeIdentifier(identifier) + symbolTableEntryType *identifier; +{ + symbolInContextType *workingContext; + environmentType *saveEnvironment; + bool result; + + nullEncode(identifier); + + if (symbName(identifier)[0] == '$') { + error(TEMP_SYMBOL_IN_OBJECT_ERROR, symbName(identifier)); + return(FALSE); + } + if (encodingFunction) { + return(encodeByte(IDENTIFIER_TAG) && + encodeBigword(identifier->ordinal)); + } + if ((workingContext = getWorkingContext(identifier)) == NULL) { + error(UNDEFINED_SYMBOL_ERROR, symbName(identifier)); + return(FALSE); + } + if (workingContext->usage == FUNCTION_SYMBOL || workingContext->usage + == BUILT_IN_FUNCTION_SYMBOL) { + error(FUNCTION_IS_NOT_A_VALUE_ERROR, symbName(identifier)); + return(FALSE); + } + if (workingContext->value == NULL) { + error(UNDEFINED_SYMBOL_ERROR, symbName(identifier)); + return(FALSE); + } + if (workingContext->value->kindOfValue == UNDEFINED_VALUE) { + if (workingContext->attributes & GLOBAL_ATT) { + return(encodeByte(IDENTIFIER_TAG) && + encodeBigword(identifier->ordinal)); + } else { + error(UNDEFINED_SYMBOL_ERROR, symbName(identifier)); + return(FALSE); + } + } + if (workingContext->value->kindOfValue == RELOCATABLE_VALUE) { + return(encodeByte(IDENTIFIER_TAG) && + encodeBigword(identifier->ordinal)); + } + if (workingContext->value->kindOfValue == FAIL) { + error(UNASSIGNED_SYMBOL_ERROR, symbName(identifier)); + return(FALSE); + } + if (workingContext->value->kindOfValue == OPERAND_VALUE) { + saveEnvironment = currentEnvironment; + if (workingContext->usage == ARGUMENT_SYMBOL) { + currentEnvironment = currentEnvironment-> + previousEnvironment; + } + result = encodeOperand(workingContext->value->value); + currentEnvironment = saveEnvironment; + return(result); + } + if (workingContext->value->kindOfValue == BLOCK_VALUE) { + error(BLOCK_OPERAND_IN_OBJECT_EXPRESSION_ERROR); + return(FALSE); + } + return(encodeValue(workingContext->value)); +} + + bool +encodeNumber(number) + numberTermType number; +{ + return( + encodeByte(NUMBER_TAG) && + encodeBigword(number) + ); +} + + bool +encodeRelocatableNumber(number) + numberTermType number; +{ + return( + encodeByte(RELOCATABLE_TAG) && + encodeBigword(number) + ); +} + + bool +encodeOperand(operand) + operandType *operand; +{ + switch (operand->kindOfOperand) { + case EXPRESSION_OPND: + case IMMEDIATE_OPND: + case INDIRECT_OPND: + case POST_INDEXED_Y_OPND: + case PRE_INDEXED_X_OPND: + case X_INDEXED_OPND: + case Y_INDEXED_OPND: + return(encodeExpression(operand->theOperand)); + + case A_REGISTER_OPND: + case X_REGISTER_OPND: + case Y_REGISTER_OPND: + error(REGISTER_OPERAND_IN_OBJECT_EXPRESSION_ERROR); + return(FALSE); + + case X_SELECTED_OPND: + case Y_SELECTED_OPND: + case PRE_SELECTED_X_OPND: + error(SELECTION_OPERAND_IN_OBJECT_EXPRESSION_ERROR); + return(FALSE); + + case STRING_OPND: + return(encodeString(operand->theOperand)); + + case BLOCK_OPND: + error(BLOCK_OPERAND_IN_OBJECT_EXPRESSION_ERROR); + return(FALSE); + } +} + + bool +encodePostopTerm(postopTerm) + postOpTermType *postopTerm; +{ + nullEncode(postopTerm); + return( + encodeByte(POSTOP_TAG) && + encodeByte(byteOp(postopTerm->postOp)) && + encodeExpression(postopTerm->postOpArgument) + ); +} + + bool +encodePreopTerm(preopTerm) + preOpTermType *preopTerm; +{ + nullEncode(preopTerm); + return( + encodeByte(PREOP_TAG) && + encodeByte(byteOp(preopTerm->preOp)) && + encodeExpression(preopTerm->preOpArgument) + ); +} + + bool +encodeString(string) + stringType *string; +{ + if (!encodeByte(STRING_TAG)) + return(FALSE); + while (*string != '\0') { + if (!encodeByte(*string++)) + return(FALSE); + } + return(encodeByte('\0')); +} + + bool +encodeUnopTerm(unopTerm) + unopTermType *unopTerm; +{ + nullEncode(unopTerm); + return( + encodeByte(UNOP_TAG) && + encodeByte(byteOp(unopTerm->unop)) && + encodeExpression(unopTerm->unopArgument) + ); +} + + bool +encodeValue(value) + valueType *value; +{ + switch (value->kindOfValue) { + case ABSOLUTE_VALUE: + return(encodeNumber(value->value)); + + case RELOCATABLE_VALUE: + return(encodeRelocatableNumber(value->value)); + + case OPERAND_VALUE: + return(encodeOperand(value->value)); + + case STRING_VALUE: + return(encodeString(value->value)); + + case CONDITION_VALUE: + return(encodeCondition(value->value)); + + case DATA_VALUE: + case BSS_VALUE: + case STRUCT_VALUE: + case FIELD_VALUE: + case MACRO_VALUE: + case UNDEFINED_VALUE: + case FUNCTION_VALUE: + case BLOCK_VALUE: + case BUILT_IN_FUNCTION_VALUE: + case ARRAY_VALUE: + case FAIL: + error(WRONG_KIND_OF_VALUE_IN_OBJECT_EXPRESSION_ERROR, + valueKindString(value->kindOfValue)); + return(FALSE); + } +} + + bool +encodeExpression(expression) + expressionType *expression; +{ + nullEncode(expression); + switch (expression->kindOfTerm) { + + case ARRAY_EXPR: + error(ARRAY_TERM_IN_OBJECT_EXPRESSION_ERROR); + return(FALSE); + break; + + case ASSIGN_EXPR: + return(encodeAssignmentTerm(expression->expressionTerm)); + break; + + case BINOP_EXPR: + return(encodeBinopTerm(expression->expressionTerm)); + break; + + case CONDITION_CODE_EXPR: + return(encodeCondition(expression->expressionTerm)); + break; + + case FUNCTION_CALL_EXPR: + return(encodeFunctionCall(expression->expressionTerm)); + break; + + case HERE_EXPR: + return(encodeHere()); + break; + + case IDENTIFIER_EXPR: + return(encodeIdentifier(expression->expressionTerm)); + break; + + case NUMBER_EXPR: + return(encodeNumber(expression->expressionTerm)); + break; + + case POSTOP_EXPR: + return(encodePostopTerm(expression->expressionTerm)); + break; + + case PREOP_EXPR: + return(encodePreopTerm(expression->expressionTerm)); + break; + + case SUBEXPRESSION_EXPR: + encodeExpression(expression->expressionTerm); + break; + + case STRING_EXPR: + return(encodeString(expression->expressionTerm)); + break; + + case UNOP_EXPR: + return(encodeUnopTerm(expression->expressionTerm)); + break; + + case VALUE_EXPR: + return(encodeValue(expression->expressionTerm)); + break; + + default: + botch("encodeExpression: funny expression kind %d\n", + expression->kindOfTerm); + break; + } +} + + bool +encodeAssertStatement(assertStatement) + assertStatementBodyType *assertStatement; +{ + return( + encodeByte(ASSERT_TAG) && + encodeExpression(assertStatement->condition) && + encodeExpression(assertStatement->message) + ); +} + + bool +encodeFreturnStatement(freturnStatement) + freturnStatementBodyType *freturnStatement; +{ + return( + encodeByte(FRETURN_TAG) && + encodeExpression(freturnStatement) + ); +} + + bool +encodeMdefineStatement(mdefineStatement) + defineStatementBodyType *mdefineStatement; +{ + return( + encodeByte(MDEFINE_TAG) && + encodeIdentifier(mdefineStatement->theSymbol) && + encodeExpression(mdefineStatement->theValue) + ); +} + + bool +encodeMdoUntilStatement(mdoUntilStatement) + mdoUntilStatementBodyType *mdoUntilStatement; +{ + return( + encodeByte(MDOUNTIL_TAG) && + encodeExpression(mdoUntilStatement->mdoUntilCondition) && + encodeBlock(mdoUntilStatement->mdoUntilLoop) + ); +} + + bool +encodeMdoWhileStatement(mdoWhileStatement) + mdoWhileStatementBodyType *mdoWhileStatement; +{ + return( + encodeByte(MDOWHILE_TAG) && + encodeExpression(mdoWhileStatement->mdoWhileCondition) && + encodeBlock(mdoWhileStatement->mdoWhileLoop) + ); +} + + bool +encodeMforStatement(mforStatement) + mforStatementBodyType *mforStatement; +{ + return( + encodeByte(MFOR_TAG) && + encodeExpression(mforStatement->initExpression) && + encodeExpression(mforStatement->testExpression) && + encodeExpression(mforStatement->incrExpression) && + encodeBlock(mforStatement->forLoop) + ); +} + + bool +encodeMifStatement(mifStatement) + mifStatementBodyType *mifStatement; +{ + return( + encodeByte(MIF_TAG) && + encodeExpression(mifStatement->mifCondition) && + encodeBlock(mifStatement->mifConsequence) && + encodeBlock(mifStatement->mifContinuation) + ); +} + + bool +encodeMswitchStatement(mswitchStatement) + mswitchStatementBodyType *mswitchStatement; +{ + caseListType *caseList; + caseType *theCase; + expressionListType *tagExpressionList; + + if (!(encodeByte(MSWITCH_TAG) && encodeExpression(mswitchStatement-> + switchExpression))) + return(FALSE); + for (caseList=mswitchStatement->cases; caseList!=NULL; caseList=caseList-> + nextCase) { + theCase = caseList->theCase; + for (tagExpressionList=theCase->caseTags; tagExpressionList!=NULL; + tagExpressionList=tagExpressionList->nextExpression) { + if (!encodeExpression(tagExpressionList->theExpression)) + return(FALSE); + } + if (!encodeBlock(theCase->caseBody)) + return(FALSE); + } + return(encodeByte(END_TAG)); +} + + bool +encodeMvariableStatement(mvariableStatement) + mvariableStatementBodyType *mvariableStatement; +{ + int length; + + if ((length=expressionListLength(mvariableStatement->theValue) > 1) || + mvariableStatement->theDimension!=NULL) { + error(ARRAY_MVARIABLE_IN_OBJECT_FUNCTION_ERROR); + return(FALSE); + } + if (!(encodeByte(MVARIABLE_TAG) && encodeIdentifier(mvariableStatement-> + theSymbol))) + return(FALSE); + if (length == 1) + return(encodeExpression(mvariableStatement->theValue-> + theExpression)); + else + return(encodeExpression(NULL)); +} + + bool +encodeMwhileStatement(mwhileStatement) + mwhileStatementBodyType *mwhileStatement; +{ + return( + encodeByte(MWHILE_TAG) && + encodeExpression(mwhileStatement->mwhileCondition) && + encodeBlock(mwhileStatement->mwhileLoop) + ); +} + + bool +encodeStatement(statement) + statementType *statement; +{ + switch(statement->kindOfStatement) { + + case ALIGN_STATEMENT: + case BLOCK_STATEMENT: + case BYTE_STATEMENT: + case CONSTRAIN_STATEMENT: + case DBYTE_STATEMENT: + case DEFINE_STATEMENT: + case DO_UNTIL_STATEMENT: + case DO_WHILE_STATEMENT: + case EXTERN_STATEMENT: + case FUNCTION_STATEMENT: + case IF_STATEMENT: + case INCLUDE_STATEMENT: + case INSTRUCTION_STATEMENT: + case LONG_STATEMENT: + case MACRO_STATEMENT: + case ORG_STATEMENT: + case REL_STATEMENT: + case START_STATEMENT: + case STRING_STATEMENT: + case STRUCT_STATEMENT: + case TARGET_STATEMENT: + case UNDEFINE_STATEMENT: + case VARIABLE_STATEMENT: + case WHILE_STATEMENT: + case WORD_STATEMENT: + error(ILLEGAL_STATEMENT_IN_OBJECT_FILE_FUNCTION_ERROR, + statementKindString(statement->kindOfStatement)); + return(FALSE); + + case ASSERT_STATEMENT: + return(encodeAssertStatement(statement->statementBody)); + + case FRETURN_STATEMENT: + return(encodeFreturnStatement(statement->statementBody)); + + case GROUP_STATEMENT: + return(encodeBlock(statement->statementBody)); + + case MDEFINE_STATEMENT: + return(encodeMdefineStatement(statement->statementBody)); + + case MDO_UNTIL_STATEMENT: + return(encodeMdoUntilStatement(statement->statementBody)); + + case MDO_WHILE_STATEMENT: + return(encodeMdoWhileStatement(statement->statementBody)); + + case MFOR_STATEMENT: + return(encodeMforStatement(statement->statementBody)); + + case MIF_STATEMENT: + return(encodeMifStatement(statement->statementBody)); + + case MSWITCH_STATEMENT: + return(encodeMswitchStatement(statement->statementBody)); + + case MVARIABLE_STATEMENT: + return(encodeMvariableStatement(statement->statementBody)); + + case MWHILE_STATEMENT: + return(encodeMwhileStatement(statement->statementBody)); + + case NULL_STATEMENT: + return(TRUE); + + case PERFORM_STATEMENT: + return(encodeExpression(statement->statementBody)); + + default: + botch("encodeStatementBody doesn't know kind %d\n", + statement->kindOfStatement); + return(FALSE); + } +} + + bool +encodeBlock(block) + blockType *block; +{ + if (!encodeByte(BLOCK_TAG)) + return(FALSE); + while (block != NULL) { + if (!encodeStatement(block)) + return(FALSE); + block = block->nextStatement; + } + return(encodeByte(END_TAG)); +} diff --git a/encode.o b/encode.o new file mode 100644 index 0000000..7310f71 Binary files /dev/null and b/encode.o differ diff --git a/errorStuff.c b/errorStuff.c new file mode 100644 index 0000000..99bbf68 --- /dev/null +++ b/errorStuff.c @@ -0,0 +1,360 @@ +/* + errorStuff.c -- Error handling for the Macross assembler + + Chip Morningstar -- Lucasfilm Ltd. + + 5-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +bool nullStatementFlag; + +/* puntOnError handles syntax errors and the like encountered during parsing + or lexical analysis: it issues the relevent error message and scans the + input up to the end of the line, in a (probably futile) effort to recover + from the booboo. */ + + void +puntOnError(theError, arg1, arg2, arg3) + errorType theError; + anyOldThing *arg1; + anyOldThing *arg2; + anyOldThing *arg3; +{ + char c; + void error(); + + while ((c = getc(input))!='\n' && c!=EOF) + ; + ungetc(c, input); + error(theError, arg1, arg2, arg3); +} + + +/* printErrorMessage is the general error message handler */ + + void +printErrorMessage(theError, arg1, arg2, arg3) + errorType theError; + anyOldThing *arg1; + anyOldThing *arg2; + anyOldThing *arg3; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'errorType'. */ + void fatalError(); + static bool dying = FALSE; + + static char *errorMessageStrings[] = { + "assignment in 'define' statement is not '='", + "digit '%c' is not valid in base %d", + "closing \"'\" missing in character constant", + "closing '\"' missing in string constant", + "octal value '0%o' too large to fit in a character", + "character '%c' not allowed here", + "comment not closed at end of file", + "line comment not closed at end of file", + "fatal: unable to open temporary scratch file '%s'", + "%s cannot be a valid address for an 'org'", + "negative block size in 'block' statement", + "'%s' is %s and hence unassignable", + "left and right hand sides of assignment are incompatible for '%s' operator", + "operands of '%s' are incompatible with each other", + "postincrement operand is %s and hence un-postincrementable", + "postdecrement operand is %s and hence un-postdecrementable", + "preincrement operand is %s and hence un-preincrementable", + "predecrement operand is %s and hence un-predecrementable", + "operand of '%s' is incompatible with operator", + "value is not an address", + "value is not an integer", + "can't 'align' to zero or negative value", + "left hand operand of '%s' has no value", + "too many operands for '%s' instruction (should have %d)", + "illegal address mode for '%s' instruction", + "value %d is too large to fit in a byte", + "value %d is too large to fit in a word", + "illegal address mode for '%s' instruction", + "divide by zero", + "symbol '%s' undefined", + "relative branch offset too large", + "label '%s' previously defined", + "fatal: can't open object file '%s'", + "%s can't be made external", + "warning: more than one output file name given on command line", + "warning: '-%c' is not a recognized command line flag", + "fatal: no output file name given on command line after '-o'", + "fatal: unable to open input file '%s'", + "fatal: unable to open include file '%s'", + "%s cannot be a valid boolean value", + "symbol '%s' was previously defined", + "assignment to undeclared variable '%s'", + "redefinition of variable '%s'", + "'%s' is not a struct", + "struct is too large for all components to be addressed", + "struct field '%s' previously defined", + "struct definition inside a struct definition", + "'%s' is not a struct field", + "macro '%s' previously defined", + "macro definition inside a macro or function", + "too many arguments given to macro '%s' (expects no more than %d)", + "function definition inside a macro or function", + "function '%s' previously defined", + "too many arguments given to function '%s' (expects no more than %d)", + "'%s' is not a function", + "function '%s' did not return a value", + "operand already has an address mode", + "multiple address modes in expression", + "include file name given is not a string", + "start address previously given", + "attempt to use function name '%s' as a value", + "statement with side-effects not allowed inside a function", + "symbolName can't find symbol", + "error inside macro '%s'", + "error inside function '%s'", + "fatal: no listing file name given on command line after '-l'", + "fatal: no symbol dump file name given on command line after '-%c'", + "warning: more than one listing file name given on command line", + "warning: more than one symbol dump file name given on command line", + "fatal: can't open listing file '%s'", + "fatal: can't open symbol dump file '%s'", + "fatal: source file '%s' does not have a Macross source file name", + "fatal: output file '%s' has a Macross source file name", + "fatal: list file '%s' has a Macross source file name", + "fatal: symbol dump file '%s' has a Macross source file name", + "constraint value is not an integer", + "constrained block crosses 0x%x boundary", + "symbol '%s' has no value", + "bad start address", + "align inside constraint block -- alignment ignored", + "constrain inside constraint block -- constraint ignored", + "can't emit %s as a word", + "can't emit %s as a byte", + "too few operands for '%s' instruction (should have %d)", + "bad color argument to 'atasciiColor'", + "'printf' format argument is not a string", + "'%s' argument #%d is not a string", + "no arguments given to '%s'", + "'%s' argument is not a string", + "too few arguments to '%s'", + "'%s' argument #%d is not an absolute value", + "bad substring indices", + "invalid 'assert' condition", + "invalid 'assert' message", + "'assert' failed: %s", + "'assert' failed", + "can't use %s as a switch value", + "can't use %s as a case value", + "can't forward reference a block", + "warning: turning macro expansion listing off because listing in general is off", + + "inappropriate address modes", + "can't do byte address op", + "quick data out of range", + "ccr op is byte op", + "sr op is word op", + "shift op is word op", + "cmp address is not byte op", + "usp move is long op", + "ccr move is word op", + "sr move is word op", + "cr move is long op", + "address move not byte op", + "trap data too large", + "relative offset value too large", + "can't do op from A register", + "forward reference not allowed here", + "fatal: address 0x%x is outside the available address space", + "argument '%s' to 'apply' is not a macro name", + "can't 'target' in relocatable mode", + "%s cannot be a valid address for a 'target'", + "macro '%s' is undefined", + "bad position argument to 'nthChar'", + "value argument to 'symbolDefine' is not an expression operand", + "attempt to use %s as an array", + "attempt to index an array with %s", + "array index of %d exceeds maximum of %d", + "too many initialization values for variable", + "negative array index", + "can't emit %s as a long", + "can't use ++ or -- on an element of a string", + "can't assign a non-character value into a string element", + "negative array size given to 'makeArray'", + "too many initialization values given to 'makeArray'", + "array element has no value", + "can't use prefix '%s' in an expression containing a forward reference", + "can't use postfix '%s' in an expression containing a forward reference", + "can't use assignment in an expression containing a forward reference", + "fatal: too many errors (choke, gasp, wheeze, die...)", + "expression too large for object file encoding", + "operator assignment not allowed in object file expression", + "temporary symbol '%s' in object file expression", + "block operand in object file expression", + "register operand in object file expression", + "selection operand in object file expression (not yet)", + "%s not allowed in object file expression", + "array term not allowed in object file expression", + "%s not allowed in object file function", + "array mvariable declaration in object file function", + "built-in function '%s' is not available in the linker", + "fatal: no name definition given on command line after '-D'", + "bad name definition: '%s'", + "warning: perform statement has no side effects", + }; + + static int errorCount = 0; + + if (!terseErrorMessages || currentFileName != lastErrorFile || + currentLineNumber != lastErrorLine) { + lastErrorFile = currentFileName; + lastErrorLine = currentLineNumber; + printf("\"%s\", line %d: ", currentFileName, currentLineNumber + -1); + printf(errorMessageStrings[(int)theError], arg1, arg2, arg3); + printf("\n"); + fflush(stdout); + } + if (++errorCount > ERROR_LIMIT && !dying) { + dying = TRUE; + fatalError(TOO_MANY_ERRORS_ERROR); + } +} + + void +error(theError, arg1, arg2, arg3) + errorType theError; + anyOldThing *arg1; + anyOldThing *arg2; + anyOldThing *arg3; +{ + printErrorMessage(theError, arg1, arg2, arg3); + errorFlag = TRUE; +} + + void +warning(theError, arg1, arg2, arg3) + errorType theError; + anyOldThing *arg1; + anyOldThing *arg2; + anyOldThing *arg3; +{ + printErrorMessage(theError, arg1, arg2, arg3); +} + + void +fatalError(theError, arg1, arg2, arg3) + errorType theError; + anyOldThing *arg1; + anyOldThing *arg2; + anyOldThing *arg3; +{ + printErrorMessage(theError, arg1, arg2, arg3); + chokePukeAndDie(); +} + + void +fatalSystemError(theError, arg1, arg2, arg3) + errorType theError; + anyOldThing *arg1; + anyOldThing *arg2; + anyOldThing *arg3; +{ + printErrorMessage(theError, arg1, arg2, arg3); + perror("Unix says"); + chokePukeAndDie(); +} + +/* yyerror is what yacc expects to call when it hits an error. Yacc passes + the error message as a string (this is almost always 'syntax error'). */ + + void +yyerror(s) + char *s; +{ + printf("\"%s\", line %d: %s\n", currentFileName, currentLineNumber,s); + fflush(stdout); + errorFlag = TRUE; +} + + +/* usageString is used in reporting errors having to do with symbol usage. + It provides a translation between the internal representation and + something printable (with the printable something designed to be embedded + in a sentence). */ + + char * +usageString(usageKind) + symbolUsageKindType usageKind; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'symbolUsageKindType'. */ + + static char *usageStrings[NUM_OF_SYM_USAGES] = { + "a struct name", + "a struct field name", + "a macro name", + "an argument variable name", + "a label", + "an external symbol", + "a variable", + "a macro variable", + "a symbol of unknown type", + "a dead symbol", + "a function name", + "a built-in-function name", + "a nested symbol of unknown type", + "a define symbol", + "a macro define symbol", + "an unknown function", + "an unknown macro", + }; + return(usageStrings[(int)usageKind]); +} + + +/* valueKindString similarly deals with the different kinds of values. */ + + char * +valueKindString(valueKind) + valueKindType valueKind; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'valueKindType'. */ + + static char *valueKindStrings[] = { + "an absolute value", + "a data value", + "a relocatable value", + "a bss value", + "a struct name", + "a field name", + "a macro name", + "an operand value", + "a string value", + "a condition code", + "an undefined value", + "a function name", + "a block of statements", + "a built in function", + "an array", + "a failed expression" + }; + return (valueKindStrings[(int)valueKind]); +} + +/* assignmentString similarly handles assignments */ + + char * +assignmentString(assignment) + assignmentKindType assignment; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'assignmentKindType'. */ + + static char *assignmentStringTable[] = { + "=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", + "<<=", ">>=", "macross botch! no assigment" + }; + return(assignmentStringTable[(int)assignment]); +} diff --git a/errorStuff.o b/errorStuff.o new file mode 100644 index 0000000..0f161c6 Binary files /dev/null and b/errorStuff.o differ diff --git a/errorfyle b/errorfyle new file mode 100644 index 0000000..7136330 --- /dev/null +++ b/errorfyle @@ -0,0 +1,39 @@ +make: Warning: Infinite loop: Target `macrossTypes.h' depends on itself +cc -c -g -DYYDEBUG -DTARGET_CPU=CPU_6502 y.tab.c +cc -c -g -DTARGET_CPU=CPU_6502 actions_6502.c +mv actions_6502.o actions.o +cc -c -g -DTARGET_CPU=CPU_6502 buildStuff1.c +cc -c -g -DTARGET_CPU=CPU_6502 buildStuff2.c +cc -c -g -DTARGET_CPU=CPU_6502 buildStuff3.c +cc -c -g -DTARGET_CPU=CPU_6502 builtInFunctions.c +cc -c -g -DTARGET_CPU=CPU_6502 builtInFunsSD_6502.c +mv builtInFunsSD_6502.o builtInFunsSD.o +cc -c -g -DTARGET_CPU=CPU_6502 debugPrint.c +cc -c -g -DTARGET_CPU=CPU_6502 debugPrintSD_6502.c +mv debugPrintSD_6502.o debugPrintSD.o +cc -c -g -DTARGET_CPU=CPU_6502 emitBranch_6502.c +mv emitBranch_6502.o emitBranch.o +cc -c -g -DBYTESWAPPED -DTARGET_CPU=CPU_6502 emitStuff.c +cc -c -g -DTARGET_CPU=CPU_6502 encode.c +cc -c -g -DTARGET_CPU=CPU_6502 errorStuff.c +cc -c -g -DTARGET_CPU=CPU_6502 expressionSemantics.c +cc -c -g -DTARGET_CPU=CPU_6502 fixups.c +cc -c -g -DTARGET_CPU=CPU_6502 garbage.c +cc -c -g -DTARGET_CPU=CPU_6502 initialize.c +cc -c -g -DTARGET_CPU=CPU_6502 lexer.c +cc -c -g -DTARGET_CPU=CPU_6502 listing.c +cc -c -g -DTARGET_CPU=CPU_6502 lookups.c +cc -c -g -DTARGET_CPU=CPU_6502 macrossTables_6502.c +mv macrossTables_6502.o macrossTables.o +cc -c -g -DTARGET_CPU=CPU_6502 main.c +cc -c -g -DTARGET_CPU=CPU_6502 malloc.c +cc -c -g -DTARGET_CPU=CPU_6502 object.c +cc -c -g -DTARGET_CPU=CPU_6502 operandStuffSD_6502.c +mv operandStuffSD_6502.o operandStuffSD.o +cc -c -g -DTARGET_CPU=CPU_6502 parserMisc.c +cc -c -g -DTARGET_CPU=CPU_6502 semanticMisc.c +cc -c -g -DTARGET_CPU=CPU_6502 statementSemantics.c +cc -c -g -DTARGET_CPU=CPU_6502 structSemantics.c +cc -c -g -DTARGET_CPU=CPU_6502 tokenStrings_6502.c +mv tokenStrings_6502.o tokenStrings.o +cc -g -o macross y.tab.o actions.o buildStuff1.o buildStuff2.o buildStuff3.o builtInFunctions.o builtInFunsSD.o debugPrint.o debugPrintSD.o emitBranch.o emitStuff.o encode.o errorStuff.o expressionSemantics.o fixups.o garbage.o initialize.o lexer.o listing.o lookups.o macrossTables.o main.o malloc.o object.o operandStuffSD.o parserMisc.o semanticMisc.o statementSemantics.o structSemantics.o tokenStrings.o diff --git a/expressionSemantics.c b/expressionSemantics.c new file mode 100644 index 0000000..a91d6a8 --- /dev/null +++ b/expressionSemantics.c @@ -0,0 +1,1219 @@ +/* + expressionSemantics.c -- Routines to eat up a parse tree and spit out + code. + + Chip Morningstar -- Lucasfilm Ltd. + + 12-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" + +operandType *dbOperand; /* safe temps for dbx hacking */ +expressionType *dbExpression; +symbolTableEntryType *dbSymbol; +stringType *dbString; + +#define nullEvaluate(thing) if (thing==NULL) return(NULL); +#define fail(err) if (!expressionFailed) {\ + error(err);\ + expressionFailed = TRUE;\ + } +#define fail1(err,arg) if (!expressionFailed) {\ + error(err,arg);\ + expressionFailed = TRUE;\ + } +#define fail2(err,arg1,arg2) if (!expressionFailed) {\ + error(err,arg1,arg2);\ + expressionFailed = TRUE;\ + } + +#define qfree2(a,b) if (freeFlag) { free(a); free(b); } + +#define expansionOff() {saveExpansion=expandMacros; expandMacros=FALSE;} +#define forceExpansion() {saveExpansion=expandMacros; expandMacros=TRUE;} +#define expansionOn() expandMacros=saveExpansion; + +#define moreStuff(f) (generatingFixup ? moreExpression(f) : moreText(f)) +#define moreStuff1(f,x) (generatingFixup? moreExpression(f,x) : moreText(f,x)) + + anyOldThing * +arrayLookup(arrayTerm, kindOfThing) + arrayTermType *arrayTerm; + valueKindType *kindOfThing; +{ + valueType *arrayValue; + valueType *indexValue; + arrayType *array; + int index; + stringType *string; + + valueType *evaluateExpression(); + + *kindOfThing = FAIL; + arrayValue = evaluateExpression(arrayTerm->arrayName, NO_FIXUP); + if (arrayValue->kindOfValue == FAIL) + return(NULL); + indexValue = evaluateExpression(arrayTerm->arrayIndex, NO_FIXUP); + if (indexValue->kindOfValue == FAIL) + return(NULL); + if (arrayValue->kindOfValue != ARRAY_VALUE && arrayValue->kindOfValue + != STRING_VALUE) { + error(ATTEMPT_TO_INDEX_NON_ARRAY_ERROR, valueKindString( + arrayValue->kindOfValue)); + return(NULL); + } else if (indexValue->kindOfValue != ABSOLUTE_VALUE) { + error(NON_INTEGER_INDEX_ERROR, valueKindString(indexValue-> + kindOfValue)); + return(NULL); + } + + index = indexValue->value; + if (arrayValue->kindOfValue == ARRAY_VALUE) { + array = (arrayType *)arrayValue->value; + if (index >= array->arraySize) { + error(ARRAY_INDEX_OUT_OF_RANGE_ERROR, index, + array->arraySize-1); + return(NULL); + } else if (index < 0) { + error(NEGATIVE_ARRAY_INDEX_ERROR); + return(NULL); + } else { + *kindOfThing = ARRAY_VALUE; + return((anyOldThing *)&((array->arrayContents)[index])); + } + } else { + string = (stringType *)arrayValue->value; + if (index >= strlen(string)) { + error(ARRAY_INDEX_OUT_OF_RANGE_ERROR, index, + strlen(string) - 1); + return(NULL); + } else if (index < 0) { + error(NEGATIVE_ARRAY_INDEX_ERROR); + return(NULL); + } else { + *kindOfThing = STRING_VALUE; + return((anyOldThing *) &(string[index])); + } + } +} + + valueType * +evaluateArrayTerm(arrayTerm) + arrayTermType *arrayTerm; +{ + anyOldThing *resultThing; + valueKindType kindOfResult; + stringType *charPtr; + valueType **valuePtr; + valueType *result; + environmentType *saveEnvironment; + bool saveExpansion; + + valueType *newValue(); + valueType *evaluateOperand(); + + expansionOff(); + resultThing = arrayLookup(arrayTerm, &kindOfResult); + expansionOn(); + if (kindOfResult == STRING_VALUE) { + charPtr = (stringType *) resultThing; + expand(moreExpression("'%c'", *charPtr)); + return(newValue(ABSOLUTE_VALUE, *charPtr, EXPRESSION_OPND)); + } else if (kindOfResult == FAIL) { + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } else if (*(valueType **)resultThing == NULL) { + error(VALUELESS_ARRAY_ELEMENT_ERROR); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } else { + valuePtr = (valueType **) resultThing; + if ((*valuePtr)->kindOfValue == OPERAND_VALUE) { + saveEnvironment = currentEnvironment; + currentEnvironment = currentEnvironment-> + previousEnvironment; + expansionOff(); + result = evaluateOperand((*valuePtr)->value); + expansionOn(); + currentEnvironment = saveEnvironment; + } else { + dupValue(result, *valuePtr); + } + expand(result->kindOfValue==ABSOLUTE_VALUE ? + moreExpression("0x%x", result->value) : (result-> + kindOfValue==STRING_VALUE ? moreExpression("\"%s\"", + result->value) : 0)); + return(result); + } +} + + valueType * +evaluateAssignmentTerm(assignmentTerm, kindOfFixup) + binopTermType *assignmentTerm; + fixupKindType kindOfFixup; +{ + symbolTableEntryType *targetSymbol; + valueType *target; + valueType **targetPtr; + anyOldThing *targetThing; + valueType *object; + valueType *result; + valueKindType kindOfTarget; + valueKindType newKindOfValue; + symbolInContextType *targetContext; + bool stringAssign; + char *charPtr; + char objectChar; + + symbolTableEntryType *effectiveSymbol(); + valueType *evaluateExpressionInternally(); + valueKindType addValueKind(); + valueKindType selectValueKind(); + valueKindType subValueKind(); + valueKindType opValueKind(); + valueType *makeUndefinedValue(); + valueType *newValue(); + + nullEvaluate(assignmentTerm); + sideEffectFlag = TRUE; + stringAssign = FALSE; + if (assignmentTerm->leftArgument->kindOfTerm == IDENTIFIER_EXPR) { + targetSymbol = effectiveSymbol(assignmentTerm->leftArgument-> + expressionTerm.identifierUnion, &targetContext); + if (isAssignable(targetContext)) { + if ((target = targetContext->value) == NULL && + (assignmentKindType)assignmentTerm->binop != + ASSIGN_ASSIGN) { + error(OPERATOR_ASSIGNMENT_ON_NULL_TARGET_ERROR, tokenString( + assignmentTerm->binop)); + return(object); /* wrong --needs evaluation */ + } + targetPtr = &(targetContext->value); + expand(moreExpression("%s %s ", symbName(targetSymbol), + assignmentString(assignmentTerm->binop))); + } else { + if (targetContext->usage == DEAD_SYMBOL || targetContext->usage == + UNKNOWN_SYMBOL || targetContext->usage == + NESTED_UNKNOWN_SYMBOL) { + fail1(UNDECLARED_VARIABLE_ERROR, symbName(targetSymbol)); + } else { + fail2(UNASSIGNABLE_SYMBOL_TYPE_ERROR, symbName(targetSymbol), + usageString(targetContext->usage)); + } + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + } else { + targetThing = arrayLookup(assignmentTerm->leftArgument-> + expressionTerm.arrayUnion, &kindOfTarget); + if (kindOfTarget == FAIL) { + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } else if (kindOfTarget == ARRAY_VALUE) { + targetPtr = (valueType **) targetThing; + target = *targetPtr; + } else if (kindOfTarget == STRING_VALUE) { + charPtr = (char *) targetThing; + stringAssign = TRUE; + } + } + + if (isUndefined(object = evaluateExpressionInternally(assignmentTerm-> + rightArgument, FALSE, kindOfFixup, FALSE))) { + result = makeUndefinedValue(); + result->addressMode = object->addressMode; + return(result); + } else if (object->kindOfValue == FAIL) { + return(object); /* we can use it as it's a failure */ + } + if (stringAssign) { + if (object->kindOfValue == ABSOLUTE_VALUE) { + objectChar = object->value & 0xFF; + } else { + fail(NON_CHARACTER_STRING_ASSIGNMENT_ERROR); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + } + + switch (assignmentTerm->binop) { + + case ASSIGN_ASSIGN: + if (stringAssign) { + *charPtr = objectChar; + } else if (target == NULL) { + *targetPtr = object; + dupValue(result, object); + return(result); + } else { + newKindOfValue = object->kindOfValue; + target->value = object->value; + } + break; + + case ADD_ASSIGN: + if (stringAssign) + *charPtr += objectChar; + else if ((newKindOfValue = addValueKind(target, object)) != + FAIL) + target->value += object->value; + break; + + case AND_ASSIGN: + if (stringAssign) + *charPtr &= objectChar; + else if ((newKindOfValue = opValueKind(target, object)) != + FAIL) + target->value &= object->value; + break; + + case DIV_ASSIGN: + if (stringAssign) + *charPtr /= objectChar; + else if ((newKindOfValue = opValueKind(target, object)) != + FAIL) + target->value /= object->value; + break; + + case LEFT_SHIFT_ASSIGN: + if (stringAssign) + *charPtr <<= objectChar; + else if ((newKindOfValue = opValueKind(target, object)) != + FAIL) + target->value <<= object->value; + break; + + case MOD_ASSIGN: + if (stringAssign) + *charPtr %= objectChar; + else if ((newKindOfValue = opValueKind(target, object)) != + FAIL) + target->value %= object->value; + break; + + case MUL_ASSIGN: + if (stringAssign) + *charPtr *= objectChar; + else if ((newKindOfValue = opValueKind(target, object)) != + FAIL) + target->value *= object->value; + break; + + case OR_ASSIGN: + if (stringAssign) + *charPtr |= objectChar; + else if ((newKindOfValue = opValueKind(target, object)) != + FAIL) + target->value |= object->value; + break; + + case RIGHT_SHIFT_ASSIGN: + if (stringAssign) + *charPtr >>= objectChar; + else if ((newKindOfValue = opValueKind(target, object)) != + FAIL) + target->value >>= object->value; + break; + + case SUB_ASSIGN: + if (stringAssign) + *charPtr -= objectChar; + else if ((newKindOfValue = subValueKind(target, object)) != + FAIL) + target->value -= object->value; + break; + + case XOR_ASSIGN: + if (stringAssign) + *charPtr ^= objectChar; + else if ((newKindOfValue = opValueKind(target, object)) != + FAIL) + target->value ^= object->value; + break; + + case NO_ASSIGN: + botch("try to assign with NO_ASSIGN\n"); + break; + + default: + botch("bad assignment kind\n"); + break; + } + if (newKindOfValue == FAIL) { + fail1(INCOMPATIBLE_ASSIGNMENT_OPERANDS_ERROR, + assignmentString(assignmentTerm->binop)); + target->value = 0; + } + if (stringAssign) { + result = newValue(ABSOLUTE_VALUE, *charPtr, EXPRESSION_OPND); + } else { + target->kindOfValue = newKindOfValue; + dupValue(result, target); + } + return(result); +} + + valueType * +evaluateBinopTerm(binopTerm, isTopLevel, kindOfFixup) + binopTermType *binopTerm; + bool isTopLevel; + fixupKindType kindOfFixup; +{ + valueType *leftOperand; + valueType *rightOperand; + symbolTableEntryType *rightSelection; + valueKindType resultKindOfValue; + int resultValue; + operandKindType resultAddressMode; + valueType *result; + + symbolInContextType *getWorkingContext(); + valueType *evaluateExpressionInternally(); + valueType *newValue(); + valueType *makeUndefinedValue(); + + nullEvaluate(binopTerm); + if (binopTerm->binop != SUB && binopTerm->binop != ADD) + isTopLevel = FALSE; + leftOperand = evaluateExpressionInternally(binopTerm->leftArgument, + isTopLevel, kindOfFixup, FALSE); + expand(moreExpression("%s", tokenString(binopTerm->binop))); + if (binopTerm->binop != ADD) + isTopLevel = FALSE; + if (binopTerm->binop == SELECT) { + expand(moreExpression("%s", symbName((symbolTableEntryType *) + binopTerm->rightArgument))); + dupValue(rightOperand, getWorkingContext( + (symbolTableEntryType *)(binopTerm->rightArgument))-> + value); + } else { + rightOperand = evaluateExpressionInternally(binopTerm-> + rightArgument, FALSE, kindOfFixup, FALSE); + } + if (isLogicalOp(binopTerm->binop)) { + resultAddressMode = EXPRESSION_OPND; + } else { + resultAddressMode = leftOperand->addressMode; + if (leftOperand->addressMode!=EXPRESSION_OPND && + rightOperand->addressMode!=EXPRESSION_OPND) { + error(MULTIPLE_ADDRESS_MODES_ERROR); + qfree2(leftOperand, rightOperand); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } else if (rightOperand->addressMode != EXPRESSION_OPND) { + resultAddressMode = rightOperand->addressMode; + } + } + if ((isUndefined(leftOperand) && !isFailure(rightOperand)) || + (isUndefined(rightOperand) && !isFailure(leftOperand))) { + qfree2(leftOperand, rightOperand); + result = makeUndefinedValue(); + result->addressMode = resultAddressMode; + return(result); + } + + switch (binopTerm->binop) { + + case ADD: + if ((resultKindOfValue = addValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value + + rightOperand->value; + break; + + case ASSIGN: + botch("assignment leaked thru to binop\n"); + break; + + case BITWISE_AND: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value & + rightOperand->value; + break; + + case BITWISE_OR: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value | + rightOperand->value; + break; + + case BITWISE_XOR: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value ^ + rightOperand->value; + break; + + case DIV: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + if (rightOperand->value == 0) { + fail(DIVIDE_BY_ZERO_ERROR); + resultKindOfValue = FAIL; + } else { + resultValue = leftOperand->value / + rightOperand->value; + } + break; + + case EQUAL_TO: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value == + rightOperand->value; + break; + + case GREATER_THAN: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value > + rightOperand->value; + break; + + case GREATER_THAN_OR_EQUAL_TO: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value >= + rightOperand->value; + break; + + case LEFT_SHIFT: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value << + rightOperand->value; + break; + + case LESS_THAN: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value < + rightOperand->value; + break; + + case LESS_THAN_OR_EQUAL_TO: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value <= + rightOperand->value; + break; + + case LOGICAL_AND: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value && + rightOperand->value; + break; + + case LOGICAL_OR: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value || + rightOperand->value; + break; + + case LOGICAL_XOR: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = logicalXOR(leftOperand->value, + rightOperand->value); + break; + + case MOD: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value % + rightOperand->value; + break; + + case MUL: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value * + rightOperand->value; + break; + + case NOT_EQUAL_TO: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value != + rightOperand->value; + break; + + case RIGHT_SHIFT: + if ((resultKindOfValue = opValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value >> + rightOperand->value; + break; + + case SELECT: + if ((resultKindOfValue = selectValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value + + rightOperand->value; + break; + + case SUB: + if ((resultKindOfValue = subValueKind(leftOperand, + rightOperand)) != FAIL) + resultValue = leftOperand->value - + rightOperand->value; + break; + + default: + botch("bad binop kind\n"); + break; + } + if (resultKindOfValue == FAIL) { + resultValue = 0; + fail1(INCOMPATIBLE_BINOP_OPERANDS_ERROR, + tokenString(binopTerm->binop)); + } + qfree2(leftOperand, rightOperand); + return(newValue(resultKindOfValue, resultValue, resultAddressMode)); +} + + valueType * +evaluateCondition(condition) + conditionType condition; +{ + valueType *newValue(); + + expand(moreExpression("%s", conditionString(condition))); + return(newValue(CONDITION_VALUE, condition, EXPRESSION_OPND)); +} + + valueType * +evaluateBuiltInFunctionCall(workingContext, parameters, kindOfFixup) + symbolInContextType *workingContext; + operandListType *parameters; + fixupKindType kindOfFixup; +{ + sideEffectFlag = TRUE; + return((*builtInFunctionTable[workingContext->value->value]. + functionEntry)(parameters, kindOfFixup)); +} + + valueType * +evaluateFunctionCall(functionCall, kindOfFixup, isStandalone) + functionCallTermType *functionCall; + fixupKindType kindOfFixup; + bool isStandalone; +{ + functionDefinitionType *theFunction; + int numberBound; + identifierListType *savedLocalVariableList; + int savedLabelTagNumber; + stringType *savedFunctionName; + bool savedErrorFlag; + bool savedBeneathFunction; + symbolInContextType *workingContext; + environmentType newEnvironment; + valueType *result; + bool saveExpansion; + + symbolInContextType *getWorkingContext(); + valueType *evaluateBuiltInFunctionCall(); + valueType *newValue(); + + nullEvaluate(functionCall); + sideEffectFlag = TRUE; + pushEnvironment(newEnvironment); + resultOfLastFunctionCall = NULL; + freturnExit = FALSE; + workingContext = getWorkingContext(functionCall->functionName); + expand(moreExpression("%s(", symbName(functionCall->functionName))); + if (isBuiltInFunction(workingContext)) { + popEnvironment(); + result = evaluateBuiltInFunctionCall(workingContext, + functionCall->parameters, kindOfFixup); + expand(moreExpression(")")); + return(result); + } if (isFunction(workingContext)) { + theFunction = (functionDefinitionType *)workingContext-> + value->value; + } else { + error(NOT_A_FUNCTION_ERROR, symbName(functionCall-> + functionName)); + popEnvironment(); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + savedLocalVariableList = currentLocalVariableList; + currentLocalVariableList = NULL; + savedLabelTagNumber = currentLabelTagNumber; + savedFunctionName = currentFunctionName; + currentFunctionName = symbName(theFunction->functionName); + currentLabelTagNumber = nextLabelTagNumber++; + savedErrorFlag = errorFlag; + savedBeneathFunction = beneathFunction; + errorFlag = FALSE; + if ((numberBound = bindFunctionArguments(theFunction->arguments, + functionCall->parameters, symbName( + theFunction->functionName))) > 0) { + expansionOff(); + beneathFunction = TRUE; + assembleBlock(theFunction->body); + freturnExit = FALSE; + expansionOn(); + } else + numberBound = -numberBound; + if (numberBound > 1) + unbindArguments(theFunction->arguments, numberBound-1); + unbindLocalVariables(currentLocalVariableList); + beneathFunction = savedBeneathFunction; + expand(moreExpression(")")); + currentLabelTagNumber = savedLabelTagNumber; + currentLocalVariableList = savedLocalVariableList; + currentFunctionName = savedFunctionName; + if (errorFlag) + error(ERROR_INSIDE_FUNCTION_ERROR, symbName(theFunction-> + functionName)); + else + errorFlag = savedErrorFlag; + popEnvironment(); + if (resultOfLastFunctionCall != NULL) { + return(resultOfLastFunctionCall); + } else { + if (!isStandalone) + error(FUNCTION_DID_NOT_RETURN_A_VALUE_ERROR, symbName( + theFunction->functionName)); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } +} + + valueType * +evaluateHere() +{ + valueType *newValue(); + valueType *result; + + expand(moreExpression("here")); + result = newValue(currentLocationCounter.kindOfValue, + currentLocationCounter.value, EXPRESSION_OPND); + result->value -= targetOffset; + return(result); +} + + valueType * +evaluateIdentifier(identifier, isTopLevel, kindOfFixup) + symbolTableEntryType *identifier; + bool isTopLevel; + fixupKindType kindOfFixup; +{ + symbolInContextType *workingContext; + valueType *resultValue; + valueType *result; + environmentType *saveEnvironment; + bool saveExpansion; + + valueType *newValue(); + valueType *evaluateOperand(); + symbolInContextType *getWorkingContext(); + symbolTableEntryType *generateLocalLabel(); + + nullEvaluate(identifier); + identifier->referenceCount++; + if (symbName(identifier)[0] == '$') + identifier = generateLocalLabel(identifier); + if ((workingContext = getWorkingContext(identifier)) == NULL) { + fail1(UNDEFINED_SYMBOL_ERROR, symbName(identifier)); + expand(moreExpression("%s", symbName(identifier))); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + if (workingContext->usage == DEAD_SYMBOL) { + reincarnateSymbol(workingContext, UNKNOWN_SYMBOL); + } + if (workingContext->usage == FUNCTION_SYMBOL || workingContext->usage + == BUILT_IN_FUNCTION_SYMBOL) { + fail1(FUNCTION_IS_NOT_A_VALUE_ERROR, symbName(identifier)); + expand(moreExpression("%s", symbName(identifier))); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + if (workingContext->value == NULL) { + if (kindOfFixup == NO_FIXUP) { + fail1(UNDEFINED_SYMBOL_ERROR, symbName(identifier)); + expand(moreExpression("%s", symbName(identifier))); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } else if (kindOfFixup != NO_FIXUP_OK) { + expand(moreExpression("%s", symbName(identifier))); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + } else { + resultValue = workingContext->value; + if (workingContext->value->kindOfValue == UNDEFINED_VALUE){ + if (kindOfFixup==NO_FIXUP || + (workingContext->usage!=LABEL_SYMBOL && + workingContext->usage!=EXTERNAL_SYMBOL && + workingContext->usage!=UNKNOWN_SYMBOL && + workingContext->usage!=NESTED_UNKNOWN_SYMBOL)) { + expand(moreExpression("%s", symbName( + identifier))); + if ((workingContext->attributes & GLOBAL_ATT) + !=0 && performingFixups) { + return(newValue(UNDEFINED_VALUE, 0, + resultValue->addressMode)); + } else { + fail1(UNDEFINED_SYMBOL_ERROR, + symbName(identifier)); + return(newValue(FAIL, 0, + EXPRESSION_OPND)); + } + } else if (kindOfFixup == NO_FIXUP_OK) { + expand(moreExpression("%s", symbName( + identifier))); + return(newValue(UNDEFINED_VALUE, 0, + EXPRESSION_OPND)); + } + } else if (workingContext->value->kindOfValue == FAIL) { + fail1(UNASSIGNED_SYMBOL_ERROR, symbName(identifier)); + expand(moreExpression("%s", symbName(identifier))); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + if (workingContext->value->kindOfValue == OPERAND_VALUE) { + saveEnvironment = currentEnvironment; + if (workingContext->usage == ARGUMENT_SYMBOL) { + currentEnvironment = currentEnvironment-> + previousEnvironment; + expand(shouldParenthesize(workingContext-> + value->value) ? moreExpression("(") : + 0); + } else { + expand(moreExpression("%s", + symbName(identifier))); + expansionOff(); + } + resultValue = evaluateOperand(workingContext-> + value->value); + if (workingContext->usage == ARGUMENT_SYMBOL) { + expand(shouldParenthesize(workingContext-> + value->value) ? moreExpression(")") : + 0); + } else { + expansionOn(); + } + currentEnvironment = saveEnvironment; + } else if (workingContext->value->kindOfValue == BLOCK_VALUE){ + sideEffectFlag = TRUE; + saveEnvironment = currentEnvironment; + currentEnvironment = currentEnvironment-> + previousEnvironment; + expand((moreText("{"), endLine(), tabCount++)); + assembleBlock(workingContext->value->value); + expand((tabCount--, tabIndent(), moreText("}"), + endLine())); + currentEnvironment = saveEnvironment; + return(newValue(UNDEFINED_VALUE, 0, EXPRESSION_OPND)); + } else if (workingContext->usage==MVARIABLE_SYMBOL || + workingContext->usage==VARIABLE_SYMBOL || + workingContext->usage==MDEFINE_SYMBOL) { + expand(workingContext->value->kindOfValue== + ABSOLUTE_VALUE ? moreExpression("0x%x", + workingContext->value->value) : ( + workingContext->value->kindOfValue== + STRING_VALUE ? moreExpression("\"%s\"", + workingContext->value->value) : 0)); + } else { + expand(moreExpression("%s", symbName(identifier))); + } + + dupValue(result, resultValue); + if (result->kindOfValue != UNDEFINED_VALUE) + workingContext->referenceCount += 1; + if (result->kindOfValue==RELOCATABLE_VALUE && (kindOfFixup!= + NO_FIXUP || performingFixups)) + result->value = 0; /* it'll be relocated */ + return(result); + } +} + + valueType * +evaluateNumber(number) + numberTermType number; +{ + valueType *newValue(); + + expand(moreExpression("0x%x", number)); + return(newValue(ABSOLUTE_VALUE, number, EXPRESSION_OPND)); +} + + valueType * +evaluatePostopTerm(postopTerm) + postOpTermType *postopTerm; +{ + valueType *theOperand; + valueType **theOperandPtr; + valueKindType kindOfOperand; + valueType *result; + symbolInContextType *workingContext; + symbolTableEntryType *targetSymbol; + + symbolTableEntryType *effectiveSymbol(); + symbolInContextType *getWorkingContext(); + + nullEvaluate(postopTerm); + sideEffectFlag = TRUE; + if (postopTerm->postOpArgument->kindOfTerm == IDENTIFIER_EXPR) { + targetSymbol = effectiveSymbol(postopTerm->postOpArgument-> + expressionTerm.identifierUnion, &workingContext); + if (workingContext != NULL) + theOperand = workingContext->value; + else + theOperand = NULL; + } else { + theOperandPtr = (valueType **) arrayLookup(postopTerm-> + postOpArgument->expressionTerm.arrayUnion, + &kindOfOperand); + if (kindOfOperand == FAIL) + theOperand = NULL; + else if (kindOfOperand == ARRAY_VALUE) + theOperand = *theOperandPtr; + else { + fail(CANT_POSTPREOP_STRING_ERROR); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + } + + switch (postopTerm->postOp) { + + case INCREMENT: + if (incrementable(theOperand)) { + expand(moreExpression("%s++",symbName(targetSymbol))); + dupValue(result, theOperand); + theOperand->value += 1; + return(result); + } else { + fail1(UNPOSTINCREMENTABLE_OPERAND_ERROR, + valueKindString(theOperand->kindOfValue)); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + break; + + case DECREMENT: + if (decrementable(theOperand)) { + expand(moreExpression("%s--",symbName(targetSymbol))); + dupValue(result, theOperand); + theOperand->value -= 1; + return(result); + } else { + fail1(UNPOSTDECREMENTABLE_OPERAND_ERROR, + valueKindString(theOperand->kindOfValue)); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + break; + + default: + botch("bad postop type\n"); + break; + } +} + + valueType * +evaluatePreopTerm(preopTerm) + preOpTermType *preopTerm; +{ + valueType *theOperand; + valueType *result; + valueType **theOperandPtr; + valueKindType kindOfOperand; + symbolInContextType *workingContext; + symbolTableEntryType *targetSymbol; + + symbolTableEntryType *effectiveSymbol(); + symbolInContextType *getWorkingContext(); + + nullEvaluate(preopTerm); + sideEffectFlag = TRUE; + if (preopTerm->preOpArgument->kindOfTerm == IDENTIFIER_EXPR) { + targetSymbol = effectiveSymbol(preopTerm->preOpArgument-> + expressionTerm.identifierUnion, &workingContext); + if (workingContext != NULL) + theOperand = workingContext->value; + else + theOperand = NULL; + } else { + theOperandPtr = (valueType **) arrayLookup(preopTerm-> + preOpArgument->expressionTerm.arrayUnion, + &kindOfOperand); + if (kindOfOperand == FAIL) + theOperand = NULL; + else if (kindOfOperand == ARRAY_VALUE) + theOperand = *theOperandPtr; + else { + fail(CANT_POSTPREOP_STRING_ERROR); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + } + + switch (preopTerm->preOp) { + + case INCREMENT: + if (incrementable(theOperand)) { + expand(moreExpression("%++s",symbName(targetSymbol))); + theOperand->value += 1; + dupValue(result, theOperand); + return(result); + } else { + fail1(UNPREINCREMENTABLE_OPERAND_ERROR, + valueKindString(theOperand->kindOfValue)); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + break; + + case DECREMENT: + if (decrementable(theOperand)) { + expand(moreExpression("%--s",symbName(targetSymbol))); + theOperand->value -= 1; + dupValue(result, theOperand); + return(result); + } else { + fail1(UNPREDECREMENTABLE_OPERAND_ERROR, + valueKindString(theOperand->kindOfValue)); + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } + break; + + default: + botch("bad preop type\n"); + break; + } +} + + valueType * +evaluateString(string) + stringType *string; +{ + valueType *newValue(); + stringType *newString; + + expand(moreExpression("\"%s\"", string)); + newString = (stringType *)malloc(strlen(string)+1); + strcpy(newString, string); + return(newValue(STRING_VALUE, newString, EXPRESSION_OPND)); +} + + valueType * +evaluateUnopTerm(unopTerm, kindOfFixup) + unopTermType *unopTerm; + fixupKindType kindOfFixup; +{ + valueType *theOperand; + valueKindType resultKindOfValue; + int resultValue; + operandKindType resultAddressMode; + valueType *result; + + valueKindType unopValueKind(); + valueType *newValue(); + valueType *evaluateExpressionInternally(); + valueType *makeUndefinedValue(); + + nullEvaluate(unopTerm); + expand(moreExpression("%s", tokenString(unopTerm->unop))); + theOperand = evaluateExpressionInternally(unopTerm->unopArgument, + FALSE, kindOfFixup, FALSE); + resultAddressMode = theOperand->addressMode; + if (isUndefined(theOperand)) { + qfree(theOperand); + result = makeUndefinedValue(); + result->addressMode = resultAddressMode; + return(result); + } + if ((resultKindOfValue = unopValueKind(theOperand)) != FAIL) { + switch (unopTerm->unop) { + + case BITWISE_NOT: + resultValue = ~theOperand->value; + break; + + case HI_BYTE: + resultValue = (theOperand->value>>8) & 0xFF; + break; + + case LO_BYTE: + resultValue = theOperand->value & 0xFF; + break; + + case LOGICAL_NOT: + resultValue = !theOperand->value; + break; + + case UNARY_MINUS: + resultValue = -theOperand->value; + break; + } + } else { + fail1(INCOMPATIBLE_UNOP_OPERAND_ERROR, tokenString(unopTerm-> + unop)); + resultValue = 0; + } + qfree(theOperand); + return(newValue(resultKindOfValue, resultValue, resultAddressMode)); +} + + valueType * +evaluateExpressionInternally(expression, isTopLevel, kindOfFixup,isStandalone) + expressionType *expression; + bool isTopLevel; + fixupKindType kindOfFixup; + bool isStandalone; +{ + valueType *result; + + nullEvaluate(expression); + switch (expression->kindOfTerm) { + + case ARRAY_EXPR: + return(evaluateArrayTerm(expression->expressionTerm)); + break; + + case ASSIGN_EXPR: + return(evaluateAssignmentTerm(expression->expressionTerm, + kindOfFixup)); + break; + + case BINOP_EXPR: + return(evaluateBinopTerm(expression->expressionTerm, + isTopLevel, kindOfFixup)); + break; + + case CONDITION_CODE_EXPR: + return(evaluateCondition(expression->expressionTerm)); + break; + + case FUNCTION_CALL_EXPR: + return(evaluateFunctionCall(expression->expressionTerm, + kindOfFixup, isStandalone)); + break; + + case HERE_EXPR: + return(evaluateHere()); + break; + + case IDENTIFIER_EXPR: + result = evaluateIdentifier(expression->expressionTerm, + isTopLevel, kindOfFixup); + return(result); + break; + + case NUMBER_EXPR: + return(evaluateNumber(expression->expressionTerm)); + break; + + case POSTOP_EXPR: + return(evaluatePostopTerm(expression->expressionTerm)); + break; + + case PREOP_EXPR: + return(evaluatePreopTerm(expression->expressionTerm)); + break; + + case SUBEXPRESSION_EXPR: + expand(moreExpression("(")); + result = evaluateExpressionInternally(expression-> + expressionTerm, isTopLevel, kindOfFixup, FALSE); + expand(moreExpression(")")); + return(result); + break; + + case STRING_EXPR: + return(evaluateString(expression->expressionTerm)); + break; + + case UNOP_EXPR: + return(evaluateUnopTerm(expression->expressionTerm, + kindOfFixup)); + break; + + case VALUE_EXPR: + if (expression->expressionTerm.valueUnion->kindOfValue == + OPERAND_VALUE) { + return(evaluateOperand(expression->expressionTerm. + valueUnion->value)); + } else { + dupValue(result, expression->expressionTerm. + valueUnion); + expand(moreExpression("0x%x", result->value)); + return(result); + } + break; + + default: + botch("evaluateExpression: funny expression kind %d\n", + expression->kindOfTerm); + break; + } +} + + valueType * +evaluateExpression(expression, kindOfFixup) + expressionType *expression; + fixupKindType kindOfFixup; +{ + valueType *result; + + expressionFailed = FALSE; + referencesToNote[currentOperandNumber] = NULL; + result = evaluateExpressionInternally(expression, TRUE, kindOfFixup, + FALSE); + if (result->kindOfValue == RELOCATABLE_VALUE) { + result->kindOfValue = UNDEFINED_VALUE; + result->value = 0; /* fix linker bug */ + } + if (isUndefined(result)) { + flushExpressionString(); + pendingFixup[currentOperandNumber] = expression; + } else + pendingFixup[currentOperandNumber] = NULL; + return(result); +} + + void +evaluateExpressionStandalone(expression) + expressionType *expression; +{ + bool saveExpansion; + valueType *expressionResult; + + expressionFailed = FALSE; + referencesToNote[currentOperandNumber] = NULL; + + standaloneExpansionFlag = amExpanding(); + expansionOff(); + expressionResult = evaluateExpressionInternally(expression, TRUE, + NO_FIXUP, TRUE); + expansionOn(); + standaloneExpansionFlag = FALSE; + if (expressionResult != NULL) + qfree(expressionResult); + pendingFixup[0] = NULL; +} + + valueType * +evaluateDefineExpression(expression) + expressionType *expression; +{ + valueType *newValue(); + expressionType *generateFixupExpression(); + operandType *buildOperand(); + + nullEvaluate(expression); + return(newValue(OPERAND_VALUE, buildOperand(EXPRESSION_OPND, + generateFixupExpression(expression)), EXPRESSION_OPND)); +} + + valueType * +evaluateSelectionList(selectionList) + selectionListType *selectionList; +{ + int offset; + valueType *newValue(); + + offset = 0; + while (selectionList != NULL) { + expand(moreExpression(".%s", symbName(selectionList-> + theSymbol))); + offset += fieldValue(selectionList->theSymbol); + selectionList = selectionList->nextIdentifier; + } + return(newValue(ABSOLUTE_VALUE, offset, EXPRESSION_OPND)); +} diff --git a/expressionSemantics.o b/expressionSemantics.o new file mode 100644 index 0000000..3ba29c0 Binary files /dev/null and b/expressionSemantics.o differ diff --git a/fixups.c b/fixups.c new file mode 100644 index 0000000..c977d3c --- /dev/null +++ b/fixups.c @@ -0,0 +1,346 @@ +/* + fixups.c -- Routines to handle expressions being saved away for fixups + in the Macross assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 20-December-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +operandType *dbOperand; /* safe temps for dbx hacking */ +expressionType *dbExpression; +symbolTableEntryType *dbSymbol; + +stringType *dbString = "graphics2.m"; + +#define nullDup(thing) if (thing==NULL) { return (NULL); } + +#define expansionOff() {saveExpansion=expandMacros; expandMacros=FALSE;} +#define expansionOn() expandMacros=saveExpansion; + +/* + Whenever a value is needed as the operand of an instruction or data + statement, but one or more of the terms of the expression which define the + value are themselves undefined symbols, we have to get fancy. What we do + is use a zero value and save away a copy of the expression for later + evaluation at a time (the end of assembly) when (hopefully) the undefined + symbols will have been defined. It is necessary to save a copy of the + expression, rather that the expression itself, since some of the terms of + the expression may be variables whose value may change between now and + when the saved expression gets reevaluated. When we are making the copy + we replace any variables with their present values. + + The routines below collectively duplicate expressions for later evaluation. + */ + + expressionType * +generateFixupExpression(expression) + expressionType *expression; +{ + expressionType *result; + expressionType *duplicateExpressionForFixup(); + + generatingFixup = TRUE; + result = duplicateExpressionForFixup(expression, TRUE, FALSE); + generatingFixup = FALSE; + return(result); +} + + expressionType * +duplicateExpressionForFixup(expression, isTopLevel, isSpecialFunctionOperand) + expressionType *expression; + bool isTopLevel; + bool isSpecialFunctionOperand; +{ + expressionType *result; + expressionType *originalResult; + valueType *value; + symbolTableEntryType *identifier; + symbolInContextType *context; + operandType *newOperand; + environmentType *saveEnvironment; + bool saveExpansion; + + operandType *duplicateOperandForFixup(); + symbolInContextType *getWorkingContext(); + functionCallTermType *duplicateFunctionCall(); + expressionType *duplicateArrayReference(); + valueType *evaluateIdentifier(); + valueType *evaluateHere(); + valueType *newValue(); + symbolTableEntryType *generateLocalLabel(); + stringType *saveString(); + + nullDup(expression); + result = originalResult = typeAlloc(expressionType); + *result = *expression; + switch (expression->kindOfTerm) { + + case STRING_EXPR: + expand(moreExpression("%s", expression->expressionTerm.stringUnion)); + result->expressionTerm.stringUnion = saveString(originalResult-> + expressionTerm.stringUnion); + break; + + case IDENTIFIER_EXPR: + identifier = expression->expressionTerm.identifierUnion; + if (symbName(identifier)[0] == '$') + identifier = result->expressionTerm.identifierUnion = + generateLocalLabel(identifier); + context = getWorkingContext(identifier); + if (context->usage == ARGUMENT_SYMBOL && context->value-> + kindOfValue == OPERAND_VALUE) { + if (isSpecialFunctionOperand) { + while (context->usage == ARGUMENT_SYMBOL && context->value-> + kindOfValue == OPERAND_VALUE) { + newOperand = (operandType *)context->value->value; + if (newOperand->kindOfOperand == EXPRESSION_OPND && + (expression = newOperand->theOperand. + expressionUnion) != NULL && expression-> + kindOfTerm == IDENTIFIER_EXPR) { + identifier = expression->expressionTerm. + identifierUnion; + context = getWorkingContext(identifier); + } else { + expand(moreExpression("*fail*")); + return(NULL); + } + } + expand(moreExpression("%s", symbName(identifier))); + result->expressionTerm.identifierUnion = identifier; + } else { + saveEnvironment = currentEnvironment; + currentEnvironment = currentEnvironment->previousEnvironment; + if ((newOperand = duplicateOperandForFixup( + context->value->value, + FALSE)) == NULL) { + result = NULL; + } else { + result->kindOfTerm = VALUE_EXPR; + result->expressionTerm.valueUnion = + newValue(OPERAND_VALUE, + newOperand, newOperand-> + kindOfOperand); + } + currentEnvironment = saveEnvironment; + } + } else { + expansionOff(); + if(!isUndefined(value = evaluateIdentifier(identifier, + isTopLevel, NO_FIXUP_OK)) && value->kindOfValue != + RELOCATABLE_VALUE) { + expansionOn(); + result->kindOfTerm = VALUE_EXPR; + result->expressionTerm.valueUnion = value; + expand((context->usage==MVARIABLE_SYMBOL || + context->usage==VARIABLE_SYMBOL || + context->usage==MDEFINE_SYMBOL) ? + moreExpression("0x%x", value->value) : + moreExpression("%s", symbName(identifier))); + } else { + expansionOn(); + expand(moreExpression("%s", symbName(identifier))); + } + } + break; + + case FUNCTION_CALL_EXPR: + if ((result->expressionTerm.functionCallUnion = + duplicateFunctionCall(expression-> + expressionTerm.functionCallUnion)) == NULL) + result = NULL; + break; + + case NUMBER_EXPR: + expand(moreExpression("0x%x", result->expressionTerm.numberUnion)); + /* keep unchanged */ + break; + + case SUBEXPRESSION_EXPR: + expand(moreExpression("(")); + if ((result->expressionTerm.subexpressionUnion = + duplicateExpressionForFixup(expression-> + expressionTerm.subexpressionUnion, + isTopLevel, FALSE)) == NULL) + result = NULL; + expand(moreExpression(")")); + break; + + case UNOP_EXPR: + expand(moreExpression("%s", tokenString(expression->expressionTerm. + unopUnion->unop))); + result->expressionTerm.unopUnion = typeAlloc(unopTermType); + result->expressionTerm.unopUnion->unop = expression->expressionTerm. + unopUnion->unop; + if ((result->expressionTerm.unopUnion->unopArgument = + duplicateExpressionForFixup(expression-> + expressionTerm.unopUnion->unopArgument, + FALSE, FALSE)) == NULL) + result = NULL; + break; + + case BINOP_EXPR: + result->expressionTerm.binopUnion = typeAlloc(binopTermType); + result->expressionTerm.binopUnion->binop = expression->expressionTerm. + binopUnion->binop; + if ((result->expressionTerm.binopUnion->leftArgument = + duplicateExpressionForFixup(expression-> + expressionTerm.binopUnion->leftArgument, + FALSE, FALSE)) == NULL) { + expand(moreExpression("*fail*")); + result = NULL; + } else { + expand(moreExpression("%s", tokenString(expression-> + expressionTerm.binopUnion->binop))); + if ((result->expressionTerm.binopUnion->rightArgument = + duplicateExpressionForFixup(expression-> + expressionTerm.binopUnion->rightArgument, + FALSE, FALSE)) == NULL) { + result = NULL; + expand(moreExpression("*fail*")); + } + } + break; + + + case PREOP_EXPR: + expand(moreExpression("*fail*")); + error(CANT_USE_PREOP_WITH_FORWARD_REFERENCE_ERROR, tokenString( + expression->expressionTerm.preOpUnion->preOp)); + result = NULL; + break; + + case POSTOP_EXPR: + expand(moreExpression("*fail*")); + error(CANT_USE_POSTOP_WITH_FORWARD_REFERENCE_ERROR, tokenString( + expression->expressionTerm.postOpUnion->postOp)); + result = NULL; + break; + + case HERE_EXPR: + result->kindOfTerm = VALUE_EXPR; + result->expressionTerm.valueUnion = evaluateHere(); + expand(moreExpression("0x%x", result->expressionTerm.valueUnion-> + value)); + break; + + case ASSIGN_EXPR: + expand(moreExpression("*fail*")); + error(CANT_USE_ASSIGNMENT_WITH_FORWARD_REFERENCE_ERROR); + result = NULL; + break; + + case CONDITION_CODE_EXPR: + /* keep unchanged */ + expand(moreExpression("%s", conditionString(expression-> + expressionTerm.conditionCodeUnion))); + break; + + case VALUE_EXPR: + /* keep unchanged */ + expand(moreExpression("0x%x", expression->expressionTerm.valueUnion-> + value)); + break; + + case ARRAY_EXPR: + result = duplicateArrayReference(expression->expressionTerm. + arrayUnion); + break; + + default: + botch("duplicateExpression: funny expression kind %d\n", + expression->kindOfTerm); + break; + } + return(result); +} + + functionCallTermType * +duplicateFunctionCall(functionCall) + functionCallTermType *functionCall; +{ + functionCallTermType *result; + operandListType **argument; + operandListType *parameterList; + + operandListType *duplicateOperandForFixup(); + + result = typeAlloc(functionCallTermType); + result->functionName = functionCall->functionName; + expand(moreExpression("%s(", symbName(functionCall->functionName))); + result->parameters = NULL; + parameterList = functionCall->parameters; + argument = &(result->parameters); + while (parameterList != NULL) { + *argument = duplicateOperandForFixup(parameterList, + (functionCall->functionName->context->attributes & + SPECIAL_FUNCTION_ATT) != 0); + (*argument)->nextOperand = NULL; + argument = &((*argument)->nextOperand); + parameterList = parameterList->nextOperand; + expand(parameterList != NULL ? moreExpression(", ") : 0); + } + expand(moreExpression(")")); + return(result); +} + + + expressionType * +duplicateArrayReference(arrayTerm) + arrayTermType *arrayTerm; +{ + anyOldThing *resultThing; + valueKindType kindOfResult; + expressionType *result; + stringType *charPtr; + valueType **valuePtr; + environmentType *saveEnvironment; + bool saveExpansion; + operandType *newOperand; + + valueType *newValue(); + operandType *duplicateOperandForFixup(); + anyOldThing *arrayLookup(); + + expansionOff(); + resultThing = arrayLookup(arrayTerm, &kindOfResult); + expansionOn(); + if (*(valueType **)resultThing == NULL) { + error(VALUELESS_ARRAY_ELEMENT_ERROR); + result = NULL; + } else if (kindOfResult == FAIL) { + result = NULL; + } else if (kindOfResult == STRING_VALUE) { + charPtr = (stringType *)resultThing; + result = typeAlloc(expressionType); + result->kindOfTerm = VALUE_EXPR; + result->expressionTerm.valueUnion = newValue(ABSOLUTE_VALUE, + *charPtr, EXPRESSION_OPND); + } else { + valuePtr = (valueType **) resultThing; + if ((*valuePtr)->kindOfValue == OPERAND_VALUE) { + saveEnvironment = currentEnvironment; + currentEnvironment = currentEnvironment-> + previousEnvironment; + if ((newOperand = duplicateOperandForFixup((* + valuePtr)->value, FALSE)) == NULL) { + result = NULL; + } else { + result = typeAlloc(expressionType); + result->kindOfTerm = VALUE_EXPR; + result->expressionTerm.valueUnion = newValue( + OPERAND_VALUE, newOperand, + newOperand->kindOfOperand); + } + currentEnvironment = saveEnvironment; + } else { + result = typeAlloc(expressionType); + result->kindOfTerm = VALUE_EXPR; + dupValue(result->expressionTerm.valueUnion,*valuePtr); + } + } + return(result); +} diff --git a/fixups.o b/fixups.o new file mode 100644 index 0000000..e824463 Binary files /dev/null and b/fixups.o differ diff --git a/garbage.c b/garbage.c new file mode 100644 index 0000000..9166a25 --- /dev/null +++ b/garbage.c @@ -0,0 +1,829 @@ +/* + garbage.c -- Routines to eat up a parse tree and throw it away + + Chip Morningstar -- Lucasfilm Ltd. + + 4-February-1985 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" + +#define nullFree(thing) if (thing == NULL) return; + + void +freeArrayTerm(arrayTerm) + arrayTermType *arrayTerm; +{ + void freeExpression(); + + nullFree(arrayTerm); + freeExpression(arrayTerm->arrayName); + freeExpression(arrayTerm->arrayIndex); + free(arrayTerm); +} + + void +freeAssignmentTerm(assignmentTerm) + binopTermType *assignmentTerm; +{ + void freeExpression(); + + nullFree(assignmentTerm); + freeExpression(assignmentTerm->rightArgument); + free(assignmentTerm); +} + + void +freeBinopTerm(binopTerm) + binopTermType *binopTerm; +{ + void freeExpression(); + + nullFree(binopTerm); + freeExpression(binopTerm->leftArgument); + if (binopTerm->binop != SELECT) + freeExpression(binopTerm->rightArgument); + free(binopTerm); +} + + void +freeFunctionCall(functionCall) + functionCallTermType *functionCall; +{ + void freeOperandList(); + + nullFree(functionCall); + freeOperandList(functionCall->parameters); + free(functionCall); +} + + void +freePostopTerm(postopTerm) + postOpTermType *postopTerm; +{ + nullFree(postopTerm); + free(postopTerm); +} + + void +freePreopTerm(preopTerm) + preOpTermType *preopTerm; +{ + nullFree(preopTerm); + free(preopTerm); +} + + void +freeString(string) + stringType *string; +{ + nullFree(string); + free(string); +} + + void +freeUnopTerm(unopTerm) + unopTermType *unopTerm; +{ + void freeExpression(); + + nullFree(unopTerm); + freeExpression(unopTerm->unopArgument); + free(unopTerm); +} + + void +freeExpression(expression) + expressionType *expression; +{ + nullFree(expression); + switch (expression->kindOfTerm) { + + case CONDITION_CODE_EXPR: + case HERE_EXPR: + case IDENTIFIER_EXPR: + case NUMBER_EXPR: + case VALUE_EXPR: + case STRING_EXPR: + break; + + case ARRAY_EXPR: + freeArrayTerm(expression->expressionTerm); + break; + + case ASSIGN_EXPR: + freeAssignmentTerm(expression->expressionTerm); + break; + + case BINOP_EXPR: + freeBinopTerm(expression->expressionTerm); + break; + + case FUNCTION_CALL_EXPR: + freeFunctionCall(expression->expressionTerm); + break; + + case POSTOP_EXPR: + freePostopTerm(expression->expressionTerm); + break; + + case PREOP_EXPR: + freePreopTerm(expression->expressionTerm); + break; + + case SUBEXPRESSION_EXPR: + freeExpression(expression->expressionTerm); + break; + + case UNOP_EXPR: + freeUnopTerm(expression->expressionTerm); + break; + + default: + botch("freeExpression: funny expression kind %d\n", + expression->kindOfTerm); + break; + } + free(expression); +} + + void +freeExpressionList(expressionList) + expressionListType *expressionList; +{ + expressionListType *newExpressionList; + + while (expressionList != NULL) { + freeExpression(expressionList->theExpression); + newExpressionList = expressionList->nextExpression; + free(expressionList); + expressionList = newExpressionList; + } +} + + void +freeIdentifierList(identifierList) + identifierListType *identifierList; +{ + identifierListType *newIdentifierList; + + while (identifierList != NULL) { + newIdentifierList = identifierList->nextIdentifier; + free(identifierList); + identifierList = newIdentifierList; + } +} + + void +freeSelectionList(selectionList) + selectionListType *selectionList; +{ + freeIdentifierList(selectionList); +} + + void +freeBlock(block) + blockType *block; +{ + void freeStatement(); + + nullFree(block); + freeStatement(block); +} + + void +freeCase(aCase) + caseType *aCase; +{ + freeExpressionList(aCase->caseTags); + freeBlock(aCase->caseBody); + free(aCase); +} + + void +freeCaseList(caseList) + caseListType *caseList; +{ + caseListType *newCaseList; + + while (caseList != NULL) { + freeCase(caseList->theCase); + newCaseList = caseList->nextCase; + free(caseList); + caseList = newCaseList; + } +} + + void +freeOperandList(operandList) + operandListType *operandList; +{ + freeOperand(operandList); +} + + void +freeMacro(operands) + operandListType *operands; +{ + freeOperandList(operands); +} + + void +freeMachineInstruction(operands) + operandListType *operands; +{ + freeOperandList(operands); +} + + void +freeAlignStatement(alignStatement) + alignStatementBodyType *alignStatement; +{ + nullFree(alignStatement); + freeExpression(alignStatement); +} + + void +freeAssertStatement(assertStatement) + assertStatementBodyType *assertStatement; +{ + nullFree(assertStatement); + freeExpression(assertStatement->condition); + freeExpression(assertStatement->message); + free(assertStatement); +} + + void +freeBlockStatement(blockStatement) + blockStatementBodyType *blockStatement; +{ + nullFree(blockStatement); + freeExpressionList(blockStatement); +} + + void +freeByteStatement(byteStatement) + byteStatementBodyType *byteStatement; +{ + byteStatementBodyType *newByteStatement; + + nullFree(byteStatement); + while (byteStatement != NULL) { + freeExpression(byteStatement->theExpression); + newByteStatement = byteStatement->nextExpression; + free(byteStatement); + byteStatement = newByteStatement; + } +} + + void +freeConstrainStatement(constrainStatement) + constrainStatementBodyType *constrainStatement; +{ + nullFree(constrainStatement); + freeExpression(constrainStatement->constraint); + freeBlock(constrainStatement->constrainedBlock); + free(constrainStatement); +} + + void +freeDbyteStatement(dbyteStatement) + dbyteStatementBodyType *dbyteStatement; +{ + dbyteStatementBodyType *newDbyteStatement; + + nullFree(dbyteStatement); + while (dbyteStatement != NULL) { + freeExpression(dbyteStatement->theExpression); + newDbyteStatement = dbyteStatement->nextExpression; + free(dbyteStatement); + dbyteStatement = newDbyteStatement; + } +} + + void +freeDefineStatement(defineStatement) + defineStatementBodyType *defineStatement; +{ + nullFree(defineStatement); + freeExpression(defineStatement->theValue); + free(defineStatement); +} + + void +freeDoUntilStatement(doUntilStatement) + doUntilStatementBodyType *doUntilStatement; +{ + nullFree(doUntilStatement); + freeBlock(doUntilStatement->doUntilLoop); + free(doUntilStatement); +} + + void +freeDoWhileStatement(doWhileStatement) + doWhileStatementBodyType *doWhileStatement; +{ + nullFree(doWhileStatement); + freeBlock(doWhileStatement->doWhileLoop); + free(doWhileStatement); +} + + void +freeExternStatement(externStatement) + externStatementBodyType *externStatement; +{ + freeIdentifierList(externStatement); +} + + void +freeFreturnStatement(freturnStatement) + freturnStatementBodyType *freturnStatement; +{ + nullFree(freturnStatement); + freeExpression(freturnStatement); +} + + void +freeFunctionStatement(functionStatement) + functionStatementBodyType *functionStatement; +{ + nullFree(functionStatement); + free(functionStatement->functionName); + free(functionStatement); +} + + void +freeIfStatement(ifStatement) + ifStatementBodyType *ifStatement; +{ + nullFree(ifStatement); + if (ifStatement->consequence != NULL) + freeBlock(ifStatement->consequence); + if (ifStatement->continuation.continuationBodyUnion != NULL) { + freeIfStatement(ifStatement->continuation); + } + free(ifStatement); +} + + void +freeIncludeStatement(includeStatement) + includeStatementBodyType *includeStatement; +{ + nullFree(includeStatement); + freeExpression(includeStatement); +} + + void +freeInstructionStatement(instructionStatement) + instructionStatementBodyType *instructionStatement; +{ + nullFree(instructionStatement); + switch(instructionStatement->kindOfInstruction) { + + case OPCODE_INSTRUCTION: + freeMachineInstruction(instructionStatement->theOperands); + break; + + case MACRO_INSTRUCTION: + freeMacro(instructionStatement->theOperands); + break; + + default: + botch("bad instruction type=%d\n", instructionStatement-> + kindOfInstruction); + break; + } +} + + void +freeLongStatement(longStatement) + longStatementBodyType *longStatement; +{ + longStatementBodyType *newLongStatement; + + nullFree(longStatement); + while (longStatement != NULL) { + freeExpression(longStatement->theExpression); + newLongStatement = longStatement->nextExpression; + free(longStatement); + longStatement = newLongStatement; + } +} + + void +freeMacroStatement(macroStatement) + macroStatementBodyType *macroStatement; +{ + nullFree(macroStatement); + free(macroStatement); +} + + void +freeMdefineStatement(mdefineStatement) + defineStatementBodyType *mdefineStatement; +{ + valueType *freeDefineExpression(); + + nullFree(mdefineStatement); + freeExpression(mdefineStatement->theValue); + free(mdefineStatement); +} + + void +freeMdoUntilStatement(mdoUntilStatement) + mdoUntilStatementBodyType *mdoUntilStatement; +{ + nullFree(mdoUntilStatement); + freeBlock(mdoUntilStatement->mdoUntilLoop); + freeExpression(mdoUntilStatement->mdoUntilCondition); +} + + void +freeMdoWhileStatement(mdoWhileStatement) + mdoWhileStatementBodyType *mdoWhileStatement; +{ + nullFree(mdoWhileStatement); + freeBlock(mdoWhileStatement->mdoWhileLoop); + freeExpression(mdoWhileStatement->mdoWhileCondition); + free(mdoWhileStatement); +} + + void +freeMifStatement(mifStatement) + mifStatementBodyType *mifStatement; +{ + nullFree(mifStatement); + freeExpression(mifStatement->mifCondition); + freeBlock(mifStatement->mifConsequence); + freeMifStatement(mifStatement->mifContinuation. + mifContinuationBodyUnion); + free(mifStatement); +} + + void +freeMswitchStatement(mswitchStatement) + mswitchStatementBodyType *mswitchStatement; +{ + freeExpression(mswitchStatement->switchExpression); + freeCaseList(mswitchStatement->cases); + free(mswitchStatement); +} + + void +freeMforStatement(mforStatement) + mforStatementBodyType *mforStatement; +{ + nullFree(mforStatement); + freeExpression(mforStatement->initExpression); + freeExpression(mforStatement->testExpression); + freeExpression(mforStatement->incrExpression); + freeBlock(mforStatement->forLoop); + free(mforStatement); +} + + void +freeMvariableStatement(mvariableStatement) + mvariableStatementBodyType *mvariableStatement; +{ + nullFree(mvariableStatement); + if ((int)mvariableStatement->theDimension != -1) + freeExpression(mvariableStatement->theDimension); + freeExpressionList(mvariableStatement->theValue); + free(mvariableStatement); +} + + void +freeMwhileStatement(mwhileStatement) + mwhileStatementBodyType *mwhileStatement; +{ + nullFree(mwhileStatement); + freeExpression(mwhileStatement->mwhileCondition); + freeBlock(mwhileStatement->mwhileLoop); + free(mwhileStatement); +} + + void +freeOrgStatement(orgStatement) + orgStatementBodyType *orgStatement; +{ + nullFree(orgStatement); + freeExpression(orgStatement); +} + + void +freePerformStatement(performStatement) + performStatementBodyType *performStatement; +{ + nullFree(performStatement); + freeExpression(performStatement); +} + + void +freeRelStatement(relStatement) + relStatementBodyType *relStatement; +{ +} + + void +freeStartStatement(startStatement) + startStatementBodyType *startStatement; +{ + nullFree(startStatement); + freeExpression(startStatement); +} + + void +freeStringStatement(stringStatement) + stringStatementBodyType *stringStatement; +{ + stringStatementBodyType *newStringStatement; + + nullFree(stringStatement); + while (stringStatement != NULL) { + freeExpression(stringStatement->theExpression); + newStringStatement = stringStatement->nextExpression; + free(stringStatement); + stringStatement = newStringStatement; + } +} + + void +freeStructStatement(structStatement) + structStatementBodyType *structStatement; +{ + nullFree(structStatement); + freeBlock(structStatement->structBody); + free(structStatement); +} + + void +freeTargetStatement(targetStatement) + targetStatementBodyType *targetStatement; +{ + nullFree(targetStatement); + freeExpression(targetStatement); +} + + void +freeUndefineStatement(undefineStatement) + undefineStatementBodyType *undefineStatement; +{ + freeIdentifierList(undefineStatement); +} + + void +freeVariableStatement(variableStatement) + variableStatementBodyType *variableStatement; +{ + nullFree(variableStatement); + if ((int)variableStatement->theDimension != -1) + freeExpression(variableStatement->theDimension); + freeExpressionList(variableStatement->theValue); + free(variableStatement); +} + + void +freeWhileStatement(whileStatement) + whileStatementBodyType *whileStatement; +{ + nullFree(whileStatement); + freeBlock(whileStatement->whileLoop); + free(whileStatement); +} + + void +freeWordStatement(wordStatement) + wordStatementBodyType *wordStatement; +{ + wordStatementBodyType *newWordStatement; + + nullFree(wordStatement); + while (wordStatement != NULL) { + freeExpression(wordStatement->theExpression); + newWordStatement = wordStatement->nextExpression; + free(wordStatement); + wordStatement = newWordStatement; + } +} + + void +freeStatementBody(kind, body) + statementKindType kind; + statementBodyType body; +{ + switch (kind) { + + case ALIGN_STATEMENT: + freeAlignStatement(body); + break; + + case ASSERT_STATEMENT: + freeAssertStatement(body); + break; + + case BLOCK_STATEMENT: + freeBlockStatement(body); + break; + + case BYTE_STATEMENT: + freeByteStatement(body); + break; + + case CONSTRAIN_STATEMENT: + freeConstrainStatement(body); + break; + + case DBYTE_STATEMENT: + freeDbyteStatement(body); + break; + + case DEFINE_STATEMENT: + freeDefineStatement(body); + break; + + case DO_UNTIL_STATEMENT: + freeDoUntilStatement(body); + break; + + case DO_WHILE_STATEMENT: + freeDoWhileStatement(body); + break; + + case EXTERN_STATEMENT: + freeExternStatement(body); + break; + + case FRETURN_STATEMENT: + freeFreturnStatement(body); + break; + + case FUNCTION_STATEMENT: + freeFunctionStatement(body); + break; + + case GROUP_STATEMENT: + freeBlock(body); + break; + + case IF_STATEMENT: + freeIfStatement(body); + break; + + case INCLUDE_STATEMENT: + freeIncludeStatement(body); + break; + + case INSTRUCTION_STATEMENT: + freeInstructionStatement(body); + break; + + case LONG_STATEMENT: + freeLongStatement(body); + break; + + case MACRO_STATEMENT: + freeMacroStatement(body); + break; + + case MDEFINE_STATEMENT: + freeMdefineStatement(body); + break; + + case MDO_UNTIL_STATEMENT: + freeMdoUntilStatement(body); + break; + + case MDO_WHILE_STATEMENT: + freeMdoWhileStatement(body); + break; + + case MIF_STATEMENT: + freeMifStatement(body); + break; + + case MSWITCH_STATEMENT: + freeMswitchStatement(body); + break; + + case MFOR_STATEMENT: + freeMforStatement(body); + break; + + case MVARIABLE_STATEMENT: + freeMvariableStatement(body); + break; + + case MWHILE_STATEMENT: + freeMwhileStatement(body); + break; + + case NULL_STATEMENT: + /* do nothing */ + break; + + case ORG_STATEMENT: + freeOrgStatement(body); + break; + + case PERFORM_STATEMENT: + freePerformStatement(body); + break; + + case REL_STATEMENT: + freeRelStatement(body); + break; + + case START_STATEMENT: + freeStartStatement(body); + break; + + case STRING_STATEMENT: + freeStringStatement(body); + break; + + case STRUCT_STATEMENT: + freeStructStatement(body); + break; + + case TARGET_STATEMENT: + freeTargetStatement(body); + break; + + case UNDEFINE_STATEMENT: + freeUndefineStatement(body); + break; + + case VARIABLE_STATEMENT: + freeVariableStatement(body); + break; + + case WHILE_STATEMENT: + freeWhileStatement(body); + break; + + case WORD_STATEMENT: + freeWordStatement(body); + break; + + default: + botch("freeStatementBody doesn't know kind %d\n", kind); + break; + } +} + + void +freeLabelList(labelList) + labelListType *labelList; +{ + labelListType *nextLabel; + + while (labelList != NULL) { + nextLabel = labelList->nextLabel; + free(labelList); + labelList = nextLabel; + } +} + + void +freeStatement(statement) + statementType *statement; +{ + statementType *newStatement; + + while (statement != NULL) { + freeLabelList(statement->labels); + freeStatementBody(statement->kindOfStatement, statement-> + statementBody); + newStatement = statement->nextStatement; + free(statement); + statement = newStatement; + } +} + + void +freeArray(array) + arrayType *array; +{ + int i; + void freeValue(); + + if (array->arraySize > 0) { + for (i=0; iarraySize; i++) + freeValue((array->arrayContents)[i]); + free(array->arrayContents); + } + free(array); +} + + void +freeValue(value) + valueType *value; +{ + if (value->kindOfValue == STRING_VALUE) + freeString(value->value); + else if (value->kindOfValue == ARRAY_VALUE) + freeArray(value->value); + free(value); +} diff --git a/garbage.o b/garbage.o new file mode 100644 index 0000000..01dbce6 Binary files /dev/null and b/garbage.o differ diff --git a/initialize.c b/initialize.c new file mode 100644 index 0000000..1f9d8c8 --- /dev/null +++ b/initialize.c @@ -0,0 +1,557 @@ +/* + initialize.c -- Routines to get things going for the Macross assembler + + Chip Morningstar -- Lucasfilm Ltd. + + 6-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +#define isAlphaNumeric(c) (alphaNumericCharacterTable[c]) + +extern int yydebug; + +static fileNameListType *bottomOfInputFileStack; +static char *outputFileName; + + void +chokePukeAndDie() +{ + unlink(outputFileName); + exit(1); +} + + void +initializeStuff(argc, argv) + int argc; + char *argv[]; +{ + int i; + int j; + char **args; + char *arg; + int outputFilesFound; + int listFilesFound; + int symbolDumpFilesFound; + char *listFileName; + char *symbolDumpFileName; + bool dontUnlinkTempFiles; + + void createHashTables(); + void installBuiltInFunctions(); + void installPredefinedSymbols(); + void installCommandLineDefineSymbols(); + void openFirstInputFile(); + void queueInputFile(); + void noteCommandLineDefine(); + + for (i=0; i<128; i++) { + lowerCaseCharacterTable[i] = i; + alphabeticCharacterTable[i] = FALSE; + numericCharacterTable[i] = FALSE; + alphaNumericCharacterTable[i] = FALSE; + } + for (i='A'; i<='Z'; i++) { + lowerCaseCharacterTable[i] = i - 'A' + 'a'; + alphabeticCharacterTable[i] = TRUE; + alphabeticCharacterTable[i - 'A' + 'a'] = TRUE; + alphaNumericCharacterTable[i] = TRUE; + alphaNumericCharacterTable[i - 'A' + 'a'] = TRUE; + } + alphabeticCharacterTable['_'] = TRUE; + alphaNumericCharacterTable['_'] = TRUE; + for (i='0'; i<='9'; i++) { + numericCharacterTable[i] = TRUE; + alphaNumericCharacterTable[i] = TRUE; + } + + outputFilesFound = 0; + listFilesFound = 0; + symbolDumpFilesFound = 0; + outputFileName = DEFAULT_OBJECT_FILE_NAME; + dontUnlinkTempFiles = FALSE; + produceLinkableObject = FALSE; + + currentFileName = ""; /* for error messages... */ + currentLineNumber = 1; /* ...during startup */ + cumulativeLineNumber = 1; + + nextEnvironmentNumber = GLOBAL_ENVIRONMENT_NUMBER; + currentEnvironment = NULL; + pushEnvironment(globalEnvironment); + beneathFunction = FALSE; + includeNestingDepth = 0; + macroOrFunctionNestingDepth = 0; + macroCallDepth = 0; + tabCount = 1; + statementEvaluationDepth = 0; + structNestingDepth = 0; + + performingFixups = FALSE; + generatingFixup = FALSE; + finishOperand = FALSE; + unknownSymbolTag = UNKNOWN_SYMBOL; + + haveUserStartAddress = FALSE; + fixupStartAddress = FALSE; + + currentLabelTagNumber = 0; + currentLocalVariableList = NULL; + inputFileStack = bottomOfInputFileStack = NULL; + listingControlCounter = 0; + nextLabelTagNumber = 1; + commandLineDefines = NULL; + + showAllSymbolsFlag = FALSE; + backwardsCompatibleIfFlag = FALSE; + debug = FALSE; + yydebug = FALSE; + emitPrint = FALSE; + freeFlag = TRUE; + freturnExit = FALSE; + listingOn = FALSE; + expandMacros = FALSE; + standaloneExpansionFlag = FALSE; + terseErrorMessages = FALSE; + lastErrorLine = -1; + lastErrorFile = NULL; + symbolTableDumpOn = 0; + positionIndependentCodeMode = FALSE; + hackFlag = 0; + + args = argv + 1; + for (i=1; i= argc) { + fatalError(NO_DASH_D_FILE_NAME_ERROR); + } else { + noteCommandLineDefine(*args++); + } + continue; + + case 'e': + emitPrint = TRUE; + continue; + + case 'g': + freeFlag = FALSE; + continue; + + case 'l': + if (++i >= argc) { + fatalError(NO_LIST_FILE_NAME_ERROR); + } else { + if (isDotMName(*args)) { + fatalError(LIST_FILE_NAME_IS_MACROSS_SOURCE_ERROR, + *args); + } + listFileName = *args++; + listFilesFound++; + } + listingOn = TRUE; + continue; + + case 'm': + expandMacros = TRUE; + continue; + + case 'o': + if (++i >= argc) { + fatalError(NO_DASH_O_FILE_NAME_ERROR); + } else { + if (isDotMName(*args)) { + fatalError(OUTPUT_FILE_NAME_IS_MACROSS_SOURCE_ERROR, + *args); + } + outputFileName = *args++; + outputFilesFound++; + } + continue; + + case 'p': + positionIndependentCodeMode = TRUE; + continue; + + case 's': + case 'S': + case 'h': + case 'H': + if (++i >= argc) { + fatalError(NO_SYMBOL_DUMP_FILE_NAME_ERROR, arg[j]); + } else { + if (isDotMName(*args)) { + fatalError(SYMBOL_DUMP_FILE_NAME_IS_MACROSS_SOURCE_ERROR, + *args); + } + symbolDumpFileName = *args++; + symbolDumpFilesFound++; + } + if (arg[j] == 'h') { + hackFlag = 1; + symbolTableDumpOn = 1; + } else if (arg[j] == 'H') { + hackFlag = 2; + symbolTableDumpOn = 1; + } else { + symbolTableDumpOn = arg[j]=='s' ? 1 : 2; + } + continue; + + case 't': + terseErrorMessages = TRUE; + continue; + + case 'u': + dontUnlinkTempFiles = TRUE; + continue; + + case 'v': + printVersion(); + continue; + + case 'Y': + yydebug = TRUE; + continue; + + default: + warning(BAD_COMMAND_LINE_FLAG_ERROR, arg[j]); + continue; + } + } + + openFirstInputFile(); + + if (outputFilesFound > 1) { + warning(MORE_THAN_ONE_OUTPUT_FILE_ERROR); + } else if ((objectFileOutput = fopen(outputFileName, "w"))==NULL) { + fatalSystemError(CANT_OPEN_OBJECT_FILE_ERROR, outputFileName); + } + + if (listFilesFound > 1) { + warning(MORE_THAN_ONE_LIST_FILE_ERROR); + } else if (listFilesFound == 1) { + if (strcmp(listFileName, "-") == 0) { + listFileOutput = stdout; + } else if ((listFileOutput = fopen(listFileName, "w"))==NULL){ + fatalSystemError(CANT_OPEN_LIST_FILE_ERROR, listFileName); + } + } + + if (symbolDumpFilesFound > 1) { + warning(MORE_THAN_ONE_SYMBOL_DUMP_FILE_ERROR); + } else if (symbolDumpFilesFound == 1) { + if (strcmp(symbolDumpFileName, "-") == 0) { + symbolDumpFileOutput = stdout; + } else if ((symbolDumpFileOutput = fopen(symbolDumpFileName, + "w"))==NULL) { + fatalSystemError(CANT_OPEN_SYMBOL_DUMP_FILE_ERROR, symbolDumpFileName); + } + } + + expressionReferenceList[0] = expressionReferenceList[1] = NULL; + numberOfReferencesInList[0] = numberOfReferencesInList[1] = 0; + externalFunctionList = endOfExternalFunctionList = NULL; + externalFunctionCount = 0; + + currentLocationCounter.kindOfValue = RELOCATABLE_VALUE; + currentLocationCounter.value = 0; + targetOffset = 0; + currentCodeMode = RELOCATABLE_BUFFER; + relocatableHighWaterMark = -1; + codeBreakList = NULL; + lastCodeBreak = NULL; + reservationList = NULL; + + for (i=0; icontext->value =newValue(BUILT_IN_FUNCTION_VALUE, + i, EXPRESSION_OPND); + if (builtInFunctionTable[i].isSpecialFunction) + newFunction->context->attributes |= + SPECIAL_FUNCTION_ATT; + } +} + + void +installPredefinedSymbols() +{ + int i; + symbolTableEntryType *newSymbol; + + symbolTableEntryType *lookupOrEnterSymbol(); + valueType *newValue(); + + for (i=0; predefinedSymbolTable[i].symbolName!=NULL; i++) { + newSymbol = lookupOrEnterSymbol(predefinedSymbolTable[i]. + symbolName, DEFINE_SYMBOL); + newSymbol->context->value = newValue(ABSOLUTE_VALUE, + predefinedSymbolTable[i].symbolValue, + EXPRESSION_OPND); + newSymbol->context->attributes |= DEFINED_VARIABLE_ATT; + } +} + + void +installCommandLineDefineSymbols() +{ + int i; + symbolTableEntryType *newSymbol; + + symbolTableEntryType *lookupOrEnterSymbol(); + valueType *newValue(); + + while (commandLineDefines != NULL) { + newSymbol = lookupOrEnterSymbol(commandLineDefines->name, + DEFINE_SYMBOL); + newSymbol->context->value = newValue(ABSOLUTE_VALUE, + commandLineDefines->value, EXPRESSION_OPND); + newSymbol->context->attributes |= DEFINED_VARIABLE_ATT; + commandLineDefines = commandLineDefines->nextDefine; + } +} + + void +createHashTables() +{ + opcodeTableEntryType *newOpcodeEntry; + keywordTableEntryType *newKeywordEntry; + conditionTableEntryType *newConditionEntry; + + newOpcodeEntry = theOpcodes; + while (newOpcodeEntry->mnemonic != NULL) + hashStringEnter(newOpcodeEntry++, opcodeTable); + + newKeywordEntry = theKeywords; + while (newKeywordEntry->string != NULL) + hashStringEnter(newKeywordEntry++, keywordTable); + + newConditionEntry = theConditions; + while (newConditionEntry->string != NULL) + hashStringEnter(newConditionEntry++, conditionTable); +} + + void +queueInputFile(name) + char *name; +{ + fileNameListType *newFileName; + + newFileName = typeAlloc(fileNameListType); + newFileName->name = name; + newFileName->fildes = NULL; + newFileName->openFlag = FALSE; + newFileName->nextFileName = NULL; + newFileName->lineNumber = 1; + if (inputFileStack == NULL) { + inputFileStack = bottomOfInputFileStack = newFileName; + } else { + bottomOfInputFileStack->nextFileName = newFileName; + bottomOfInputFileStack = newFileName; + } +} + + void +openFirstInputFile() +{ + if (inputFileStack == NULL) { + inputFileStack = typeAlloc(fileNameListType); + inputFileStack->name = ""; + inputFileStack->fildes = stdin; + inputFileStack->openFlag = TRUE; + inputFileStack->lineNumber = 1; + inputFileStack->nextFileName = NULL; + } else { + if ((inputFileStack->fildes = fopen(inputFileStack->name, + "r")) == NULL) { + fatalSystemError(UNABLE_TO_OPEN_INPUT_FILE_ERROR, + inputFileStack->name); + } else { + inputFileStack->openFlag = TRUE; + } + } + input = inputFileStack->fildes; + currentLineNumber = inputFileStack->lineNumber; + currentFileName = inputFileStack->name; + currentOperandNumber = 0; +} + + bool +isDotMName(fileName) + stringType *fileName; +{ + int length; + + length = strlen(fileName); + return(length >= 2 && fileName[length - 1] == 'm' && + fileName[length - 2] == '.'); +} + + bool +parseCommandLineDefine(arg, name, value) + char *arg; + char **name; + int *value; +{ + char *ptr; + char c; + int base; + int start; + + ptr = arg; + while ((c = *ptr++) && (ptr-arg)name = name; + newCommandLineDefine->value = value; + newCommandLineDefine->nextDefine = commandLineDefines; + commandLineDefines = newCommandLineDefine; + } +} diff --git a/initialize.o b/initialize.o new file mode 100644 index 0000000..6160d5a Binary files /dev/null and b/initialize.o differ diff --git a/lexer.c b/lexer.c new file mode 100644 index 0000000..fa03963 --- /dev/null +++ b/lexer.c @@ -0,0 +1,542 @@ +/* + lexer.c -- Lexical scanner for the Macross assembler + + Chip Morningstar -- Lucasfilm Ltd. + + 3-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" +#include "lexerTables.h" + +extern int yylval; +extern int yydebug; + +static char lineBuffer[LINE_BUFFER_SIZE] = { '\0' }; +static int lineBufferPtr = 0; + +#define getNextChar() (lineBuffer[lineBufferPtr] ? \ + lineBuffer[lineBufferPtr++] : \ + readAnotherLine()) +/*int getNextChar() {int c;c=xgetNextChar();printf("read '%c'\n",c);return(c);}*/ + +#define oopsThatWasTheWrongChar(c) { if(lineBufferPtr) \ + lineBuffer[--lineBufferPtr] = c; } +/*oopsThatWasTheWrongChar(c)char c;{printf("ungetting '%c'\n", c);xoopsThatWasTheWrongChar(c);}*/ + +#define isAlphabetic(c) (alphabeticCharacterTable[c]) +#define isNumeric(c) (numericCharacterTable[c]) +#define isAlphaNumeric(c) (alphaNumericCharacterTable[c]) + + int +yylex() +{ + int result; + + result = lexer(); + if (yydebug) { + printf("lexer returns "); + printToken(result); + printf(", value=%d (0x%x)\n", yylval, yylval); + } + return(result); +} + + int +lexer() +{ + char c; + + char skipWhitespaceAndComments(); + + if ((c = skipWhitespaceAndComments()) == EOF) + return(lexLiteral(c)); + else + return((*lexDispatchTable[c])(c)); +} + + void +initializeLexDispatchTable() +{ + int c; + int lexIdentifier(); + int lexNumber(); + int lexLiteral(); + int lexCharacterConstant(); + int lexStringConstant(); + int lexOperator(); + + for (c = 0; c < LEX_DISPATCH_TABLE_SIZE; c++) { + if (isAlphabetic(c) || c=='$') + lexDispatchTable[c] = lexIdentifier; + else if (isNumeric(c)) + lexDispatchTable[c] = lexNumber; + else if (isMacrossLiteralCharacter(c)) + lexDispatchTable[c] = lexLiteral; + else if (c == '\'') + lexDispatchTable[c] = lexCharacterConstant; + else if (c == '"') + lexDispatchTable[c] = lexStringConstant; + else + lexDispatchTable[c] = lexOperator; + } +} + + bool +isMacrossLiteralCharacter(c) + char c; +{ + return(c==':' || c==',' || c=='@' || c=='#' || + c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || + c=='\n' || c==EOF); +} + + void +snarfAlphanumericString(c, buffer) + char c; + char *buffer; +{ + char *bufferPtr; + + bufferPtr = buffer; + do { + if (bufferPtr < &buffer[MAX_NAME_SIZE]) + *bufferPtr++ = c; + c = getNextChar(); + } while (c!=EOF && isAlphaNumeric(c)); + *bufferPtr = '\0'; + oopsThatWasTheWrongChar(c); +} + +char nameBuffer[MAX_NAME_SIZE+1]; + + int +lexIdentifier(c) + char c; +{ + char *saveString(); + int hashValue; + + snarfAlphanumericString(c, nameBuffer); + hashValue = hashString(nameBuffer); + if (yylval = lookupOpcode(nameBuffer, hashValue)) + return(Opcode); + else if (yylval = lookupKeyword(nameBuffer, hashValue)) + return(yylval); + else if ((yylval = lookupConditionCode(nameBuffer, hashValue)) != + (int)NOT_FOUND_COND) + return(ConditionCode); + else if (yylval = lookupMacroName(nameBuffer, hashValue)) + return(MacroName); + else { + yylval = (int) saveString(nameBuffer); + return(Identifier); + } +} + +char numberBuffer[MAX_NAME_SIZE+1]; + + int +lexNumber(c) + char c; +{ + int base; + int start; + + snarfAlphanumericString(c, numberBuffer); + if (numberBuffer[0] != '0') { + base = 10; + start = 0; + } else if (numberBuffer[1]=='b' || numberBuffer[1]=='B') { + base = 2; + start = 2; + } else if (numberBuffer[1]=='q' || numberBuffer[1]=='Q') { + base = 4; + start = 2; + } else if (numberBuffer[1]=='x' || numberBuffer[1]=='X') { + base = 16; + start = 2; + } else { + base = 8; + start = 1; + } + yylval = fancyAtoI(&numberBuffer[start], base); + return(Number); +} + + int +fancyAtoI(buffer, base) + char *buffer; + int base; +{ + int value; + int digit; + char c; + + value = 0; + while (*buffer != '\0') { + if ((digit = digitValue(c = *buffer++)) >= base) { + error(DIGIT_OUT_OF_RADIX_ERROR, c, base); + return(0); + } + value = value*base + digit; + } + return(value); +} + + int +digitValue(c) + char c; +{ + if (isNumeric(c)) + return(c - '0'); + else + return(toLowerCase(c) - 'a' + 10); +} + + int +lexLiteral(c) + char c; +{ + static bool passedEnd = FALSE; + + yylval = 0; + if (c == '\n') { + return(EOL); + } else if (c == EOF) { + if (passedEnd) { + return(0); + } else { + passedEnd = TRUE; + return(ENDFILE); + } + } else { + return(c); + } +} + + int +lexCharacterConstant() +{ + char c; + + yylval = getStringCharacter(input); + if (getNextChar() != '\'') { + error(UNCLOSED_CHARACTER_CONSTANT_ERROR); + while ((c = getNextChar())!='\'' && c!='\n' && c!=EOF) + ; + } + return(Number); +} + +bool escaped; /* true if last string character read was an escape + code. */ + int +getStringCharacter(input) + FILE *input; +{ + char c; + char *numberPtr; + int result; + char controlCharacter(); + + escaped = FALSE; + c = getNextChar(); + if (c == '\\') { + escaped = TRUE; + c = getNextChar(); + if (c == '^') + return(controlCharacter(getNextChar())); + else if ('0'<=c && c<='7') { + numberPtr = numberBuffer; + while ('0'<=c && c<='7') { + *numberPtr++ = c; + c = getNextChar(); + } + *numberPtr = '\0'; + oopsThatWasTheWrongChar(c); + result = fancyAtoI(numberBuffer, 8); + if (result > 0377) + error(OCTAL_CHARACTER_TOO_BIG_ERROR, result); + return (result % 0377); + } else + return(escapeCodes[c]); + } else + return(c); +} + +char stringBuffer[MAX_NAME_SIZE + 1]; + + int +lexStringConstant() +{ + char *stringPtr; + char c; + + stringPtr = stringBuffer; + while (((c = getStringCharacter(input))!='"' && c!='\n' && c!=EOF) + || escaped) + *stringPtr++ = c; + *stringPtr = '\0'; + if (c=='\n' || c==EOF) + error(UNCLOSED_STRING_CONSTANT_ERROR); + yylval = (int)saveString(stringBuffer); + return(TextString); +} + + int +lexOperator(firstC) + char firstC; +{ + char secondC; + char thirdC; + int op; + int oper; + + secondC = getNextChar(); + for (op=0; operatorTable[op].first!='\0'; op++) { + if (operatorTable[op].first==firstC && + operatorTable[op].second==secondC) + break; + else if (operatorTable[op].first==firstC && + operatorTable[op].second=='\0') { + oopsThatWasTheWrongChar(secondC); + break; + } + } + if (operatorTable[op].first == '\0') { + error(UNRECOGNIZED_SOMETHING_OR_OTHER_ERROR, firstC); + return(yylex()); + } + /* kludge to deal with the two three-character operators: */ + if ((oper=operatorTable[op].token)==RIGHT_SHIFT || oper==LEFT_SHIFT) { + thirdC = getNextChar(); + if (thirdC == '=') { + yylval = (int)((oper==RIGHT_SHIFT) ? + RIGHT_SHIFT_ASSIGN : LEFT_SHIFT_ASSIGN); + return(ASSIGN); + } else + oopsThatWasTheWrongChar(thirdC); + } + yylval = (int)operatorTable[op].value; + return(operatorTable[op].token); +} + + char +controlCharacter(c) + char c; +{ +#define CONTROL_CHARACTER_MASK (~0100) + + return(c & CONTROL_CHARACTER_MASK); +} + + char +skipWhitespaceAndComments() +{ + char c; + + while ((c=getNextChar())==' ' || c=='\t' || c=='/') { + if (c == '/') { + if ((c = getNextChar()) == '*') { + while (TRUE) { + while ((c = getNextChar()) != '*') { + if (c == EOF) { + error(UNCLOSED_COMMENT_ERROR); + return(c); + } + } + if ((c = getNextChar()) == '/') { + break; + } else if (c == '*') { + oopsThatWasTheWrongChar(c); + } + } + } else { + oopsThatWasTheWrongChar(c); + return('/'); + } + } + } + if (c == ';') { + while ((c = getNextChar()) != '\n') { + if (c == EOF) { + error(UNCLOSED_LINE_COMMENT_ERROR); + return(c); + } + } + } + return(c); +} + + int +popInputFileStack() +{ + fileNameListType *oldFile; + + if (inputFileStack->nextFileName == NULL) + return(EOF); + oldFile = inputFileStack; + inputFileStack = inputFileStack->nextFileName; + qfree(oldFile); + currentLineNumber = inputFileStack->lineNumber; + currentFileName = inputFileStack->name; + cumulativeLineNumber--; + fclose(input); + if (!inputFileStack->openFlag) { + if ((inputFileStack->fildes = fopen(inputFileStack->name, + "r")) == NULL) { + fatalSystemError(UNABLE_TO_OPEN_INPUT_FILE_ERROR, + inputFileStack->name); + } else { + inputFileStack->openFlag = TRUE; + } + } + input = inputFileStack->fildes; + if (includeNestingDepth > 0) { + includeNestingDepth--; + currentLineNumber--; + } + return(getNextChar()); +} + + void +pushInputFileStack(fileName) + stringType *fileName; +{ + fileNameListType *newFileName; + + inputFileStack->lineNumber = currentLineNumber; + newFileName = typeAlloc(fileNameListType); + if ((input = newFileName->fildes = fopen(fileName, "r")) == NULL) { + fatalSystemError(UNABLE_TO_OPEN_INCLUDE_FILE_ERROR, fileName); + } + newFileName->openFlag = TRUE; + newFileName->nextFileName = inputFileStack; + inputFileStack = newFileName; + currentFileName = newFileName->name = fileName; + currentLineNumber = newFileName->lineNumber = 1; + includeNestingDepth++; + if (statementEvaluationDepth == 1) + oopsThatWasTheWrongChar('\n'); /* hack for line #'s */ +} + + void +resynchronizeInput() +{ + char c; + while ((c = getNextChar())!='\n' && c!=EOF) + ; + oopsThatWasTheWrongChar(c); +} + + bool longLineFlag = FALSE; +static bool previousLongLineFlag = FALSE; + + void +saveLineForListing(line) + stringType *line; +{ + if (!previousLongLineFlag) { + putw(currentLocationCounter.value, saveFileForPass2); + putw(includeNestingDepth, saveFileForPass2); + } + previousLongLineFlag = longLineFlag; + fputs(line, saveFileForPass2); +} + + void +saveEOLForListing() +{ + putw(-1, saveFileForPass2); + putw(includeNestingDepth, saveFileForPass2); + fputs("\n", saveFileForPass2); +} + + void +saveIndexForListing(kindOfStatement, cumulativeLineNumber) + statementKindType kindOfStatement; + int cumulativeLineNumber; +{ + if (!amExpanding() || !notListable(kindOfStatement)) { + putw(kindOfStatement, indexFileForPass2); + putw(currentLocationCounter.value, indexFileForPass2); + if (amExpanding()) + putw(-cumulativeLineNumber, indexFileForPass2); + else + putw( cumulativeLineNumber, indexFileForPass2); + } +} + + void +saveEndMifForListing(cumulativeLineNumber) + int cumulativeLineNumber; +{ + putw(MIF_STATEMENT, indexFileForPass2); + putw(-1, indexFileForPass2); + if (amExpanding()) + putw(-cumulativeLineNumber, indexFileForPass2); + else + putw(cumulativeLineNumber, indexFileForPass2); +} + + void +saveListingOff() +{ + saveIndexForListing(-1, cumulativeLineNumber); +} + + void +saveListingOn() +{ + if (currentCodeMode == ABSOLUTE_BUFFER) + saveIndexForListing(-1, cumulativeLineNumber); + else + saveIndexForListing(-2, cumulativeLineNumber); +} + + char * +myfgets(buffer, length, stream) + char *buffer; + int length; + FILE *stream; +{ + char *result; + char c; + + result = buffer; + while (length-- > 1 && (c = getc(stream)) != EOF && c != '\n') + *buffer++ = c; + if (c == EOF) { + *result = '\0'; + return(NULL); + } + if (length > 0) + *buffer++ = c; + if (length == 0 && c != '\n') + longLineFlag = TRUE; + else + longLineFlag = FALSE; + *buffer = '\0'; + return(result); +} + + int +readAnotherLine() +{ + int result; + + if (myfgets(lineBuffer, LINE_BUFFER_SIZE, input)) { + if (amListing()) + saveLineForListing(lineBuffer); + lineBufferPtr = 1; + result = lineBuffer[0]; + } else { + result = popInputFileStack(); + } + currentLineNumber++; + cumulativeLineNumber++; + return(result); +} diff --git a/lexer.o b/lexer.o new file mode 100644 index 0000000..67dbdfd Binary files /dev/null and b/lexer.o differ diff --git a/lexerTables.h b/lexerTables.h new file mode 100644 index 0000000..df12c43 --- /dev/null +++ b/lexerTables.h @@ -0,0 +1,85 @@ +/* + lexerTables.h -- Tables describing stuff the lexer needs to know. + + Chip Morningstar -- Lucasfilm Ltd. + + 3-November-1984 +*/ + +struct { + char first; + char second; + int token; + assignmentKindType value; + } operatorTable[] = { + '!', '=', NOT_EQUAL_TO, NO_ASSIGN, + '!', '\0', LOGICAL_NOT, NO_ASSIGN, + '%', '=', ASSIGN, MOD_ASSIGN, + '%', '\0', MOD, NO_ASSIGN, + '&', '&', LOGICAL_AND, NO_ASSIGN, + '&', '=', ASSIGN, AND_ASSIGN, + '&', '\0', BITWISE_AND, NO_ASSIGN, + '*', '=', ASSIGN, MUL_ASSIGN, + '*', '\0', MUL, NO_ASSIGN, + '+', '+', INCREMENT, NO_ASSIGN, + '+', '=', ASSIGN, ADD_ASSIGN, + '+', '\0', ADD, NO_ASSIGN, + '-', '-', DECREMENT, NO_ASSIGN, + '-', '=', ASSIGN, SUB_ASSIGN, + '-', '\0', SUB, NO_ASSIGN, + '.', '\0', SELECT, NO_ASSIGN, + '/', '=', ASSIGN, DIV_ASSIGN, + '/', '\0', DIV, NO_ASSIGN, + '<', '<', LEFT_SHIFT, NO_ASSIGN, + '<', '=', LESS_THAN_OR_EQUAL_TO, NO_ASSIGN, + '<', '\0', LESS_THAN, NO_ASSIGN, + '=', '=', EQUAL_TO, NO_ASSIGN, + '=', '\0', ASSIGN, ASSIGN_ASSIGN, + '>', '=', GREATER_THAN_OR_EQUAL_TO, NO_ASSIGN, + '>', '>', RIGHT_SHIFT, NO_ASSIGN, + '>', '\0', GREATER_THAN, NO_ASSIGN, + '^', '=', ASSIGN, XOR_ASSIGN, + '^', '^', LOGICAL_XOR, NO_ASSIGN, + '^', '\0', BITWISE_XOR, NO_ASSIGN, + '|', '=', ASSIGN, OR_ASSIGN, + '|', '|', LOGICAL_OR, NO_ASSIGN, + '|', '\0', BITWISE_OR, NO_ASSIGN, + '~', '\0', BITWISE_NOT, NO_ASSIGN, + '?', '\0', HI_BYTE, NO_ASSIGN, + '\0', '\0', 0, NO_ASSIGN, + }; + +char escapeCodes[256] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + ' ', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', '\b', 'c', 'd', '\33', '\f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', '\n', 'o', + 'p', 'q', '\r', 's', '\t', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', '\177', + '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', + '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', + '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', + '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', +}; diff --git a/listing.c b/listing.c new file mode 100644 index 0000000..667542c --- /dev/null +++ b/listing.c @@ -0,0 +1,649 @@ +/* + listing.c -- Routines to generate a Macross assembly listing. + + Chip Morningstar -- Lucasfilm Ltd. + + 10-February-1985 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +static char lineBuffer1[LINE_BUFFER_SIZE]; +static char lineBuffer2[LINE_BUFFER_SIZE]; +static int cumulativeLineNumber = 0; +static char macroLineBuffer[LINE_BUFFER_SIZE]; +static char nextMacroLineBuffer[LINE_BUFFER_SIZE]; +static int macroAddress; +static int nextMacroAddress; +static int macroDepth; +static int nextMacroDepth; + + void +outputListing() +{ + void generateListing(); + + rewind(saveFileForPass2); + rewind(indexFileForPass2); + rewind(macroFileForPass2); + generateListing(); +} + + void +terminateListingFiles() +{ + saveLineForListing("\n"); + saveIndexForListing(NULL_STATEMENT, cumulativeLineNumber); + saveLineForListing("\n"); + saveIndexForListing(NULL_STATEMENT, cumulativeLineNumber); +} + +#define advanceSourceFile() \ + if (nextSourceAddress == -1) {\ + readSourceFileLine(&sourceAddress, &sourceDepth,\ + sourceText = lineBuffer1, saveFileForPass2);\ + readSourceFileLine(&nextSourceAddress,\ + &nextSourceDepth, nextSourceText =\ + lineBuffer2, saveFileForPass2);\ + sourceLineNumber++;\ + } else {\ + sourceAddress = nextSourceAddress;\ + sourceDepth = nextSourceDepth;\ + tempText = sourceText;\ + sourceText = nextSourceText;\ + nextSourceText = tempText;\ + if (tempText == NULL)\ + nextSourceText = (sourceText==lineBuffer1) ?\ + lineBuffer2 : lineBuffer1;\ + readSourceFileLine(&nextSourceAddress,\ + &nextSourceDepth, nextSourceText,\ + saveFileForPass2);\ + sourceLineNumber++;\ + } + +#define advanceIndexFile() {\ + indexAddress = nextIndexAddress;\ + indexLineNumber = nextIndexLineNumber;\ + indexKind = nextIndexKind;\ + readIndexFileLine(&nextIndexKind, &nextIndexAddress,\ + &nextIndexLineNumber);\ + } + +/* This is the most horrible piece of code I have ever written in my entire + life -- cbm */ + void +generateListing() +{ + int sourceAddress; + int sourceDepth; + char *sourceText = lineBuffer1; + int nextSourceAddress; + int nextSourceDepth; + char *nextSourceText = lineBuffer2; + int sourceLineNumber; + + int indexAddress; + int indexLineNumber; + statementKindType indexKind; + int nextIndexAddress; + int nextIndexLineNumber; + statementKindType nextIndexKind; + + bool firstLine; + bool alreadyListingMacroExpansion; + bool finishingListingMacroExpansion; + bool nullMacroLine; + int callLineNumber; + int targetLineNumber; + bool mifEndFlag; + int numberOfBytesToList; + int numberOfBytesListed; + char *tempText; + + void readIndexFileLine(); + void readSourceFileLine(); + + sourceLineNumber = 1; + alreadyListingMacroExpansion = FALSE; + readSourceFileLine(&sourceAddress, &sourceDepth, sourceText, + saveFileForPass2); + readSourceFileLine(&nextSourceAddress, &nextSourceDepth, + nextSourceText, saveFileForPass2); + if (expandMacros) + readSourceFileLine(&nextMacroAddress, &nextMacroDepth, + nextMacroLineBuffer, macroFileForPass2); + readIndexFileLine(&indexKind, &indexAddress, &indexLineNumber); + readIndexFileLine(&nextIndexKind, &nextIndexAddress, + &nextIndexLineNumber); + currentCodeMode = RELOCATABLE_BUFFER; + if (indexKind == ORG_STATEMENT || indexKind == ALIGN_STATEMENT || + indexKind == REL_STATEMENT) { + if (indexKind == ORG_STATEMENT) { + currentCodeMode = ABSOLUTE_BUFFER; + } + advanceIndexFile(); + } + while (!feof(saveFileForPass2) && !feof(indexFileForPass2)) { + mifEndFlag = FALSE; + if ((int)indexKind == -1) { + advanceIndexFile(); + if ((int)indexKind == -1) + currentCodeMode = ABSOLUTE_BUFFER; + else + currentCodeMode = RELOCATABLE_BUFFER; + advanceIndexFile(); + sourceLineNumber = indexLineNumber; + if (nextIndexKind == ORG_STATEMENT || nextIndexKind == + ALIGN_STATEMENT || nextIndexKind == + REL_STATEMENT) { + if (nextIndexKind == ORG_STATEMENT) { + currentCodeMode = ABSOLUTE_BUFFER; + } else if (nextIndexKind == REL_STATEMENT) { + currentCodeMode = RELOCATABLE_BUFFER; + } + advanceIndexFile(); + } + } + if (indexKind == MACRO_STATEMENT || indexKind == + FUNCTION_STATEMENT || indexKind == + STRUCT_STATEMENT) { + while (sourceLineNumber < indexLineNumber) { + printListingLine(0, indexAddress, sourceText, + indexKind); + advanceSourceFile(); + } + } else if (!alreadyListingMacroExpansion && isBlockOpener( + indexKind)) { + while (sourceLineNumber < nextIndexLineNumber) { + printListingLine(0, indexAddress, sourceText, + indexKind); + advanceSourceFile(); + } + readIndexFileLine(&nextIndexKind, &nextIndexAddress, + &nextIndexLineNumber); + } + while ((indexLineNumber == nextIndexLineNumber && + !alreadyListingMacroExpansion && + (int)nextIndexKind != -1 && indexKind != + ORG_STATEMENT) || (indexKind == + NULL_STATEMENT && nextSourceAddress == -1)) { + while (nextSourceAddress == -1) { + printListingLine(0, indexAddress, sourceText, + indexKind); + advanceSourceFile(); + } + readIndexFileLine(&nextIndexKind, &nextIndexAddress, + &nextIndexLineNumber); + } + if (nextIndexLineNumber >= 0) { + targetLineNumber = alreadyListingMacroExpansion ? + callLineNumber : sourceLineNumber; + while (nextIndexLineNumber < targetLineNumber && + !isBlockOpener(indexKind)) { + readIndexFileLine(&nextIndexKind, + &nextIndexAddress, + &nextIndexLineNumber); + } + } + while (nextIndexAddress == -1 && !feof(indexFileForPass2)) { + readIndexFileLine(&nextIndexKind, &nextIndexAddress, + &nextIndexLineNumber); + mifEndFlag = TRUE; + } + numberOfBytesToList = nextIndexAddress - indexAddress; + firstLine = TRUE; + nullMacroLine = FALSE; + while (numberOfBytesToList > 0 || nextSourceAddress == -1 || + firstLine) { + firstLine = FALSE; + if (alreadyListingMacroExpansion) { + if (nullMacroLine) { + numberOfBytesListed = printListingLine( + numberOfBytesToList, indexAddress, + NULL, indexKind); + nullMacroLine = FALSE; + } else { + numberOfBytesListed = printMacroLine( + numberOfBytesToList, indexAddress, + indexKind); + } + } else if (!feof(indexFileForPass2)) { + numberOfBytesListed = printListingLine( + numberOfBytesToList, indexAddress, + sourceText, indexKind); + } + numberOfBytesToList -= numberOfBytesListed; + indexAddress += numberOfBytesListed; + if (nextSourceAddress == -1 || (sourceLineNumber < + indexLineNumber && indexKind == + INSTRUCTION_STATEMENT && + !alreadyListingMacroExpansion)) { + advanceSourceFile(); + firstLine = TRUE; + } else if (!alreadyListingMacroExpansion && + nextIndexLineNumber >= 0) { + sourceText = NULL; + } else if (alreadyListingMacroExpansion && + numberOfBytesToList > 0) { + nullMacroLine = TRUE; + } + } + while (mifEndFlag && sourceLineNumber+10; spaces--) { + putc(' ', listFileOutput); + column++; + } + } else { + putc(*text, listFileOutput); + column++; + } + text++; + } +} + + void +printNTimes(aChar, times) + char aChar; + int times; +{ + void moreText(); + + while (times-- > 0) + moreText("%c", aChar); +} + + void +tabIndent() +{ + printNTimes('\t', tabCount); +} + +static char expressionString[LINE_BUFFER_SIZE] = { '\0' }; +static char *expressionStringPtr = expressionString; +static char expansionString[LINE_BUFFER_SIZE] = { '\0' }; +static char *expansionStringPtr = expansionString; +static char labelString[LINE_BUFFER_SIZE] = { '\0' }; +static char *labelStringPtr = labelString; + + bool +labeledLine() +{ + return(labelStringPtr != labelString); +} + + void +addText(buffer, bufferPtr, format, arg1, arg2, arg3) + char *buffer; + char **bufferPtr; + char *format; + int arg1; + int arg2; + int arg3; +{ + sprintf(*bufferPtr, format, arg1, arg2, arg3); + *bufferPtr = buffer + strlen(buffer); +} + + void +moreTextOptional(buffer, bufferPtr, format, arg1, arg2, arg3) + char *buffer; + char **bufferPtr; + char *format; + int arg1; + int arg2; + int arg3; +{ + if (buffer == NULL) + addText(expansionString, &expansionStringPtr, format, arg1, + arg2, arg3); + else + addText(buffer, bufferPtr, format, arg1, arg2, arg3); +} + + void +moreText(format, arg1, arg2, arg3) + char *format; + int arg1; + int arg2; + int arg3; +{ + addText(expansionString, &expansionStringPtr, format, arg1,arg2,arg3); +} + + void +moreLabel(format, arg1, arg2, arg3) + char *format; + int arg1; + int arg2; + int arg3; +{ + sprintf(labelStringPtr, format, arg1, arg2, arg3); + labelStringPtr = labelString + strlen(labelString); +} + +static addressType savedCurrentLocationCounterValue; +static int savedIncludeNestingDepth; + + void +startLine() +{ + printNTimes('+', macroCallDepth); + savedCurrentLocationCounterValue = currentLocationCounter.value; + savedIncludeNestingDepth = includeNestingDepth; +} + + void +endLine() +{ + if (amListing()) { + putw(savedCurrentLocationCounterValue, macroFileForPass2); + putw(savedIncludeNestingDepth, macroFileForPass2); + fprintf(macroFileForPass2, "%s\n", expansionString); + } + expansionStringPtr = expansionString; + *expansionStringPtr = '\0'; +} + + void +flushExpressionString() +{ + expressionStringPtr = expressionString; + *expressionStringPtr = '\0'; +} + + void +expandExpression(toBuffer, toBufferPtr) + char *toBuffer; + char **toBufferPtr; +{ + if (toBuffer == NULL) + moreText("%s", expressionString); + else + addText(toBuffer, toBufferPtr, "%s", expressionString); + flushExpressionString(); +} + + void +expandNum(buffer, bufferPtr, n) + char *buffer; + char **bufferPtr; + int n; +{ + moreTextOptional(buffer, bufferPtr, "%d", n); +} + + void +flushOperand(n) + int n; +{ + moreText("%s", operandBuffer[n]); + operandBuffer[n][0] = '\0'; +} + + void +expandOperands(op) + int op; +{ + int i; + + if (op > 0) { + flushOperand(0); + for (i=1; icode); + else + return(NOT_FOUND_COND); +} + + int +lookupKeyword(s, hashValue) + char *s; + int hashValue; +{ + keywordTableEntryType *result; + + genericTableEntryType *prehashedStringLookup(); + + result = (keywordTableEntryType *) prehashedStringLookup(s, + keywordTable, hashValue); + if (result != NULL) + return(result->token); + else + return(0); +} + + macroTableEntryType * +lookupMacroName(s, hashValue) + char *s; + int hashValue; +{ + genericTableEntryType *prehashedStringLookup(); + + return((macroTableEntryType *) prehashedStringLookup(s, macroTable, + hashValue)); +} + + opcodeTableEntryType * +lookupOpcode(s, hashValue) + char *s; + int hashValue; +{ + genericTableEntryType *prehashedStringLookup(); + + return((opcodeTableEntryType *) prehashedStringLookup(s, + opcodeTable, hashValue)); +} + +/* lookupOrEnterSymbol -- if there is an entry in the symbol table for the + given symbol, return that entry, otherwise create a new entry for it of + the given kind and return *that* */ + + symbolTableEntryType * +lookupOrEnterSymbol(s, kind) + stringType *s; + symbolUsageKindType kind; +{ + symbolTableEntryType *result; + genericTableEntryType *hashStringLookup(); + genericTableEntryType *hashStringEnter(); + symbolTableEntryType *buildSymbolTableEntry(); + + if (result = (symbolTableEntryType *)hashStringLookup(s,symbolTable)){ +/* result->referenceCount++;*/ + return(result); + } else + return((symbolTableEntryType *) + hashStringEnter(buildSymbolTableEntry(s, kind), + symbolTable)); +} + + void +pushSymbol(symbol) + symbolTableEntryType *symbol; +{ + symbolInContextType *newContext; + + newContext = typeAlloc(symbolInContextType); + newContext->pushedContexts = symbol->context; + symbol->context = newContext; +} + + void +popSymbol(symbol) + symbolTableEntryType *symbol; +{ + symbolInContextType *deadContext; + + deadContext = symbol->context; + if (deadContext == NULL) + botch("symbol pop underflow\n"); + else { + symbol->context = deadContext->pushedContexts; + if (freeFlag) { + if (deadContext->value != NULL) + freeValue(deadContext->value); + free(deadContext); + } + } +} + + macroTableEntryType * +createMacro(macroName) + stringType *macroName; +{ + macroTableEntryType *result; + symbolTableEntryType *testSymbol; + + genericTableEntryType *hashStringLookup(); + genericTableEntryType *hashStringEnter(); + macroTableEntryType *buildMacroTableEntry(); + symbolTableEntryType *lookupOrEnterSymbol(); + + testSymbol = lookupOrEnterSymbol(macroName, MACRO_SYMBOL); + if (testSymbol->context->usage != MACRO_SYMBOL) { + error(SYMBOL_ALREADY_THERE_ERROR, symbName(testSymbol)); + return(NULL); + } else if (hashStringLookup(macroName, macroTable) != NULL) { + error(SYMBOL_ALREADY_THERE_ERROR, symbName(testSymbol)); + return(NULL); + } else { + result = (macroTableEntryType *) + hashStringEnter(buildMacroTableEntry(macroName), + macroTable); + result->body = NULL; + return(result); + } +} + + +/* + Generic table lookup utility routines + */ + + genericTableEntryType * +prehashedStringLookup(s, table, hashValue) + char *s; + genericTableEntryType *table[]; + int hashValue; +{ + genericTableEntryType *result; + int test; + + result = table[hashValue]; + while (result != NULL) { + if ((test = strcmplc(s, result->string)) == 0) + break; + else if (test > 0) { + result = NULL; + break; + } else { + result = result->next; + } + } + return(result); +} + + genericTableEntryType * +hashStringLookup(s, table) + char *s; + genericTableEntryType *table[]; +{ + return(prehashedStringLookup(s, table, hashString(s))); +} + + genericTableEntryType * +hashStringEnter(entry, table) + genericTableEntryType *entry; + genericTableEntryType *table[]; +{ + genericTableEntryType *result; + genericTableEntryType *oldResult; + int test; + int hashValue; + + hashValue = hashString(entry->string); + result = table[hashValue]; + if (result == NULL) { + table[hashValue] = entry; + entry->next = NULL; + return(entry); + } + oldResult = NULL; + while (result != NULL) { + if ((test = strcmplc(entry->string, result->string)) == 0) { + botch("symbol table entry %s already there\n", + entry->string); + } else if (test > 0) { + entry->next = result; + if (oldResult == NULL) + table[hashValue] = entry; + else + oldResult->next = entry; + return(entry); + } else { + oldResult = result; + result = result->next; + } + } + if (oldResult == NULL) + table[hashValue] = entry; + else + oldResult->next = entry; + entry->next = NULL; + return(entry); +} + + int +hashString(s) + char *s; +{ + unsigned result; + + result = 0; + while (*s != '\0') + result = (result << 1) + toLowerCase(*s++); + return(result & HASH_TABLE_MASK); +} + + bool +strcmplc(s1, s2) /* string compare in lower case */ + char *s1; /* heavily optimized version */ + char *s2; +{ + char c1; + int result; + + do { + c1 = toLowerCase(*s1++); + + /* if result != 0, they differ */ + if (result = c1 - toLowerCase(*s2++)) { + return(result); /* c1c2==pos */ + } else if (!c1) { /* if they're null, we're done */ + return(0); + } + } while (TRUE); +} + + bool +strcmplct(s1, s2) /* For tables: s2 is already lower case */ + char *s1; /* heavily optimized version. */ + char *s2; +{ + char c1; + int result; + + while (TRUE) { + c1 = toLowerCase(*s1++); + if (result = c1 - (*s2++)) { /* if result != 0, they differ */ + return(result); /* c1c2==pos */ + } else if (!c1) { /* if they're null, we're done */ + return(0); + } + } +} + + void +purgeSymbol(symbol) + symbolTableEntryType *symbol; +{ + symbolInContextType *context; + + symbolInContextType *getWorkingContext(); + + if ((context = getWorkingContext(symbol)) != NULL) + context->usage = DEAD_SYMBOL; +} + + void +reincarnateSymbol(context, newUsage) + symbolInContextType *context; + symbolUsageKindType newUsage; +{ + context->attributes = 0; + dupValue(context->value, UndefinedValue); + context->usage = newUsage; +} + + +/* + Routines to handle assembly-time binding of symbols to contexts. + */ + + void +pushBinding(symbol, newBinding, newUsage) + symbolTableEntryType *symbol; + valueType *newBinding; + symbolUsageKindType newUsage; +{ + valueType *newValue(); + + pushSymbol(symbol); + if (newBinding == NULL) + newBinding = newValue(FAIL, 0, EXPRESSION_OPND); + symbol->context->value = newBinding; + symbol->context->usage = newUsage; + symbol->context->environmentNumber = currentEnvironment-> + environmentNumber; + symbol->context->attributes = DEFINED_VARIABLE_ATT; +} + + void +popBinding(symbol) + symbolTableEntryType *symbol; +{ + popSymbol(symbol); +} + + int /* returns number of bindings completed, negative this if failure */ +bindMacroArguments(argumentList, parameterList, macroName) + argumentDefinitionListType *argumentList; + operandListType *parameterList; + stringType *macroName; +{ + int numberBound; + bool arrayTag; + int arrayLength; + valueType **arrayContents; + int i; + + valueType *newValue(); + + if (argumentList == NULL) + arrayTag = FALSE; + else + arrayTag = ((argumentListHeadType *)argumentList)->arrayTag; + numberBound = 1; + while (argumentList!=NULL && (!arrayTag || argumentList-> + nextArgument!=NULL) && parameterList!=NULL) { + pushBinding(argumentList->theArgument, newValue(OPERAND_VALUE, + parameterList, EXPRESSION_OPND), ARGUMENT_SYMBOL); + argumentList = argumentList->nextArgument; + parameterList = parameterList->nextOperand; + numberBound++; + } + if (!arrayTag) { + if (parameterList != NULL) { + error(TOO_MANY_ARGUMENTS_TO_MACRO_ERROR, macroName, + numberBound-1); + return(-numberBound); + } + while (argumentList != NULL) { + pushBinding(argumentList->theArgument, newValue(FAIL, + 0, EXPRESSION_OPND), ARGUMENT_SYMBOL); + argumentList = argumentList->nextArgument; + numberBound++; + } + } else { + if (parameterList == NULL) { + while (argumentList->nextArgument != NULL) { + pushBinding(argumentList->theArgument, + newValue(FAIL, 0, EXPRESSION_OPND), + ARGUMENT_SYMBOL); + argumentList = argumentList->nextArgument; + numberBound++; + } + } + arrayLength = countParameters(parameterList); + pushBinding(argumentList->theArgument, newValue(ARRAY_VALUE, + allocArray(arrayLength, &arrayContents), + EXPRESSION_OPND), ARGUMENT_SYMBOL); + for (i=0; inextOperand; + } + numberBound++; + } + return(numberBound); +} + + int /* returns number of bindings completed, negative this if failure */ +bindFunctionArguments(argumentList, parameterList, functionName) + argumentDefinitionListType *argumentList; + operandListType *parameterList; + stringType *functionName; +{ + valueType *argument; + bool arrayTag; + int arrayLength; + valueType **arrayContents; + int i; + int numberBound; + valueType *firstArgument; + environmentType *saveEnvironment; + + valueType *evaluateOperand(); + valueType *newValue(); + + if (argumentList == NULL) + arrayTag = FALSE; + else + arrayTag = ((argumentListHeadType *)argumentList)->arrayTag; + numberBound = 1; + firstArgument = NULL; + while (argumentList!=NULL && (!arrayTag || argumentList-> + nextArgument!=NULL) && parameterList!=NULL) { + saveEnvironment = currentEnvironment; + currentEnvironment = currentEnvironment->previousEnvironment; + argument = evaluateOperand(parameterList, NO_FIXUP); + currentEnvironment = saveEnvironment; + if (firstArgument == NULL) + firstArgument = argument; + if (isUsable(argument)) { + pushBinding(argumentList->theArgument, argument, + ARGUMENT_SYMBOL); + argumentList = argumentList->nextArgument; + parameterList = parameterList->nextOperand; + expand((argumentList!=NULL && parameterList!=NULL) ? + moreExpression(", ") : 0); + numberBound++; + } else { + if (isUndefined(argument)) + resultOfLastFunctionCall = + newValue(UNDEFINED_VALUE, 0, + firstArgument->addressMode); + return(-numberBound); + } + } + if (!arrayTag) { + if (parameterList != NULL) { + error(TOO_MANY_ARGUMENTS_TO_FUNCTION_ERROR, + functionName, numberBound - 1); + return(-numberBound); + } + while (argumentList != NULL) { + pushBinding(argumentList->theArgument, newValue(FAIL, + 0, EXPRESSION_OPND), ARGUMENT_SYMBOL); + argumentList = argumentList->nextArgument; + numberBound++; + } + } else { + if (parameterList == NULL) { + while (argumentList->nextArgument != NULL) { + pushBinding(argumentList->theArgument, + newValue(FAIL, 0, EXPRESSION_OPND), + ARGUMENT_SYMBOL); + argumentList = argumentList->nextArgument; + numberBound++; + } + } + arrayLength = countParameters(parameterList); + pushBinding(argumentList->theArgument, newValue(ARRAY_VALUE, + allocArray(arrayLength, &arrayContents), + EXPRESSION_OPND), ARGUMENT_SYMBOL); + numberBound++; + for (i=0; i + previousEnvironment; + argument = evaluateOperand(parameterList, NO_FIXUP); + currentEnvironment = saveEnvironment; + if (firstArgument == NULL) + firstArgument = argument; + if (isUsable(argument)) { + arrayContents[i] = argument; + parameterList = parameterList->nextOperand; + } else { + if (isUndefined(argument)) + resultOfLastFunctionCall = + newValue(UNDEFINED_VALUE, 0, + firstArgument->addressMode); + return(-numberBound); + } + } + } + return(numberBound); +} + + void +unbindArguments(argumentList, numberToUnbind) + argumentDefinitionListType *argumentList; + int numberToUnbind; +{ + while (argumentList != NULL && numberToUnbind-- > 0) { + popBinding(argumentList->theArgument); + argumentList = argumentList->nextArgument; + } + if (numberToUnbind > 0) + botch("binding count larger than number of bindings\n"); +} + + void +unbindLocalVariables(identifierList) + identifierListType *identifierList; +{ + identifierListType *deadEntry; + + while (identifierList != NULL) { + popBinding(identifierList->theSymbol); + deadEntry = identifierList; + identifierList = identifierList->nextIdentifier; + qfree(deadEntry); + } +} diff --git a/lookups.o b/lookups.o new file mode 100644 index 0000000..e46b287 Binary files /dev/null and b/lookups.o differ diff --git a/macross b/macross new file mode 100755 index 0000000..591f45c Binary files /dev/null and b/macross differ diff --git a/macrossGlobals.h b/macrossGlobals.h new file mode 100644 index 0000000..b24eaef --- /dev/null +++ b/macrossGlobals.h @@ -0,0 +1,151 @@ +/* + macrossGlobals.h -- Global variable definitions for the Macross + assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 1-November-1984 + +*/ + +bool backwardsCompatibleIfFlag; +bool beneathFunction; +commandLineDefineType *commandLineDefines; +int cumulativeLineNumber; +environmentType *currentEnvironment; +int currentFieldOffset; +char *currentFileName; +char *lastErrorFile; +stringType *currentFunctionName; +int currentLabelTagNumber; +int currentLineNumber; +int lastErrorLine; +identifierListType *currentLocalVariableList; +valueType currentLocationCounter; +int currentOperandNumber; +int currentReferenceDepth; +bool debug; +bool emitPrint; +bool expandMacros; +bool errorFlag; +bool expressionFailed; +bool finishOperand; +operandKindType fixupAddressMode[MAX_NUMBER_OF_OPERANDS]; +operandKindType newFixupAddressMode; +fixupListType *fixupList; +bool freeFlag; +bool freturnExit; +bool generatingFixup; +environmentType globalEnvironment; +int hackFlag; +bool haveUserStartAddress; +bool fixupStartAddress; +int includeNestingDepth; +FILE *indexFileForPass2; +FILE *input; +fileNameListType *inputFileStack; +FILE *listFileOutput; +int listingControlCounter; +bool listingOn; +int macroCallDepth; +FILE *macroFileForPass2; +int macroOrFunctionNestingDepth; +structInstanceType *newStruct; +int nextEnvironmentNumber; +int nextLabelTagNumber; +FILE *objectFileOutput; +char operandBuffer[MAX_NUMBER_OF_OPERANDS][LINE_BUFFER_SIZE]; +char pass2IndexFileName[]; +char pass2SourceFileName[]; +char pass2MacroExpansionFileName[]; +expressionType *pendingFixup[MAX_NUMBER_OF_OPERANDS]; +bool performingFixups; +bool positionIndependentCodeMode; +bool produceLinkableObject; +addressType relocatableHighWaterMark; +reservationListType *reservationList; +valueType *resultOfLastFunctionCall; +valueType savedRelocatableCurrentLocationCounter; +FILE *saveFileForPass2; +bool showAllSymbolsFlag; +bool sideEffectFlag; +bool standaloneExpansionFlag; +valueType *startAddress; +int statementEvaluationDepth; +int statementListNestingDepth; +int structNestingDepth; +FILE *symbolDumpFileOutput; +bool symbolTableDumpOn; +int tabCount; +addressType targetOffset; +bool terseErrorMessages; +valueType *UndefinedValue; +symbolUsageKindType unknownSymbolTag; + +#define DEFAULT_OBJECT_FILE_NAME "m.out" + +#define LEX_DISPATCH_TABLE_SIZE 128 +int (*lexDispatchTable[128])(); + +#define HASH_TABLE_SIZE 512 +#define HASH_TABLE_MASK 0x1FF + +struct { + stringType *functionName; + valueType *(*functionEntry)(); + bool isSpecialFunction; + int ordinal; + } builtInFunctionTable[]; + +struct { + stringType *symbolName; + int symbolValue; + } predefinedSymbolTable[]; + +macroTableEntryType *macroTable[HASH_TABLE_SIZE]; + +opcodeTableEntryType *opcodeTable[HASH_TABLE_SIZE]; + +opcodeTableEntryType theOpcodes[]; + +keywordTableEntryType *keywordTable[HASH_TABLE_SIZE]; + +keywordTableEntryType theKeywords[]; + +conditionTableEntryType *conditionTable[HASH_TABLE_SIZE]; + +conditionTableEntryType theConditions[]; + +symbolTableEntryType *symbolTable[HASH_TABLE_SIZE]; + +int operandClassTable[]; + +void (*instructionActionTable[])(); + +int validSymbolValues[NUM_OF_SYM_USAGES]; + +byte structScratchBuffer[MAXIMUM_ALLOWED_STRUCT_SIZE]; + +codeRegionType absoluteCodeRegion; +codeRegionType relocatableCodeRegion; +codeRegionType *codeRegions[2]; +codeBufferKindType currentCodeMode; +codeBufferType *emptyBuffer; /* ??? */ +codeBreakType *codeBreakList; +codeBreakType *lastCodeBreak; + +expressionReferenceListType *expressionReferenceList[3]; +expressionReferenceListType *referencesToNote[MAX_NUMBER_OF_OPERANDS]; +int numberOfReferencesInList[3]; +functionDefinitionType *externalFunctionList; +functionDefinitionType *endOfExternalFunctionList; +int externalFunctionCount; + +char alphabeticCharacterTable[128]; +char alphaNumericCharacterTable[128]; +char lowerCaseCharacterTable[128]; +char numericCharacterTable[128]; + +int expressionBufferSize; +#define EXPRESSION_BUFFER_LIMIT 500 +byte expressionBuffer[EXPRESSION_BUFFER_LIMIT]; diff --git a/macrossTables.o b/macrossTables.o new file mode 100644 index 0000000..5220965 Binary files /dev/null and b/macrossTables.o differ diff --git a/macrossTables_6502.c b/macrossTables_6502.c new file mode 100644 index 0000000..f9aaa51 --- /dev/null +++ b/macrossTables_6502.c @@ -0,0 +1,405 @@ +/* + macrossTables.c -- Define the contents of various tables and values + of various initialized global variables. + + Chip Morningstar -- Lucasfilm Ltd. + + 5-November-1984 +*/ + +#include "macrossTypes.h" +#include "y.tab.h" + +/* All those NULLs are used to string together lists after this all gets + hashed */ +conditionTableEntryType theConditions[] = { + "always", NULL, ALWAYS_COND, + "carry", NULL, CARRY_COND, + "equal", NULL, ZERO_COND, + "geq", NULL, GEQ_COND, + "greater", NULL, GT_COND, + "gt", NULL, GT_COND, + "leq", NULL, LEQ_COND, + "less", NULL, LT_COND, + "lt", NULL, LT_COND, + "minus", NULL, NEGATIVE_COND, + "negative", NULL, NEGATIVE_COND, + "neq", NULL, NOT_ZERO_COND, + "never", NULL, NEVER_COND, + "not_carry", NULL, NOT_CARRY_COND, /* for dragon */ + "not_equal", NULL, NOT_ZERO_COND, /* for dragon */ + "not_overflow", NULL, NOT_OVERFLOW_COND, /* for dragon */ + "not_zero", NULL, NOT_ZERO_COND, /* for dragon */ + "overflow", NULL, OVERFLOW_COND, + "plus", NULL, NOT_NEGATIVE_COND, + "positive", NULL, NOT_NEGATIVE_COND, + "sgeq", NULL, SGEQ_COND, + "sgt", NULL, SGT_COND, + "sleq", NULL, SLEQ_COND, + "slt", NULL, SLT_COND, + "sneq", NULL, NOT_ZERO_COND, + "zero", NULL, ZERO_COND, + NULL, NULL, NEVER_COND, + }; + +/* All those NULLs are used to string together lists after this all gets + hashed */ +keywordTableEntryType theKeywords[] = { + "a", NULL, A, + "align", NULL, ALIGN, + "assert", NULL, ASSERT, + "block", NULL, BLOCK, + "byte", NULL, BYTE, + "constrain", NULL, CONSTRAIN, + "dbyte", NULL, DBYTE, + "define", NULL, DEFINE, + "do", NULL, DO, + "else", NULL, ELSE, + "elseif", NULL, ELSEIF, + "extern", NULL, EXTERN, + "freturn", NULL, FRETURN, + "function", NULL, FUNCTION, + "here", NULL, HERE, + "if", NULL, IF, + "include", NULL, INCLUDE, + "long", NULL, LONG, + "macro", NULL, MACRO, + "mcase", NULL, MCASE, + "mdefault", NULL, MDEFAULT, + "mdefine", NULL, MDEFINE, + "mdo", NULL, MDO, + "melse", NULL, MELSE, + "melseif", NULL, MELSEIF, + "mfor", NULL, MFOR, + "mif", NULL, MIF, + "mswitch", NULL, MSWITCH, + "muntil", NULL, MUNTIL, + "mvariable", NULL, MVARIABLE, + "mwhile", NULL, MWHILE, + "org", NULL, ORG, + "rel", NULL, REL, + "start", NULL, START, + "string", NULL, STRING, + "struct", NULL, STRUCT, + "target", NULL, TARGET, + "undefine", NULL, UNDEFINE, + "until", NULL, UNTIL, + "variable", NULL, VARIABLE, + "while", NULL, WHILE, + "word", NULL, WORD, + "x", NULL, X, + "y", NULL, Y, + NULL, NULL, 0, + }; + +#define HASH_TABLE_SIZE 509 + +macroTableEntryType *macroTable[HASH_TABLE_SIZE]; + +opcodeTableEntryType *opcodeTable[HASH_TABLE_SIZE]; + +symbolTableEntryType *symbolTable[HASH_TABLE_SIZE]; + +keywordTableEntryType *keywordTable[HASH_TABLE_SIZE]; + +conditionTableEntryType *conditionTable[HASH_TABLE_SIZE]; + +/* All those NULLs are used to string together lists after this all gets + hashed. */ +opcodeTableEntryType theOpcodes[] = { + "adc", NULL, 0x61, IMM_INDEX, IMM_INDEX_CLASS_BITS, 1, 1, 0, + "and", NULL, 0x21, IMM_INDEX, IMM_INDEX_CLASS_BITS, 1, 1, 0, + "asl", NULL, 0x02, DIR_X_1, DIR_X_1_CLASS_BITS, 1, 1, 0, + "bcc", NULL, 0x90, RELATIVE, REL_CLASS_BITS, 1, 1, 0, + "bcs", NULL, 0xB0, RELATIVE, REL_CLASS_BITS, 1, 1, 0, + "beq", NULL, 0xF0, RELATIVE, REL_CLASS_BITS, 1, 1, 0, + "bit", NULL, 0x24, DIR_1, DIR_1_CLASS_BITS, 1, 1, 0, + "bmi", NULL, 0x30, RELATIVE, REL_CLASS_BITS, 1, 1, 0, + "bne", NULL, 0xD0, RELATIVE, REL_CLASS_BITS, 1, 1, 0, + "bpl", NULL, 0x10, RELATIVE, REL_CLASS_BITS, 1, 1, 0, + "brk", NULL, 0x00, NONE, NONE_CLASS_BITS, 0, 0, 0, + "bvc", NULL, 0x50, RELATIVE, REL_CLASS_BITS, 1, 1, 0, + "bvs", NULL, 0x70, RELATIVE, REL_CLASS_BITS, 1, 1, 0, + "clc", NULL, 0x18, NONE, NONE_CLASS_BITS, 0, 0, 0, + "cld", NULL, 0xD8, NONE, NONE_CLASS_BITS, 0, 0, 0, + "cli", NULL, 0x58, NONE, NONE_CLASS_BITS, 0, 0, 0, + "clv", NULL, 0xB8, NONE, NONE_CLASS_BITS, 0, 0, 0, + "cmp", NULL, 0xC1, IMM_INDEX, IMM_INDEX_CLASS_BITS, 1, 1, 0, + "cpx", NULL, 0xE0, IMM_DIR, IMM_DIR_CLASS_BITS, 1, 1, 0, + "cpy", NULL, 0xC0, IMM_DIR, IMM_DIR_CLASS_BITS, 1, 1, 0, + "dec", NULL, 0xC6, DIR_X_2, DIR_X_2_CLASS_BITS, 1, 1, 0, + "dex", NULL, 0xCA, NONE, NONE_CLASS_BITS, 0, 0, 0, + "dey", NULL, 0x88, NONE, NONE_CLASS_BITS, 0, 0, 0, + "eor", NULL, 0x41, IMM_INDEX, IMM_INDEX_CLASS_BITS, 1, 1, 0, + "inc", NULL, 0xE6, DIR_X_2, DIR_X_2_CLASS_BITS, 1, 1, 0, + "inx", NULL, 0xE8, NONE, NONE_CLASS_BITS, 0, 0, 0, + "iny", NULL, 0xC8, NONE, NONE_CLASS_BITS, 0, 0, 0, + "jmp", NULL, 0x4C, DIR_INDIR, DIR_INDIR_CLASS_BITS, 1, 1, 0, + "jsr", NULL, 0x20, DIR_2, DIR_2_CLASS_BITS, 1, 1, 0, + "lda", NULL, 0xA1, IMM_INDEX, IMM_INDEX_CLASS_BITS, 1, 1, 0, + "ldx", NULL, 0xA2, IMM_DIR_Y, IMM_DIR_Y_CLASS_BITS, 1, 1, 0, + "ldy", NULL, 0xA0, IMM_DIR_X, IMM_DIR_X_CLASS_BITS, 1, 1, 0, + "lsr", NULL, 0x42, DIR_X_1, DIR_X_1_CLASS_BITS, 1, 1, 0, + "nop", NULL, 0xEA, NONE, NONE_CLASS_BITS, 0, 0, 0, + "ora", NULL, 0x01, IMM_INDEX, IMM_INDEX_CLASS_BITS, 1, 1, 0, + "pha", NULL, 0x48, NONE, NONE_CLASS_BITS, 0, 0, 0, + "php", NULL, 0x08, NONE, NONE_CLASS_BITS, 0, 0, 0, + "pla", NULL, 0x68, NONE, NONE_CLASS_BITS, 0, 0, 0, + "plp", NULL, 0x28, NONE, NONE_CLASS_BITS, 0, 0, 0, + "rol", NULL, 0x22, DIR_X_1, DIR_X_1_CLASS_BITS, 1, 1, 0, + "ror", NULL, 0x62, DIR_X_1, DIR_X_1_CLASS_BITS, 1, 1, 0, + "rti", NULL, 0x40, NONE, NONE_CLASS_BITS, 0, 0, 0, + "rts", NULL, 0x60, NONE, NONE_CLASS_BITS, 0, 0, 0, + "sbc", NULL, 0xE1, IMM_INDEX, IMM_INDEX_CLASS_BITS, 1, 1, 0, + "sec", NULL, 0x38, NONE, NONE_CLASS_BITS, 0, 0, 0, + "sed", NULL, 0xF8, NONE, NONE_CLASS_BITS, 0, 0, 0, + "sei", NULL, 0x78, NONE, NONE_CLASS_BITS, 0, 0, 0, + "sta", NULL, 0x81, INDEX, INDEX_CLASS_BITS, 1, 1, 0, + "stx", NULL, 0x86, DIR_Y, DIR_Y_CLASS_BITS, 1, 1, 0, + "sty", NULL, 0x84, DIR_X_3, DIR_X_3_CLASS_BITS, 1, 1, 0, + "tax", NULL, 0xAA, NONE, NONE_CLASS_BITS, 0, 0, 0, + "tay", NULL, 0xA8, NONE, NONE_CLASS_BITS, 0, 0, 0, + "tsx", NULL, 0xBA, NONE, NONE_CLASS_BITS, 0, 0, 0, + "txa", NULL, 0x8A, NONE, NONE_CLASS_BITS, 0, 0, 0, + "txs", NULL, 0x9A, NONE, NONE_CLASS_BITS, 0, 0, 0, + "tya", NULL, 0x98, NONE, NONE_CLASS_BITS, 0, 0, 0, + NULL, NULL, 0x00, NONE, NONE_CLASS_BITS, 0, 0, 0, +}; + +int operandClassTable[] = { /* indexed by operandKindType */ + EXPRESSION_OPND_BIT, + IMMEDIATE_OPND_BIT, + INDIRECT_OPND_BIT, + A_REGISTER_OPND_BIT, + X_REGISTER_OPND_BIT, + Y_REGISTER_OPND_BIT, + POST_INDEXED_Y_OPND_BIT, + PRE_INDEXED_X_OPND_BIT, + X_INDEXED_OPND_BIT, + Y_INDEXED_OPND_BIT, + X_SELECTED_OPND_BIT, + Y_SELECTED_OPND_BIT, + PRE_SELECTED_X_OPND_BIT, + STRING_OPND_BIT, + BLOCK_OPND_BIT, +}; + +int actionsRelative(); +int actionsDir1(); +int actionsDir2(); +int actionsDirIndir(); +int actionsDirX1(); +int actionsDirX2(); +int actionsDirX3(); +int actionsDirY(); +int actionsImmDir(); +int actionsImmDirX(); +int actionsImmDirY(); +int actionsNone(); +int actionsIndex(); +int actionsImmIndex(); + +/* indexed by opcodeClass */ +int (*instructionActionTable[])() = { + actionsRelative, + actionsDir1, + actionsDir2, + actionsDirIndir, + actionsDirX1, + actionsDirX2, + actionsDirX3, + actionsDirY, + actionsImmDir, + actionsImmDirX, + actionsImmDirY, + actionsNone, + actionsIndex, + actionsImmIndex, +}; + +/* indexed by symbolUsageKindType */ +int validSymbolValues[NUM_OF_SYM_USAGES] = { + /* STRUCT_NAME_SYMBOL */ STRUCT_VALUE_BIT, + /* STRUCT_FIELD_SYMBOL */ FIELD_VALUE_BIT, + /* MACRO_SYMBOL */ MACRO_VALUE_BIT, + /* ARGUMENT_SYMBOL */ OPERAND_VALUE_BIT, + /* LABEL_SYMBOL */ ABSOLUTE_VALUE_BIT | RELOCATABLE_VALUE_BIT | + DATA_VALUE_BIT | BSS_VALUE_BIT, + /* EXTERNAL_SYMBOL */ ABSOLUTE_VALUE_BIT | RELOCATABLE_VALUE_BIT | + DATA_VALUE_BIT | BSS_VALUE_BIT | + UNDEFINED_VALUE_BIT, + /* VARIABLE_SYMBOL */ ABSOLUTE_VALUE_BIT | RELOCATABLE_VALUE_BIT | + DATA_VALUE_BIT | BSS_VALUE_BIT | + UNDEFINED_VALUE_BIT | + STRING_VALUE_BIT | OPERAND_VALUE_BIT | + CONDITION_VALUE_BIT, + /* MVARIABLE_SYMBOL */ ABSOLUTE_VALUE_BIT | RELOCATABLE_VALUE_BIT | + DATA_VALUE_BIT | BSS_VALUE_BIT | + UNDEFINED_VALUE_BIT | + STRING_VALUE_BIT | OPERAND_VALUE_BIT | + CONDITION_VALUE_BIT, + /* UNKNOWN_SYMBOL */ UNDEFINED_VALUE_BIT, + /* FUNCTION_SYMBOL */ FUNCTION_VALUE_BIT, + /* BUILT_IN_FUNCTION_SYMBOL */ BUILT_IN_FUNCTION_VALUE_BIT, + /* NESTED_UNKNOWN_SYMBOL */ UNDEFINED_VALUE_BIT, + /* DEFINE_SYMBOL */ OPERAND_VALUE_BIT, + /* MDEFINE_SYMBOL */ OPERAND_VALUE_BIT, + /* UNKNOWN_FUNCTION_SYMBOL */ UNDEFINED_VALUE_BIT, + /* UNKNOWN_MACRO_SYMBOL */ UNDEFINED_VALUE_BIT, +}; + +/* indexed by valueKindType */ +int valueBitTable[] = { + ABSOLUTE_VALUE_BIT, + DATA_VALUE_BIT, + RELOCATABLE_VALUE_BIT, + BSS_VALUE_BIT, + STRUCT_VALUE_BIT, + FIELD_VALUE_BIT, + MACRO_VALUE_BIT, + OPERAND_VALUE_BIT, + STRING_VALUE_BIT, + CONDITION_VALUE_BIT, + UNDEFINED_VALUE_BIT, + FUNCTION_VALUE_BIT, + BLOCK_VALUE_BIT, + BUILT_IN_FUNCTION_VALUE_BIT, + ARRAY_VALUE_BIT, + FAIL_BIT, +}; + + +codeRegionType absoluteCodeRegion; +codeRegionType relocatableCodeRegion; +codeRegionType *codeRegions[2] = { + &absoluteCodeRegion, + &relocatableCodeRegion +}; + +/* A predefined undefined value so we don't have to make a new one every + time we need one */ +valueType undefinedValueValue = { UNDEFINED_VALUE, 0, + EXPRESSION_OPND }; +valueType *UndefinedValue = &undefinedValueValue; + +valueType *addressModeBIF(); +valueType *applyBIF(); +valueType *arrayLengthBIF(); +valueType *atasciiBIF(); +valueType *atasciiColorBIF(); +valueType *debugModeOffBIF(); +valueType *debugModeOnBIF(); +valueType *emitModeOffBIF(); +valueType *emitModeOnBIF(); +valueType *isAbsoluteValueBIF(); +valueType *isARegisterBIF(); +valueType *isBlockBIF(); +valueType *isBuiltInFunctionBIF(); +valueType *isConditionCodeBIF(); +valueType *isDefinedBIF(); +valueType *isDirectModeBIF(); +valueType *isExternalBIF(); +valueType *isFieldBIF(); +valueType *isFunctionBIF(); +valueType *isImmediateModeBIF(); +valueType *isIndexedModeBIF(); +valueType *isIndirectModeBIF(); +valueType *isPostIndexedModeBIF(); +valueType *isPreIndexedModeBIF(); +valueType *isRelocatableValueBIF(); +valueType *isStringBIF(); +valueType *isStructBIF(); +valueType *isSymbolBIF(); +valueType *isXIndexedModeBIF(); +valueType *isXRegisterBIF(); +valueType *isYIndexedModeBIF(); +valueType *isYRegisterBIF(); +valueType *listingOffBIF(); +valueType *listingOnBIF(); +valueType *makeArrayBIF(); +valueType *nthCharBIF(); +valueType *printfBIF(); +valueType *strcatBIF(); +valueType *strcmpBIF(); +valueType *strcmplcBIF(); +valueType *strlenBIF(); +valueType *substrBIF(); +valueType *symbolDefineBIF(); +valueType *symbolLookupBIF(); +valueType *symbolNameBIF(); +valueType *symbolUsageBIF(); +valueType *valueTypeBIF(); + +/* Used to initialize symbols representing built-in functions */ +struct { + stringType *functionName; + valueType *(*functionEntry)(); + bool isSpecialFunction; + int ordinal; + } builtInFunctionTable[] = { + "addressMode", addressModeBIF, FALSE, -1, + "apply", applyBIF, FALSE, -1, + "arrayLength", arrayLengthBIF, FALSE, -1, + "atascii", atasciiBIF, FALSE, 0, + "atasciiColor", atasciiColorBIF, FALSE, 1, + "debugModeOff", debugModeOffBIF, FALSE, -1, + "debugModeOn", debugModeOnBIF, FALSE, -1, + "emitModeOff", emitModeOffBIF, FALSE, -1, + "emitModeOn", emitModeOnBIF, FALSE, -1, + "isAbsoluteValue", isAbsoluteValueBIF, FALSE, 2, + "isARegister", isARegisterBIF, FALSE, -1, + "isBlock", isBlockBIF, FALSE, -1, + "isBuiltInFunction", isBuiltInFunctionBIF, FALSE, -1, + "isConditionCode", isConditionCodeBIF, FALSE, 3, + "isDefined", isDefinedBIF, TRUE, 4, + "isDirectMode", isDirectModeBIF, FALSE, -1, + "isExternal", isExternalBIF, TRUE, 5, + "isField", isFieldBIF, FALSE, -1, + "isFunction", isFunctionBIF, FALSE, -1, + "isImmediateMode", isImmediateModeBIF, FALSE, -1, + "isIndexedMode", isIndexedModeBIF, FALSE, -1, + "isIndirectMode", isIndirectModeBIF, FALSE, -1, + "isPostIndexedMode", isPostIndexedModeBIF, FALSE, -1, + "isPreIndexedMode", isPreIndexedModeBIF, FALSE, -1, + "isRelocatableValue", isRelocatableValueBIF, FALSE, -1, + "isString", isStringBIF, FALSE, -1, + "isStruct", isStructBIF, FALSE, -1, + "isSymbol", isSymbolBIF, TRUE, -1, + "isXIndexedMode", isXIndexedModeBIF, FALSE, -1, + "isXRegister", isXRegisterBIF, FALSE, -1, + "isYIndexedMode", isYIndexedModeBIF, FALSE, -1, + "isYRegister", isYRegisterBIF, FALSE, -1, + "listingOff", listingOffBIF, FALSE, -1, + "listingOn", listingOnBIF, FALSE, -1, + "makeArray", makeArrayBIF, FALSE, -1, + "nthChar", nthCharBIF, FALSE, 6, + "printf", printfBIF, FALSE, 7, + "strcat", strcatBIF, FALSE, 8, + "strcmp", strcmpBIF, FALSE, 9, + "strcmplc", strcmplcBIF, FALSE, 10, + "strlen", strlenBIF, FALSE, 11, + "substr", substrBIF, FALSE, 12, + "symbolDefine", symbolDefineBIF, FALSE, -1, + "symbolLookup", symbolLookupBIF, FALSE, 13, + "symbolName", symbolNameBIF, TRUE, 14, + "symbolUsage", symbolUsageBIF, TRUE, -1, + "valueType", valueTypeBIF, FALSE, -1, + NULL, NULL, FALSE, -1, +}; + +/* Used to initialize predefined symbols */ +struct { + stringType *symbolName; + int symbolValue; + } predefinedSymbolTable[] = { + "FALSE", 0, + "NULL", 0, + "TRUE", 1, + NULL, 0, +}; + +/* These define the temporary files used to hold scratch data used in the + generation of listings. The "XXXXXX"s get blasted by 'mktemp' */ +char pass2SourceFileName[] = "/tmp/zsourceXXXXXX"; +char pass2IndexFileName[] = "/tmp/zindexXXXXXX"; +char pass2MacroExpansionFileName[] = "/tmp/zmacroXXXXXX"; diff --git a/macrossTables_68000.c b/macrossTables_68000.c new file mode 100644 index 0000000..95d91c4 --- /dev/null +++ b/macrossTables_68000.c @@ -0,0 +1,608 @@ +/* + macrossTables.c -- Define the contents of various tables and values + of various initialized global variables. + + Chip Morningstar -- Lucasfilm Ltd. + + 5-November-1984 +*/ + +#include "macrossTypes.h" +#include "y.tab.h" + +/* All those NULLs are used to string together lists after this all gets + hashed */ +conditionTableEntryType theConditions[] = { + "always", NULL, ALWAYS_COND, + "carry", NULL, CARRY_COND, + "equal", NULL, EQUAL_COND, + "geq", NULL, GEQ_COND, + "greater", NULL, GT_COND, + "gt", NULL, GT_COND, + "high", NULL, HIGH_COND, + "high_same", NULL, NOT_CARRY_COND, + "hs", NULL, NOT_CARRY_COND, + "less", NULL, LT_COND, + "leq", NULL, LEQ_COND, + "low", NULL, CARRY_COND, + "low_same", NULL, LOW_OR_SAME_COND, + "ls", NULL, LOW_OR_SAME_COND, + "lt", NULL, LT_COND, + "minus", NULL, MINUS_COND, + "negative", NULL, MINUS_COND, + "neq", NULL, NOT_EQUAL_COND, + "never", NULL, NEVER_COND, + "not_carry", NULL, NOT_CARRY_COND, /* for dragon */ + "not_equal", NULL, NOT_EQUAL_COND, /* for dragon */ + "not_overflow", NULL, NOT_OVERFLOW_COND, /* for dragon */ + "not_zero", NULL, NOT_EQUAL_COND, /* for dragon */ + "overflow", NULL, OVERFLOW_COND, + "plus", NULL, PLUS_COND, + "positive", NULL, PLUS_COND, + "zero", NULL, EQUAL_COND, + NULL, NULL, NEVER_COND, + }; + +/* All those NULLs are used to string together lists after this all gets + hashed */ +keywordTableEntryType theKeywords[] = { + "a0", NULL, A0, + "a1", NULL, A1, + "a2", NULL, A2, + "a3", NULL, A3, + "a4", NULL, A4, + "a5", NULL, A5, + "a6", NULL, A6, + "a7", NULL, A7, + "align", NULL, ALIGN, + "assert", NULL, ASSERT, + "block", NULL, BLOCK, + "byte", NULL, BYTE, + "cc", NULL, CCR, + "ccr", NULL, CCR, + "constrain", NULL, CONSTRAIN, + "d0", NULL, D0, + "d1", NULL, D1, + "d2", NULL, D2, + "d3", NULL, D3, + "d4", NULL, D4, + "d5", NULL, D5, + "d6", NULL, D6, + "d7", NULL, D7, + "dbyte", NULL, DBYTE, + "define", NULL, DEFINE, + "dfc", NULL, DFC, + "do", NULL, DO, + "else", NULL, ELSE, + "elseif", NULL, ELSEIF, + "extern", NULL, EXTERN, + "freturn", NULL, FRETURN, + "function", NULL, FUNCTION, + "here", NULL, HERE, + "if", NULL, IF, + "include", NULL, INCLUDE, + "l", NULL, L, + "long", NULL, LONG, + "macro", NULL, MACRO, + "mcase", NULL, MCASE, + "mdefault", NULL, MDEFAULT, + "mdefine", NULL, MDEFINE, + "mdo", NULL, MDO, + "melse", NULL, MELSE, + "melseif", NULL, MELSEIF, + "mfor", NULL, MFOR, + "mif", NULL, MIF, + "mswitch", NULL, MSWITCH, + "muntil", NULL, MUNTIL, + "mvariable", NULL, MVARIABLE, + "mwhile", NULL, MWHILE, + "org", NULL, ORG, + "pc", NULL, PC, + "rel", NULL, REL, + "sfc", NULL, SFC, + "sr", NULL, SR, + "start", NULL, START, + "string", NULL, STRING, + "struct", NULL, STRUCT, + "target", NULL, TARGET, + "undefine", NULL, UNDEFINE, + "until", NULL, UNTIL, + "usp", NULL, USP, + "variable", NULL, VARIABLE, + "vbr", NULL, VBR, + "w", NULL, W, + "while", NULL, WHILE, + "word", NULL, WORD, + NULL, NULL, 0, + }; + +#define HASH_TABLE_SIZE 509 + +macroTableEntryType *macroTable[HASH_TABLE_SIZE]; + +opcodeTableEntryType *opcodeTable[HASH_TABLE_SIZE]; + +symbolTableEntryType *symbolTable[HASH_TABLE_SIZE]; + +keywordTableEntryType *keywordTable[HASH_TABLE_SIZE]; + +conditionTableEntryType *conditionTable[HASH_TABLE_SIZE]; + +/* All those NULLs are used to string together lists after this all gets + hashed. */ +opcodeTableEntryType theOpcodes[] = { +/* mnemonic, next, opcode, class, allowed modes, min#operands, max#operands, + subclass/alternate opcode */ + "abcd", NULL, 0xC100, CLASS_I, CLASS_I_BITS, 2, 2, 0, + "addb", NULL, 0xD000, CLASS_II, CLASS_II_BITS, 2, 2, 0x0600, + "addl", NULL, 0xD080, CLASS_II, CLASS_II_BITS, 2, 2, 0x0680, + "addqb",NULL, 0x5000, CLASS_III, CLASS_III_BITS, 2, 2, 0, + "addql",NULL, 0x5080, CLASS_III, CLASS_III_BITS, 2, 2, 0, + "addqw",NULL, 0x5040, CLASS_III, CLASS_III_BITS, 2, 2, 0, + "addw", NULL, 0xD040, CLASS_II, CLASS_II_BITS, 2, 2, 0x0640, + "addxb",NULL, 0xD100, CLASS_I, CLASS_I_BITS, 2, 2, 0, + "addxl",NULL, 0xD180, CLASS_I, CLASS_I_BITS, 2, 2, 0, + "addxw",NULL, 0xD140, CLASS_I, CLASS_I_BITS, 2, 2, 0, + "andb", NULL, 0xC000, CLASS_IV, CLASS_IV_BITS, 2, 2, 0x0200, + "andl", NULL, 0xC080, CLASS_IV, CLASS_IV_BITS, 2, 2, 0x0280, + "andw", NULL, 0xC040, CLASS_IV, CLASS_IV_BITS, 2, 2, 0x0240, + "aslb", NULL, 0xE100, CLASS_V, CLASS_V_BITS, 1, 2, 00, + "asll", NULL, 0xE180, CLASS_V, CLASS_V_BITS, 1, 2, 00, + "aslw", NULL, 0xE140, CLASS_V, CLASS_V_BITS, 1, 2, 00, + "asrb", NULL, 0xE000, CLASS_V, CLASS_V_BITS, 1, 2, 00, + "asrl", NULL, 0xE080, CLASS_V, CLASS_V_BITS, 1, 2, 00, + "asrw", NULL, 0xE040, CLASS_V, CLASS_V_BITS, 1, 2, 00, + "bcc", NULL, 0x64, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bchg", NULL, 0x0040, CLASS_VII, CLASS_VII_BITS, 2, 2, 0, + "bclr", NULL, 0x0080, CLASS_VII, CLASS_VII_BITS, 2, 2, 0, + "bcs", NULL, 0x65, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "beq", NULL, 0x67, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bge", NULL, 0x6C, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bgt", NULL, 0x6E, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bhi", NULL, 0x62, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "ble", NULL, 0x6F, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bls", NULL, 0x63, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "blt", NULL, 0x6D, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bmi", NULL, 0x6B, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bne", NULL, 0x66, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bpl", NULL, 0x6A, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bra", NULL, 0x60, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bset", NULL, 0x00C0, CLASS_VII, CLASS_VII_BITS, 2, 2, 0, + "bsr", NULL, 0x61, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "btst", NULL, 0x0000, CLASS_VII, CLASS_VII_BITS, 2, 2, 0, + "bvc", NULL, 0x68, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "bvs", NULL, 0x69, CLASS_VI, CLASS_VI_BITS, 1, 1, 0, + "chk", NULL, 0x4180, CLASS_VIII, CLASS_VIII_BITS,2, 2, 0, + "clrb", NULL, 0x4200, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "clrl", NULL, 0x4280, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "clrw", NULL, 0x4240, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "cmpb", NULL, 0x0000, CLASS_X, CLASS_X_BITS, 2, 2, 0x0000, + "cmpl", NULL, 0x0080, CLASS_X, CLASS_X_BITS, 2, 2, 0xB1C0, + "cmpmb",NULL, 0xB108, CLASS_XI, CLASS_XI_BITS, 2, 2, 0, + "cmpml",NULL, 0xB188, CLASS_XI, CLASS_XI_BITS, 2, 2, 0, + "cmpmw",NULL, 0xB148, CLASS_XI, CLASS_XI_BITS, 2, 2, 0, + "cmpw", NULL, 0x0040, CLASS_X, CLASS_X_BITS, 2, 2, 0xB0C0, + "dbcc", NULL, 0x54C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbcs", NULL, 0x55C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbeq", NULL, 0x57C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbf", NULL, 0x51C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbge", NULL, 0x5CC8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbgt", NULL, 0x5EC8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbhi", NULL, 0x52C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dble", NULL, 0x5FC8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbls", NULL, 0x53C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dblt", NULL, 0x5DC8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbmi", NULL, 0x5BC8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbne", NULL, 0x56C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbpl", NULL, 0x5BC8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbra", NULL, 0x50C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbt", NULL, 0x50C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbvc", NULL, 0x58C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "dbvs", NULL, 0x59C8, CLASS_XII, CLASS_XII_BITS, 2, 2, 0, + "divs", NULL, 0x81C0, CLASS_VIII, CLASS_VIII_BITS,2, 2, 0, + "divu", NULL, 0x80C0, CLASS_VIII, CLASS_VIII_BITS,2, 2, 0, + "eorb", NULL, 0xB100, CLASS_XIII, CLASS_XIII_BITS,2, 2, 0x0A00, + "eorl", NULL, 0xB180, CLASS_XIII, CLASS_XIII_BITS,2, 2, 0x0A80, + "eorw", NULL, 0xB140, CLASS_XIII, CLASS_XIII_BITS,2, 2, 0x0A40, + "exg", NULL, 0xC100, CLASS_XIV, CLASS_XIV_BITS, 2, 2, 0, + "extl", NULL, 0x48C0, CLASS_XV, CLASS_XV_BITS, 1, 1, 0, + "extw", NULL, 0x4880, CLASS_XV, CLASS_XV_BITS, 1, 1, 0, + "illegal",NULL, 0x4AFC, CLASS_XVI, CLASS_XVI_BITS, 0, 0, 0, + "jmp", NULL, 0x4EC0, CLASS_XVII, CLASS_XVII_BITS,1, 1, 0, + "jsr", NULL, 0x4E80, CLASS_XVII, CLASS_XVII_BITS,1, 1, 0, + "lea", NULL, 0x41C0, CLASS_XVIII, CLASS_XVIII_BITS,2, 2, 0, + "link", NULL, 0x4E50, CLASS_XIX, CLASS_XIX_BITS, 2, 2, 0, + "lslb", NULL, 0xE100, CLASS_V, CLASS_V_BITS, 1, 2, 01, + "lsll", NULL, 0xE180, CLASS_V, CLASS_V_BITS, 1, 2, 01, + "lslw", NULL, 0xE140, CLASS_V, CLASS_V_BITS, 1, 2, 01, + "lsrb", NULL, 0xE000, CLASS_V, CLASS_V_BITS, 1, 2, 01, + "lsrl", NULL, 0xE080, CLASS_V, CLASS_V_BITS, 1, 2, 01, + "lsrw", NULL, 0xE040, CLASS_V, CLASS_V_BITS, 1, 2, 01, + "movb", NULL, 0x1000, CLASS_XX, CLASS_XX_BITS, 2, 2, 0x0000, + "moveb",NULL, 0x1000, CLASS_XX, CLASS_XX_BITS, 2, 2, 0x0000, + "movel",NULL, 0x2000, CLASS_XX, CLASS_XX_BITS, 2, 2, 0x2040, + "moveml",NULL, 0x48C0, CLASS_XXI, CLASS_XXI_BITS, 2, 17, 0, + "movemw",NULL, 0x4880, CLASS_XXI, CLASS_XXI_BITS, 2, 17, 0, + "movepl",NULL, 0x0148, CLASS_XXII, CLASS_XXII_BITS,2, 2, 0, + "movepw",NULL, 0x0108, CLASS_XXII, CLASS_XXII_BITS,2, 2, 0, + "moveq",NULL, 0x70, CLASS_XXIII, CLASS_XXIII_BITS,2, 2, 0, + "movesb",NULL, 0x0E00, CLASS_XXIV, CLASS_XXIV_BITS,2, 2, 0, + "movesl",NULL, 0x0E80, CLASS_XXIV, CLASS_XXIV_BITS,2, 2, 0, + "movesw",NULL, 0x0E40, CLASS_XXIV, CLASS_XXIV_BITS,2, 2, 0, + "movew",NULL, 0x3000, CLASS_XX, CLASS_XX_BITS, 2, 2, 0x3040, + "movl", NULL, 0x2000, CLASS_XX, CLASS_XX_BITS, 2, 2, 0x2040, + "movml",NULL, 0x48C0, CLASS_XXI, CLASS_XXI_BITS, 2, 17, 0, + "movmw",NULL, 0x4880, CLASS_XXI, CLASS_XXI_BITS, 2, 17, 0, + "movpl",NULL, 0x0148, CLASS_XXII, CLASS_XXII_BITS,2, 2, 0, + "movpw",NULL, 0x0108, CLASS_XXII, CLASS_XXII_BITS,2, 2, 0, + "movq", NULL, 0x70, CLASS_XXIII, CLASS_XXIII_BITS,2, 2, 0, + "movsb",NULL, 0x0E00, CLASS_XXIV, CLASS_XXIV_BITS,2, 2, 0, + "movsl",NULL, 0x0E80, CLASS_XXIV, CLASS_XXIV_BITS,2, 2, 0, + "movsw",NULL, 0x0E40, CLASS_XXIV, CLASS_XXIV_BITS,2, 2, 0, + "movw", NULL, 0x3000, CLASS_XX, CLASS_XX_BITS, 2, 2, 0x3040, + "muls", NULL, 0xC1C0, CLASS_VIII, CLASS_VIII_BITS,2, 2, 0, + "mulu", NULL, 0xC0C0, CLASS_VIII, CLASS_VIII_BITS,2, 2, 0, + "nbcd", NULL, 0x4800, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "negb", NULL, 0x4400, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "negl", NULL, 0x4480, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "negw", NULL, 0x4440, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "negxb",NULL, 0x4000, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "negxl",NULL, 0x4080, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "negxw",NULL, 0x4040, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "nop", NULL, 0x4E71, CLASS_XVI, CLASS_XVI_BITS, 0, 0, 0, + "notb", NULL, 0x4600, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "notl", NULL, 0x4680, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "notw", NULL, 0x4640, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "orb", NULL, 0x8000, CLASS_IV, CLASS_IV_BITS, 2, 2, 0x0000, + "orl", NULL, 0x8080, CLASS_IV, CLASS_IV_BITS, 2, 2, 0x0080, + "orw", NULL, 0x8040, CLASS_IV, CLASS_IV_BITS, 2, 2, 0x0040, + "pea", NULL, 0x4840, CLASS_XVII, CLASS_XVII_BITS,1, 1, 0, + "reset",NULL, 0x4E70, CLASS_XVI, CLASS_XVI_BITS, 0, 0, 0, + "rolb", NULL, 0xE100, CLASS_V, CLASS_V_BITS, 1, 2, 02, + "roll", NULL, 0xE180, CLASS_V, CLASS_V_BITS, 1, 2, 02, + "rolw", NULL, 0xE140, CLASS_V, CLASS_V_BITS, 1, 2, 02, + "rorb", NULL, 0xE000, CLASS_V, CLASS_V_BITS, 1, 2, 02, + "rorl", NULL, 0xE080, CLASS_V, CLASS_V_BITS, 1, 2, 02, + "rorw", NULL, 0xE040, CLASS_V, CLASS_V_BITS, 1, 2, 02, + "roxlb",NULL, 0xE100, CLASS_V, CLASS_V_BITS, 1, 2, 03, + "roxll",NULL, 0xE180, CLASS_V, CLASS_V_BITS, 1, 2, 03, + "roxlw",NULL, 0xE140, CLASS_V, CLASS_V_BITS, 1, 2, 03, + "roxrb",NULL, 0xE000, CLASS_V, CLASS_V_BITS, 1, 2, 03, + "roxrl",NULL, 0xE080, CLASS_V, CLASS_V_BITS, 1, 2, 03, + "roxrw",NULL, 0xE040, CLASS_V, CLASS_V_BITS, 1, 2, 03, + "rtd", NULL, 0x4E74, CLASS_XXV, CLASS_XXV_BITS, 1, 1, 0, + "rte", NULL, 0x4E73, CLASS_XVI, CLASS_XVI_BITS, 0, 0, 0, + "rtr", NULL, 0x4E77, CLASS_XVI, CLASS_XVI_BITS, 0, 0, 0, + "rts", NULL, 0x4E75, CLASS_XVI, CLASS_XVI_BITS, 0, 0, 0, + "sbcd", NULL, 0x8100, CLASS_I, CLASS_I_BITS, 2, 2, 0, + "scc", NULL, 0x54C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "scs", NULL, 0x55C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "seq", NULL, 0x57C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "sf", NULL, 0x51C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "sge", NULL, 0x5CC0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "sgt", NULL, 0x5EC0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "shi", NULL, 0x52C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "sle", NULL, 0x5FC0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "sls", NULL, 0x53C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "slt", NULL, 0x5DC0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "smi", NULL, 0x5BC0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "sne", NULL, 0x56C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "spl", NULL, 0x5AC0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "st", NULL, 0x50C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "stop", NULL, 0x4E72, CLASS_XXVII, CLASS_XXVII_BITS,1, 1, 0, + "subb", NULL, 0x9000, CLASS_II, CLASS_II_BITS, 2, 2, 0x0400, + "subl", NULL, 0x9080, CLASS_II, CLASS_II_BITS, 2, 2, 0x0480, + "subqb",NULL, 0x5100, CLASS_III, CLASS_III_BITS, 2, 2, 0, + "subql",NULL, 0x5180, CLASS_III, CLASS_III_BITS, 2, 2, 0, + "subqw",NULL, 0x5140, CLASS_III, CLASS_III_BITS, 2, 2, 0, + "subw", NULL, 0x9040, CLASS_II, CLASS_II_BITS, 2, 2, 0x0440, + "subxb",NULL, 0x9100, CLASS_I, CLASS_I_BITS, 2, 2, 0, + "subxl",NULL, 0x9180, CLASS_I, CLASS_I_BITS, 2, 2, 0, + "subxw",NULL, 0x9140, CLASS_I, CLASS_I_BITS, 2, 2, 0, + "svc", NULL, 0x58C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "svs", NULL, 0x59C0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "swap", NULL, 0x4840, CLASS_XV, CLASS_XV_BITS, 1, 1, 0, + "tas", NULL, 0x4AC0, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "trap", NULL, 0x4E40, CLASS_XXVIII, CLASS_XXVIII_BITS,1,1, 0, + "trapv",NULL, 0x4E76, CLASS_XVI, CLASS_XVI_BITS, 0, 0, 0, + "tstb", NULL, 0x4A00, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "tstl", NULL, 0x4A80, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "tstw", NULL, 0x4A40, CLASS_IX, CLASS_IX_BITS, 1, 1, 0, + "unlk", NULL, 0x4E58, CLASS_XXVI, CLASS_XXVI_BITS,1, 1, 0, + NULL, NULL, 0x0000, CLASS_XVI, 0, 0, 0, 0, +}; + +int operandClassTable[] = { /* indexed by operandKindType */ + EXPRESSION_OPND_BIT, + STRING_OPND_BIT, + BLOCK_OPND_BIT, + D_REGISTER_OPND_BIT, + A_REGISTER_OPND_BIT, + A_REGISTER_INDIRECT_OPND_BIT, + POSTINCREMENT_OPND_BIT, + PREDECREMENT_OPND_BIT, + DISPLACEMENT_OPND_BIT, + INDEXED_OPND_BIT, + PC_DISPLACEMENT_OPND_BIT, + PC_INDEXED_OPND_BIT, + IMMEDIATE_OPND_BIT, + ABSOLUTE_SHORT_OPND_BIT, + ABSOLUTE_LONG_OPND_BIT, + CC_REGISTER_OPND_BIT, + STATUS_REGISTER_OPND_BIT, + USP_REGISTER_OPND_BIT, + CONTROL_REGISTER_OPND_BIT, + SELECTED_OPND_BIT, + INDEX_SELECTED_OPND_BIT, +}; + +int actionsClassI(); +int actionsClassII(); +int actionsClassIII(); +int actionsClassIV(); +int actionsClassV(); +int actionsClassVI(); +int actionsClassVII(); +int actionsClassVIII(); +int actionsClassIX(); +int actionsClassX(); +int actionsClassXI(); +int actionsClassXII(); +int actionsClassXIII(); +int actionsClassXIV(); +int actionsClassXV(); +int actionsClassXVI(); +int actionsClassXVII(); +int actionsClassXVIII(); +int actionsClassXIX(); +int actionsClassXX(); +int actionsClassXXI(); +int actionsClassXXII(); +int actionsClassXXIII(); +int actionsClassXXIV(); +int actionsClassXXV(); +int actionsClassXXVI(); +int actionsClassXXVII(); +int actionsClassXXVIII(); + +/* indexed by opcodeClass */ +int (*instructionActionTable[])() = { + actionsClassI, + actionsClassII, + actionsClassIII, + actionsClassIV, + actionsClassV, + actionsClassVI, + actionsClassVII, + actionsClassVIII, + actionsClassIX, + actionsClassX, + actionsClassXI, + actionsClassXII, + actionsClassXIII, + actionsClassXIV, + actionsClassXV, + actionsClassXVI, + actionsClassXVII, + actionsClassXVIII, + actionsClassXIX, + actionsClassXX, + actionsClassXXI, + actionsClassXXII, + actionsClassXXIII, + actionsClassXXIV, + actionsClassXXV, + actionsClassXXVI, + actionsClassXXVII, + actionsClassXXVIII, +}; + +/* indexed by symbolUsageKindType */ +int validSymbolValues[NUM_OF_SYM_USAGES] = { + /* STRUCT_NAME_SYMBOL */ STRUCT_VALUE_BIT, + /* STRUCT_FIELD_SYMBOL */ FIELD_VALUE_BIT, + /* MACRO_SYMBOL */ MACRO_VALUE_BIT, + /* ARGUMENT_SYMBOL */ OPERAND_VALUE_BIT, + /* LABEL_SYMBOL */ ABSOLUTE_VALUE_BIT | RELOCATABLE_VALUE_BIT | + DATA_VALUE_BIT | BSS_VALUE_BIT, + /* EXTERNAL_SYMBOL */ ABSOLUTE_VALUE_BIT | RELOCATABLE_VALUE_BIT | + DATA_VALUE_BIT | BSS_VALUE_BIT | + UNDEFINED_VALUE_BIT, + /* VARIABLE_SYMBOL */ ABSOLUTE_VALUE_BIT | RELOCATABLE_VALUE_BIT | + DATA_VALUE_BIT | BSS_VALUE_BIT | + UNDEFINED_VALUE_BIT | + STRING_VALUE_BIT | OPERAND_VALUE_BIT | + CONDITION_VALUE_BIT, + /* MVARIABLE_SYMBOL */ ABSOLUTE_VALUE_BIT | RELOCATABLE_VALUE_BIT | + DATA_VALUE_BIT | BSS_VALUE_BIT | + UNDEFINED_VALUE_BIT | + STRING_VALUE_BIT | OPERAND_VALUE_BIT | + CONDITION_VALUE_BIT, + /* UNKNOWN_SYMBOL */ UNDEFINED_VALUE_BIT, + /* FUNCTION_SYMBOL */ FUNCTION_VALUE_BIT, + /* BUILT_IN_FUNCTION_SYMBOL */ BUILT_IN_FUNCTION_VALUE_BIT, + /* NESTED_UNKNOWN_SYMBOL */ UNDEFINED_VALUE_BIT, + /* DEFINE_SYMBOL */ OPERAND_VALUE_BIT, + /* MDEFINE_SYMBOL */ OPERAND_VALUE_BIT, + /* UNKNOWN_FUNCTION_SYMBOL */ UNDEFINED_VALUE_BIT, + /* UNKNOWN_MACRO_SYMBOL */ UNDEFINED_VALUE_BIT, +}; + +/* indexed by valueKindType */ +int valueBitTable[] = { + ABSOLUTE_VALUE_BIT, + DATA_VALUE_BIT, + RELOCATABLE_VALUE_BIT, + BSS_VALUE_BIT, + STRUCT_VALUE_BIT, + FIELD_VALUE_BIT, + MACRO_VALUE_BIT, + OPERAND_VALUE_BIT, + STRING_VALUE_BIT, + CONDITION_VALUE_BIT, + UNDEFINED_VALUE_BIT, + FUNCTION_VALUE_BIT, + BLOCK_VALUE_BIT, + BUILT_IN_FUNCTION_VALUE_BIT, + ARRAY_VALUE_BIT, + FAIL_BIT, +}; + + +codeRegionType absoluteCodeRegion; +codeRegionType relocatableCodeRegion; +codeRegionType *codeRegions[2] = { + &absoluteCodeRegion, + &relocatableCodeRegion +}; + +/* A predefined undefined value so we don't have to make a new one every + time we need one */ +valueType undefinedValueValue = { UNDEFINED_VALUE, 0, + EXPRESSION_OPND }; +valueType *UndefinedValue = &undefinedValueValue; + +valueType *addressModeBIF(); +valueType *applyBIF(); +valueType *atasciiBIF(); +valueType *atasciiColorBIF(); +valueType *debugModeOffBIF(); +valueType *debugModeOnBIF(); +valueType *emitModeOffBIF(); +valueType *emitModeOnBIF(); +valueType *getAddressRegisterBIF(); +valueType *getDataRegisterBIF(); +valueType *getIndexRegisterBIF(); +valueType *getRegisterBIF(); +valueType *getWLBIF(); +valueType *isARegisterBIF(); +valueType *isAbsoluteLongModeBIF(); +valueType *isAbsoluteModeBIF(); +valueType *isAbsoluteShortModeBIF(); +valueType *isAbsoluteValueBIF(); +valueType *isBlockBIF(); +valueType *isBuiltInFunctionBIF(); +valueType *isCCRegisterBIF(); +valueType *isConditionCodeBIF(); +valueType *isControlRegisterBIF(); +valueType *isDFCRegisterBIF(); +valueType *isDRegisterBIF(); +valueType *isDefinedBIF(); +valueType *isDisplacementModeBIF(); +valueType *isExternalBIF(); +valueType *isFieldBIF(); +valueType *isFunctionBIF(); +valueType *isImmediateModeBIF(); +valueType *isIndexedModeBIF(); +valueType *isIndirectModeBIF(); +valueType *isPCDisplacementModeBIF(); +valueType *isPCIndexedModeBIF(); +valueType *isPostincrementModeBIF(); +valueType *isPredecrementModeBIF(); +valueType *isRelocatableValueBIF(); +valueType *isSFCRegisterBIF(); +valueType *isStatusRegisterBIF(); +valueType *isStringBIF(); +valueType *isStructBIF(); +valueType *isSymbolBIF(); +valueType *isUSPBIF(); +valueType *isVBRegisterBIF(); +valueType *listingOffBIF(); +valueType *listingOnBIF(); +valueType *nthCharBIF(); +valueType *printfBIF(); +valueType *strcatBIF(); +valueType *strcmpBIF(); +valueType *strcmplcBIF(); +valueType *strlenBIF(); +valueType *substrBIF(); +valueType *symbolDefineBIF(); +valueType *symbolLookupBIF(); +valueType *symbolNameBIF(); +valueType *symbolUsageBIF(); +valueType *valueTypeBIF(); + +/* Used to initialize symbols representing built-in functions */ +struct { + stringType *functionName; + valueType *(*functionEntry)(); + bool isSpecialFunction; + } builtInFunctionTable[] = { + "addressMode", addressModeBIF, FALSE, + "apply", applyBIF, FALSE, + "atascii", atasciiBIF, FALSE, + "atasciiColor", atasciiColorBIF, FALSE, + "debugModeOff", debugModeOffBIF, FALSE, + "debugModeOn", debugModeOnBIF, FALSE, + "emitModeOff", emitModeOffBIF, FALSE, + "emitModeOn", emitModeOnBIF, FALSE, + "getAddressRegister", getAddressRegisterBIF, FALSE, + "getDataRegister", getDataRegisterBIF, FALSE, + "getIndexRegister", getIndexRegisterBIF, FALSE, + "getRegister", getRegisterBIF, FALSE, + "getWL", getWLBIF, FALSE, + "isARegister", isARegisterBIF, FALSE, + "isAbsoluteLongMode", isAbsoluteLongModeBIF, FALSE, + "isAbsoluteMode", isAbsoluteModeBIF, FALSE, + "isAbsoluteShortMode", isAbsoluteShortModeBIF, FALSE, + "isAbsoluteValue", isAbsoluteValueBIF, FALSE, + "isBlock", isBlockBIF, FALSE, + "isBuiltInFunction", isBuiltInFunctionBIF, FALSE, + "isCCRegister", isCCRegisterBIF, FALSE, + "isConditionCode", isConditionCodeBIF, FALSE, + "isControlRegister", isControlRegisterBIF, FALSE, + "isDFCRegister", isDFCRegisterBIF, FALSE, + "isDRegister", isDRegisterBIF, FALSE, + "isDefined", isDefinedBIF, TRUE, + "isDisplacementMode", isDisplacementModeBIF, FALSE, + "isExternal", isExternalBIF, TRUE, + "isField", isFieldBIF, FALSE, + "isFunction", isFunctionBIF, FALSE, + "isImmediateMode", isImmediateModeBIF, FALSE, + "isIndexedMode", isIndexedModeBIF, FALSE, + "isIndirectMode", isIndirectModeBIF, FALSE, + "isPCDisplacementMode", isPCDisplacementModeBIF,FALSE, + "isPCIndexedMode", isPCIndexedModeBIF, FALSE, + "isPostincrementMode", isPostincrementModeBIF, FALSE, + "isPredecrementMode", isPredecrementModeBIF, FALSE, + "isRelocatableValue", isRelocatableValueBIF, FALSE, + "isSFCRegister", isSFCRegisterBIF, FALSE, + "isStatusRegister", isStatusRegisterBIF, FALSE, + "isString", isStringBIF, FALSE, + "isStruct", isStructBIF, FALSE, + "isSymbol", isSymbolBIF, TRUE, + "isUSP", isUSPBIF, FALSE, + "isVBRegister", isVBRegisterBIF, FALSE, + "listingOff", listingOffBIF, FALSE, + "listingOn", listingOnBIF, FALSE, + "nthChar", nthCharBIF, FALSE, + "printf", printfBIF, FALSE, + "strcat", strcatBIF, FALSE, + "strcmp", strcmpBIF, FALSE, + "strcmplc", strcmplcBIF, FALSE, + "strlen", strlenBIF, FALSE, + "substr", substrBIF, FALSE, + "symbolDefine", symbolDefineBIF, FALSE, + "symbolLookup", symbolLookupBIF, FALSE, + "symbolName", symbolNameBIF, TRUE, + "symbolUsage", symbolUsageBIF, TRUE, + "valueType", valueTypeBIF, FALSE, + NULL, NULL, FALSE, +}; + +/* Used to initialize predefined symbols */ +struct { + stringType *symbolName; + int symbolValue; + } predefinedSymbolTable[] = { + "FALSE", 0, + "NULL", 0, + "TRUE", 1, + NULL, 0, +}; + +/* These define the temporary files used to hold scratch data used in the + generation of listings. The "XXXXXX"s get blasted by 'mktemp' */ +char pass2SourceFileName[] = "/tmp/zsourceXXXXXX"; +char pass2IndexFileName[] = "/tmp/zindexXXXXXX"; +char pass2MacroExpansionFileName[] = "/tmp/zmacroXXXXXX"; diff --git a/macrossTypes.h b/macrossTypes.h new file mode 100644 index 0000000..a12ae0b --- /dev/null +++ b/macrossTypes.h @@ -0,0 +1,1070 @@ +/* + macrossTypes.h -- Data type definitions for the Macross assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 1-November-1984 + +*/ + +#include + +/* + Stuff for sorting out which target processor we are going to be an + assembler for, this time around. +*/ + +/* TARGET_CPU gets defined as one of these on the 'cc' commmand line using + the "-D" option */ +#define CPU_6502 1 +#define CPU_68000 2 + +#if TARGET_CPU == CPU_6502 +#define OPERAND_DEFS "operandDefs_6502.h" +#define OPERAND_BODY "operandBody_6502.h" +#define CONDITION_DEFS "conditionDefs_6502.h" +#define TARGET_CPU_STRING "6502" + +#else if TARGET_CPU == CPU_68000 +#define OPERAND_DEFS "operandDefs_68000.h" +#define OPERAND_BODY "operandBody_68000.h" +#define CONDITION_DEFS "conditionDefs_68000.h" +#define TARGET_CPU_STRING "MC68000" + +#endif + +/* + General types -- These data types are just useful for dealing with the + world at large. +*/ + +typedef int nullType; /* for nothingness */ + +typedef char anyOldThing; /* for storage allocators */ + +typedef int bool; /* for logical operations */ +#define FALSE 0 +#define TRUE 1 + +typedef unsigned char byte; + +typedef unsigned short wordType; + +typedef unsigned long longType; + +typedef unsigned long bigWord; + +typedef union { /* lets us build or take */ + wordType wordPart; /* apart a word while */ + byte bytePart[2]; /* keeping control over */ + } byteToWordType;/* byte order. */ +/* which element of bytePart is the low order byte and which is the high + order byte is host-system dependent! */ + +typedef union { /* lets us build or take */ + longType longPart; /* apart a long while */ + byte bytePart[4]; /* keeping control over */ + } byteToLongType;/* byte order. */ +/* which element of bytePart is the low order byte and which is the high + order byte is host-system dependent! */ + +typedef char stringType; /* sometimes...because + although a char is not a +string, a pointer to a char *is* a pointer to a string and pointers are what +we care about. We never declare anything to be 'stringType' but we'll declare +lots of things 'stringType *' */ + +typedef long addressType; /* address on the target + processor, not the host + processor */ + +/* + Values: the values of Macross expressions, instruction operands, and so on + are kept track of internally using objects of 'valueType'. This is a + struct consisting of the value itself together with something telling what + kind of value it is (string, relocatable address, etc.) and what address + mode is associated with it (direct, indirect, etc.). + */ + +typedef enum { + ABSOLUTE_VALUE, DATA_VALUE, RELOCATABLE_VALUE, BSS_VALUE, + STRUCT_VALUE, FIELD_VALUE, MACRO_VALUE, OPERAND_VALUE, STRING_VALUE, + CONDITION_VALUE, UNDEFINED_VALUE, FUNCTION_VALUE, BLOCK_VALUE, + BUILT_IN_FUNCTION_VALUE, ARRAY_VALUE, FAIL + } valueKindType; +#define NUM_OF_VALUE_KINDS 16 /* C really could benefit from a + 'cardinality-of-enumerated-type' operator */ + +#define ABSOLUTE_VALUE_BIT 0x0001 +#define DATA_VALUE_BIT 0x0002 +#define RELOCATABLE_VALUE_BIT 0x0004 +#define BSS_VALUE_BIT 0x0008 +#define STRUCT_VALUE_BIT 0x0010 +#define FIELD_VALUE_BIT 0x0020 +#define MACRO_VALUE_BIT 0x0040 +#define OPERAND_VALUE_BIT 0x0080 +#define STRING_VALUE_BIT 0x0100 +#define CONDITION_VALUE_BIT 0x0200 +#define UNDEFINED_VALUE_BIT 0x0400 +#define FUNCTION_VALUE_BIT 0x0800 +#define BLOCK_VALUE_BIT 0x1000 +#define BUILT_IN_FUNCTION_VALUE_BIT 0x2000 +#define ARRAY_VALUE_BIT 0x4000 +#define FAIL_BIT 0x8000 + +#include OPERAND_DEFS + +typedef struct { + valueKindType kindOfValue; + int value; + operandKindType addressMode; + } valueType; + +typedef struct { + int arraySize; + valueType **arrayContents; + } arrayType; + +/* + Input files are kept track of using 'fileNameListType'. A linked list of + these structs is built with one entry for each input file given on the + command line. Include files are pushed onto the head of this list. Thus, + the standard action upon reading an EOF is to pop the list. When the list + is empty, we're done! + */ + +typedef struct fileNameListStruct { + char *name; + FILE *fildes; + bool openFlag; + int lineNumber; + struct fileNameListStruct *nextFileName; + } fileNameListType; + +typedef struct commandLineDefineStruct { + char *name; + int value; + struct commandLineDefineStruct *nextDefine; + } commandLineDefineType; + +/* + Internal tables +*/ + +/* Symbol table: all user-defined symbols are kept in the symbol table. Each + symbol has but one entry. Associated with each such entry is a list of + 'symbolInContextType's that contain information pertaining to particular + uses of individual symbols. This is how we handle scoping in function and + macro calls. */ + +typedef int symbolAttributesType; /* Symbol attributes */ +#define GLOBAL_ATT 0x01 /* are orthogonal to symbol */ +#define ZERO_PAGE_ATT 0x02 /* type */ +#define DEFINED_VARIABLE_ATT 0x04 +#define SYMBOL_USED_ATT 0x08 +#define SPECIAL_FUNCTION_ATT 0x10 +#define TENTATIVE_GLOBAL_ATT 0x20 + +typedef enum { + STRUCT_NAME_SYMBOL, STRUCT_FIELD_SYMBOL, MACRO_SYMBOL, + ARGUMENT_SYMBOL, LABEL_SYMBOL, EXTERNAL_SYMBOL, + VARIABLE_SYMBOL, MVARIABLE_SYMBOL, UNKNOWN_SYMBOL, + DEAD_SYMBOL, FUNCTION_SYMBOL, BUILT_IN_FUNCTION_SYMBOL, + NESTED_UNKNOWN_SYMBOL, DEFINE_SYMBOL, MDEFINE_SYMBOL, + UNKNOWN_FUNCTION_SYMBOL, UNKNOWN_MACRO_SYMBOL, + } symbolUsageKindType; +#define NUM_OF_SYM_USAGES 17 + +typedef struct symbolInContextStruct { + valueType *value; + symbolUsageKindType usage; + symbolAttributesType attributes; + int referenceCount; + struct symbolInContextStruct *pushedContexts; + int environmentNumber; + int definingLineNumber; + char *definingFileName; + } symbolInContextType; +#define GLOBAL_ENVIRONMENT_NUMBER 0 + +typedef struct environmentStruct { + int environmentNumber; + struct environmentStruct *previousEnvironment; + } environmentType; + +#define pushEnvironment(newEnv) {\ + newEnv.environmentNumber = nextEnvironmentNumber++;\ + newEnv.previousEnvironment = currentEnvironment;\ + currentEnvironment = &newEnv;\ + } + +#define popEnvironment() currentEnvironment = currentEnvironment->\ + previousEnvironment; + +typedef struct symbolTableEntryStruct { + stringType *symbolName; + struct symbolTableEntryStruct *nextSymbol; + symbolInContextType *context; + int ordinal; + int referenceCount; + } symbolTableEntryType; + +#define symbName(sptr) ((sptr)->symbolName) + +/* symbolClass bits */ +#define SYMBOL_UNDEFINED 0x00 +#define SYMBOL_ABSOLUTE 0x02 +#define SYMBOL_RELOCATABLE 0x04 +#define SYMBOL_EXTERNAL 0x01 + +typedef struct { + byte symbolClass; /* see above */ + int symbolValue; + } objectSymbolType; + +/* These structs are used to allow us to put symbols in the object file */ + +#define MODE_ABSOLUTE 0 +#define MODE_RELOCATABLE 1 + +#define REF_BYTE 0 +#define REF_WORD 1 +#define REF_DBYTE 2 +#define REF_LONG 3 + +typedef struct { + bigWord referenceAddress : 24, /* target machine address */ + referenceMode : 1, /* see above MODE_xx defines*/ + referenceRelative : 1, /* TRUE==is relative */ + referenceKind : 3, /* see above REF_xx defines */ + referenceExternal : 1, /* TRUE==is ref to external */ + : 2; /* unused bits */ + int referenceExpression; /* local expression ordinal */ + } expressionReferenceType; + +#define ExpressionType struct expressionTermStruct + +typedef struct expressionReferenceListStruct { + expressionReferenceType relocation; + struct expressionReferenceListStruct *nextReference; + ExpressionType *expressionReferenced; + } expressionReferenceListType; + +/* These are sort of 'forward references' to types used in the construction of + parse trees, but they are refered to by various internal tables and so have + to go here, rather than with the other parse-tree types. */ + +#define BlockType struct statementStruct + +#define IdentifierListType struct identifierListStruct +#define IdentifierListHeadType struct identifierListHeadStruct + +typedef symbolTableEntryType argumentType; + +typedef struct argumentDefinitionListStruct { + argumentType *theArgument; + struct argumentDefinitionListStruct *nextArgument; + } argumentDefinitionListType; + +typedef struct { + argumentType *theArgument; + argumentDefinitionListType *nextArgument; + argumentDefinitionListType *tail; + bool arrayTag; + } argumentListHeadType; + +/* Macros: */ +typedef struct macroTableEntryStruct { + stringType *macroName; + struct macroTableEntryStruct *nextMacro; + argumentDefinitionListType *arguments; + BlockType *body; + } macroTableEntryType; + +/* Functions: */ +typedef struct functionDefinitionStruct { + symbolTableEntryType *functionName; + argumentDefinitionListType *arguments; + BlockType *body; + int ordinal; + struct functionDefinitionStruct *nextExternalFunction; + } functionDefinitionType; + +typedef struct opcodeTableEntryStruct { + stringType *mnemonic; + struct opcodeTableEntryStruct *nextOpcode; + unsigned int opcode; + addressClassType addressClass; + int permissibleOperandModes; + int minNumberOfOperands; + int maxNumberOfOperands; + int subClass; + } opcodeTableEntryType; + +/* Macross keywords: */ +typedef struct keywordTableEntryStruct { + stringType *string; + struct keywordTableEntryStruct *nextKeyword; + int token; + } keywordTableEntryType; + +/* All the various things that are stored in tables, like keywords, symbols + and macro names, are stored with a common format to the head of the struct + that defines them, so that a set of generic table handling routines may be + written. These routines look at the following type: */ + +typedef struct genericTableEntryStruct { + stringType *string; + struct genericTableEntryStruct *next; + } genericTableEntryType; +/* + Parser types -- These data types define the parse-tree data structure + which is constructed during the parse phase of assembly. This is the form + in which statements are stored internally prior to being turned into + object code, as well as the form in which macros and functions are + remembered. + + The exposition of the types is by necessity bottom-up. That's C. +*/ + +typedef int postOpKindType; + +typedef struct { + postOpKindType postOp; + ExpressionType *postOpArgument; + } postOpTermType; + +typedef int preOpKindType; + +typedef struct { + preOpKindType preOp; + ExpressionType *preOpArgument; + } preOpTermType; + +typedef int unopKindType; + +typedef int binopKindType; + +typedef enum { + ASSIGN_ASSIGN, ADD_ASSIGN, SUB_ASSIGN, MUL_ASSIGN, DIV_ASSIGN, + MOD_ASSIGN, AND_ASSIGN, OR_ASSIGN, XOR_ASSIGN, + LEFT_SHIFT_ASSIGN, RIGHT_SHIFT_ASSIGN, NO_ASSIGN + } assignmentKindType; + +typedef struct { + unopKindType unop; + ExpressionType *unopArgument; + } unopTermType; + +typedef struct { + binopKindType binop; + ExpressionType *leftArgument; + ExpressionType *rightArgument; + } binopTermType; + +#define ExpressionListType struct expressionListStruct + +typedef struct { + ExpressionType *arrayName; + ExpressionType *arrayIndex; + } arrayTermType; + +typedef ExpressionType subexpressionTermType; + +typedef int numberTermType; + +#define OperandListType struct operandStruct + +typedef struct { + symbolTableEntryType *functionName; + OperandListType *parameters; + } functionCallTermType; + +typedef symbolTableEntryType identifierTermType; + +typedef nullType hereTermType; + +#include CONDITION_DEFS + +typedef struct conditionTableEntryStruct { + stringType *string; + struct conditionTableEntryStruct *nextCondition; + conditionType code; + } conditionTableEntryType; + +typedef conditionType conditionCodeTermType; + +typedef stringType stringTermType; + +typedef enum { + IDENTIFIER_EXPR, FUNCTION_CALL_EXPR, NUMBER_EXPR, + SUBEXPRESSION_EXPR, UNOP_EXPR, BINOP_EXPR, PREOP_EXPR, + POSTOP_EXPR, HERE_EXPR, ASSIGN_EXPR, CONDITION_CODE_EXPR, + STRING_EXPR, VALUE_EXPR, ARRAY_EXPR, + } expressionTermKindType; + +typedef union expressionTermBodyUnion { + identifierTermType *identifierUnion; + functionCallTermType *functionCallUnion; + numberTermType numberUnion; + conditionCodeTermType conditionCodeUnion; + subexpressionTermType *subexpressionUnion; + unopTermType *unopUnion; + binopTermType *binopUnion; + preOpTermType *preOpUnion; + postOpTermType *postOpUnion; + hereTermType *hereUnion; + stringTermType *stringUnion; + arrayTermType *arrayUnion; + valueType *valueUnion; + } expressionTermBodyType; + +typedef struct expressionTermStruct { + expressionTermKindType kindOfTerm; + expressionTermBodyType expressionTerm; + } expressionTermType; + +typedef expressionTermType expressionType; + +typedef enum { + BYTE_FIXUP, WORD_FIXUP, NO_FIXUP, OPERAND_FIXUP, + BYTE_RELATIVE_FIXUP, DBYTE_FIXUP, NO_FIXUP_OK, LONG_FIXUP, + WORD_RELATIVE_FIXUP, + } fixupKindType; + +typedef enum { + ABSOLUTE_BUFFER, RELOCATABLE_BUFFER, + } codeBufferKindType; +#define LAST_BUFFER_KIND ((int)RELOCATABLE_BUFFER) +#define STRUCT_BUFFER (LAST_BUFFER_KIND + 1) + +typedef struct fixupListStruct { + addressType locationToFixup; + codeBufferKindType codeMode; + fixupKindType kindOfFixup; + expressionType *theFixupExpression; + int targetOffset; + stringType *fileName; + int lineNumber; + struct fixupListStruct *nextFixup; + } fixupListType; + +typedef struct simpleFixupListStruct { + valueType locationToFixup; + struct simpleFixupListStruct *nextFixup; + } simpleFixupListType; + +typedef expressionType performStatementBodyType; + +typedef expressionType orgStatementBodyType; + +typedef expressionType targetStatementBodyType; + +typedef expressionType startStatementBodyType; + +typedef struct identifierListStruct { + symbolTableEntryType *theSymbol; + struct identifierListStruct *nextIdentifier; + } identifierListType; + +typedef struct identifierListHeadStruct { + symbolTableEntryType *theSymbol; + struct identifierListStruct *nextIdentifier; + identifierListType *tail; + } identifierListHeadType; + +typedef identifierListType externStatementBodyType; + +#define StatementListType struct statementStruct + +typedef BlockType structBodyType; + +typedef struct { + structBodyType *structBody; + symbolTableEntryType *structName; + } structStatementBodyType; + +typedef enum { + UNTIL_END, WHILE_END + } doEndKindType; + +typedef struct { + doEndKindType mdoEndKind; + expressionType *mdoEndCondition; + } mdoEndType; + +typedef struct { + expressionType *mdoUntilCondition; + BlockType *mdoUntilLoop; + } mdoUntilStatementBodyType; + +typedef struct { + expressionType *mdoWhileCondition; + BlockType *mdoWhileLoop; + } mdoWhileStatementBodyType; + +typedef struct { + expressionType *mwhileCondition; + BlockType *mwhileLoop; + } mwhileStatementBodyType; + +typedef struct { + expressionType *initExpression; + expressionType *testExpression; + expressionType *incrExpression; + } forExpressionsType; + +typedef struct { + expressionType *initExpression; + expressionType *testExpression; + expressionType *incrExpression; + BlockType *forLoop; + } mforStatementBodyType; + +#define MifStatementBodyType struct mifStatementBodyStruct + +typedef MifStatementBodyType mifContinuationBodyType; + +typedef union { + mifContinuationBodyType *mifContinuationBodyUnion; + BlockType *mifBlockUnion; + } mifContinuationType; + +typedef struct { + expressionType *headCondition; + BlockType *headBody; + } mifHeadType; + +typedef struct mifStatementBodyStruct { + expressionType *mifCondition; + BlockType *mifConsequence; + mifContinuationType mifContinuation; + } mifStatementBodyType; + +typedef identifierListType undefineStatementBodyType; + +typedef struct { + macroTableEntryType *theMacro; + argumentDefinitionListType *theArguments; + BlockType *theBlock; + } macroStatementBodyType; + +typedef struct { + stringType *functionName; + argumentDefinitionListType *theArguments; + BlockType *theBlock; + } functionStatementBodyType; + +typedef struct { + symbolTableEntryType *theSymbol; + expressionType *theValue; + } defineStatementBodyType; + +typedef struct { + symbolTableEntryType *theSymbol; + expressionType *theValue; + } mdefineStatementBodyType; + +typedef struct { + symbolTableEntryType *theSymbol; + ExpressionListType *theValue; + expressionType *theDimension; + } variableStatementBodyType; + +typedef struct { + symbolTableEntryType *theSymbol; + ExpressionListType *theValue; + expressionType *theDimension; + } mvariableStatementBodyType; + +typedef identifierListType selectionListType; +typedef identifierListHeadType selectionListHeadType; + +#include OPERAND_BODY + +typedef struct operandStruct { + operandKindType kindOfOperand; + operandBodyType theOperand; + struct operandStruct *nextOperand; + } operandType; + +typedef struct { + operandKindType kindOfOperand; + valueType *theOperand; + } operandValueType; + +typedef expressionType freturnStatementBodyType; + +typedef operandType operandListType; + +typedef struct { + operandKindType kindOfOperand; + operandBodyType theOperand; + operandListType *nextOperand; + operandListType *tail; + } operandListHeadType; + +typedef union { + opcodeTableEntryType *opcodeUnion; + macroTableEntryType *macroUnion; + } instructionType; + +typedef enum { + OPCODE_INSTRUCTION, MACRO_INSTRUCTION + } instructionKindType; + +typedef struct { + instructionKindType kindOfInstruction; + instructionType theInstruction; + operandListType *theOperands; + } instructionStatementBodyType; + +typedef expressionType includeStatementBodyType; + +typedef struct expressionListStruct { + expressionType *theExpression; + struct expressionListStruct *nextExpression; + } expressionListType; + +typedef struct { + expressionType *theExpression; + expressionListType *nextExpression; + expressionListType *tail; + } expressionListHeadType; + +typedef expressionListType stringStatementBodyType; + +typedef expressionListType byteStatementBodyType; + +typedef expressionListType dbyteStatementBodyType; + +typedef expressionType alignStatementBodyType; + +typedef expressionListType wordStatementBodyType; + +typedef expressionListType longStatementBodyType; + +typedef struct { + doEndKindType doEndKind; + conditionType doEndCondition; + } doEndType; + +typedef struct { + conditionType doUntilCondition; + BlockType *doUntilLoop; + } doUntilStatementBodyType; + +typedef struct { + conditionType doWhileCondition; + BlockType *doWhileLoop; + } doWhileStatementBodyType; + +typedef struct { + conditionType whileCondition; + BlockType *whileLoop; + } whileStatementBodyType; + +#define IfStatementBodyType struct ifStatementBodyStruct + +typedef enum { + NO_CONTINUATION, ELSE_CONTINUATION, ELSEIF_CONTINUATION + } ifContinuationKindType; + +typedef IfStatementBodyType ifContinuationBodyType; + +typedef union { + ifContinuationBodyType *continuationBodyUnion; + BlockType *blockUnion; + } ifContinuationType; + +typedef struct { + conditionType headCondition; + BlockType *headBody; + } ifHeadType; + +typedef struct ifStatementBodyStruct { + conditionType ifCondition; + BlockType *consequence; + ifContinuationType continuation; + } ifStatementBodyType; + +typedef struct { + expressionType *constraint; + BlockType *constrainedBlock; + } constrainStatementBodyType; + +typedef struct { + expressionType *condition; + expressionType *message; + } assertStatementBodyType; + +typedef struct { + expressionListType *caseTags; + BlockType *caseBody; + } caseType; + +typedef struct caseListStruct { + caseType *theCase; + struct caseListStruct *nextCase; + } caseListType; + +typedef struct { + caseType *theCase; + caseListType *nextCase; + caseListType *tail; + } caseListHeadType; + +typedef struct { + expressionType *switchExpression; + caseListType *cases; + } mswitchStatementBodyType; + +typedef nullType relStatementBodyType; + +typedef expressionListType blockStatementBodyType; + +typedef BlockType groupStatementBodyType; + +typedef union { + ifStatementBodyType *ifUnion; + whileStatementBodyType *whileUnion; + doWhileStatementBodyType *doWhileUnion; + doUntilStatementBodyType *doUntilUnion; + wordStatementBodyType *wordUnion; + dbyteStatementBodyType *dbyteUnion; + byteStatementBodyType *byteUnion; + stringStatementBodyType *stringUnion; + blockStatementBodyType *blockUnion; + structStatementBodyType *structUnion; + instructionStatementBodyType *instructionUnion; + defineStatementBodyType *defineUnion; + mdefineStatementBodyType *mdefineUnion; + variableStatementBodyType *variableUnion; + mvariableStatementBodyType *mvariableUnion; + macroStatementBodyType *macroUnion; + functionStatementBodyType *functionUnion; + undefineStatementBodyType *undefineUnion; + mifStatementBodyType *mifUnion; + freturnStatementBodyType *freturnUnion; + mforStatementBodyType *mforUnion; + mwhileStatementBodyType *mwhileUnion; + mdoWhileStatementBodyType *mdoWhileUnion; + mdoUntilStatementBodyType *mdoUntilUnion; + includeStatementBodyType *includeUnion; + externStatementBodyType *externUnion; + startStatementBodyType *startUnion; + alignStatementBodyType *alignUnion; + orgStatementBodyType *orgUnion; + targetStatementBodyType *targetUnion; + relStatementBodyType *relUnion; + performStatementBodyType *performUnion; + groupStatementBodyType *groupUnion; + constrainStatementBodyType *constrainUnion; + assertStatementBodyType *assertUnion; + mswitchStatementBodyType *mswitchUnion; + longStatementBodyType *longUnion; + } statementBodyType; + +typedef enum { + IF_STATEMENT, WHILE_STATEMENT, DO_WHILE_STATEMENT, + DO_UNTIL_STATEMENT, WORD_STATEMENT, DBYTE_STATEMENT, + BYTE_STATEMENT, STRING_STATEMENT, STRUCT_STATEMENT, + INSTRUCTION_STATEMENT, DEFINE_STATEMENT, + UNDEFINE_STATEMENT, MIF_STATEMENT, + FRETURN_STATEMENT, MFOR_STATEMENT, MDO_WHILE_STATEMENT, + MDO_UNTIL_STATEMENT, INCLUDE_STATEMENT, EXTERN_STATEMENT, + START_STATEMENT, ALIGN_STATEMENT, ORG_STATEMENT, + REL_STATEMENT, PERFORM_STATEMENT, BLOCK_STATEMENT, + MWHILE_STATEMENT, MDEFINE_STATEMENT, NULL_STATEMENT, + GROUP_STATEMENT, MACRO_STATEMENT, FUNCTION_STATEMENT, + VARIABLE_STATEMENT, MVARIABLE_STATEMENT, CONSTRAIN_STATEMENT, + ASSERT_STATEMENT, MSWITCH_STATEMENT, LONG_STATEMENT, + TARGET_STATEMENT, + } statementKindType; + +typedef struct labelStruct { + symbolTableEntryType *theLabel; + struct labelStruct *nextLabel; + } labelType; + +typedef labelType labelListType; + +typedef struct { + symbolTableEntryType *theLabel; + labelListType *nextLabel; + labelListType *tail; + } labelListHeadType; + +typedef struct statementStruct { + statementKindType kindOfStatement; + labelListType *labels; + statementBodyType statementBody; + struct statementStruct *nextStatement; + stringType *fileName; + int lineNumber; + int cumulativeLineNumber; + } statementType; + +typedef statementType statementListType; + +typedef statementListType blockType; + +typedef struct { + statementKindType kindOfStatement; + labelListType *labels; + statementBodyType statementBody; + statementListType *nextStatement; + stringType *fileName; + int lineNumber; + int cumulativeLineNumber; + statementListType *tail; + } statementListHeadType; + +typedef statementListType programType; + +/* End of parse-tree types */ + + +#define UNASSIGNED NULL + +#define MAX_NAME_SIZE 300 + + +/* Struct instances */ + +#define MAXIMUM_ALLOWED_STRUCT_SIZE 255 + +typedef struct { + int structSize; + byte *structMap; + fixupListType *structFixups; + expressionReferenceListType *structReferences; + } structInstanceType; + + +/* Code output buffers */ + +#define CODE_BUFFER_SIZE 1024 +#if TARGET_CPU == CPU_6502 +#define CODE_BUFFERS_IN_ADDRESS_SPACE 64 + +#else if TARGET_CPU == CPU_68000 +#define CODE_BUFFERS_IN_ADDRESS_SPACE 256 + +#endif + +#define bufferNumber(addr) ((addr)/CODE_BUFFER_SIZE) +#define bufferPosition(addr) ((addr)%CODE_BUFFER_SIZE) + +typedef byte codeBufferType[CODE_BUFFER_SIZE]; + +typedef enum { + BREAK_BREAK, ALIGN_BREAK, CONSTRAIN_BREAK, + END_CONSTRAIN_BREAK, + } codeBreakKindType; + +typedef struct codeBreakStruct { + codeBreakKindType kindOfBreak; + addressType breakAddress; + int breakData; + struct codeBreakStruct *nextBreak; + } codeBreakType; + +typedef struct { + addressType codeStartAddress; + addressType codeEndAddress; + codeBufferType *codeBuffer; + } codeSegmentType; + +typedef struct { + addressType regionStartAddress; + addressType regionEndAddress; + codeSegmentType *codeSegments[ + CODE_BUFFERS_IN_ADDRESS_SPACE]; + } codeRegionType; + +typedef struct reservationListStruct { + addressType startAddress; + int blockSize; + struct reservationListStruct *nextReservation; + } reservationListType; + +#define LINE_BUFFER_SIZE 300 + +/* Error types */ + +typedef enum { + DEFINE_ASSIGNMENT_WRONG_ERROR, + DIGIT_OUT_OF_RADIX_ERROR, + UNCLOSED_CHARACTER_CONSTANT_ERROR, + UNCLOSED_STRING_CONSTANT_ERROR, + OCTAL_CHARACTER_TOO_BIG_ERROR, + UNRECOGNIZED_SOMETHING_OR_OTHER_ERROR, + UNCLOSED_COMMENT_ERROR, + UNCLOSED_LINE_COMMENT_ERROR, + UNABLE_TO_OPEN_PASS_2_FILE_ERROR, + BAD_ORG_ADDRESS_ERROR, + NEGATIVE_BLOCK_SIZE_ERROR, + UNASSIGNABLE_SYMBOL_TYPE_ERROR, + INCOMPATIBLE_ASSIGNMENT_OPERANDS_ERROR, + INCOMPATIBLE_BINOP_OPERANDS_ERROR, + UNPOSTINCREMENTABLE_OPERAND_ERROR, + UNPOSTDECREMENTABLE_OPERAND_ERROR, + UNPREINCREMENTABLE_OPERAND_ERROR, + UNPREDECREMENTABLE_OPERAND_ERROR, + INCOMPATIBLE_UNOP_OPERAND_ERROR, + VALUE_IS_NOT_AN_ADDRESS_ERROR, + VALUE_IS_NOT_AN_INT_ERROR, + IMPROPER_ALIGNMENT_VALUE_ERROR, + OPERATOR_ASSIGNMENT_ON_NULL_TARGET_ERROR, + TOO_MANY_INSTRUCTION_OPERANDS_ERROR, + ILLEGAL_OPERAND_TYPE_ERROR, + BYTE_VALUE_TOO_LARGE_ERROR, + WORD_VALUE_TOO_LARGE_ERROR, + BAD_INSTRUCTION_OPERAND_ERROR, + DIVIDE_BY_ZERO_ERROR, + UNDEFINED_SYMBOL_ERROR, + RELATIVE_OFFSET_TOO_LARGE_ERROR, + LABEL_ALREADY_DEFINED_ERROR, + CANT_OPEN_OBJECT_FILE_ERROR, + BAD_KIND_OF_SYMBOL_TO_MAKE_EXTERNAL_ERROR, + MORE_THAN_ONE_OUTPUT_FILE_ERROR, + BAD_COMMAND_LINE_FLAG_ERROR, + NO_DASH_O_FILE_NAME_ERROR, + UNABLE_TO_OPEN_INPUT_FILE_ERROR, + UNABLE_TO_OPEN_INCLUDE_FILE_ERROR, + INVALID_BOOLEAN_VALUE_ERROR, + SYMBOL_ALREADY_THERE_ERROR, + UNDECLARED_VARIABLE_ERROR, + REDEFINITION_OF_SYMBOL_ERROR, + NOT_A_STRUCT_NAME_ERROR, + STRUCT_TOO_BIG_ERROR, + FIELD_ALREADY_DEFINED_ERROR, + STRUCT_DEFINITION_INSIDE_STRUCT_DEFINITION_ERROR, + VALUE_IS_NOT_A_FIELD_ERROR, + MACRO_ALREADY_EXISTS_ERROR, + MACRO_DEFINITION_INSIDE_MACRO_ERROR, + TOO_MANY_ARGUMENTS_TO_MACRO_ERROR, + FUNCTION_DEFINITION_INSIDE_FUNCTION_ERROR, + FUNCTION_ALREADY_EXISTS_ERROR, + TOO_MANY_ARGUMENTS_TO_FUNCTION_ERROR, + NOT_A_FUNCTION_ERROR, + FUNCTION_DID_NOT_RETURN_A_VALUE_ERROR, + BAD_ADDRESS_MODE_ERROR, + MULTIPLE_ADDRESS_MODES_ERROR, + INCLUDE_FILE_NOT_A_STRING_VALUE_ERROR, + START_ADDRESS_ALREADY_GIVEN_ERROR, + FUNCTION_IS_NOT_A_VALUE_ERROR, + SIDE_EFFECT_ERROR, + CANT_FIND_SYMBOL_ERROR, + ERROR_INSIDE_MACRO_ERROR, + ERROR_INSIDE_FUNCTION_ERROR, + NO_LIST_FILE_NAME_ERROR, + NO_SYMBOL_DUMP_FILE_NAME_ERROR, + MORE_THAN_ONE_LIST_FILE_ERROR, + MORE_THAN_ONE_SYMBOL_DUMP_FILE_ERROR, + CANT_OPEN_LIST_FILE_ERROR, + CANT_OPEN_SYMBOL_DUMP_FILE_ERROR, + FILE_NAME_IS_NOT_MACROSS_SOURCE_ERROR, + OUTPUT_FILE_NAME_IS_MACROSS_SOURCE_ERROR, + LIST_FILE_NAME_IS_MACROSS_SOURCE_ERROR, + SYMBOL_DUMP_FILE_NAME_IS_MACROSS_SOURCE_ERROR, + INVALID_CONSTRAINT_VALUE_ERROR, + CONSTRAINT_ERROR, + UNASSIGNED_SYMBOL_ERROR, + BAD_START_ADDRESS_ERROR, + ALIGN_INSIDE_CONSTRAIN_ERROR, + CONSTRAIN_INSIDE_CONSTRAIN_ERROR, + NON_ADDRESS_WORD_VALUE_ERROR, + NON_ADDRESS_BYTE_VALUE_ERROR, + TOO_FEW_INSTRUCTION_OPERANDS_ERROR, + BAD_COLOR_ARGUMENT_TO_ATASCII_COLOR_ERROR, + PRINTF_FORMAT_IS_NOT_A_STRING_ERROR, + BIF_NTH_ARGUMENT_IS_NOT_A_STRING_ERROR, /* name, # */ + NO_ARGUMENTS_TO_BIF_ERROR, /* name */ + BIF_ARGUMENT_IS_NOT_A_STRING_ERROR, /* name */ + TOO_FEW_ARGUMENTS_TO_BIF_ERROR, /* name */ + BIF_NTH_ARGUMENT_IS_NOT_ABSOLUTE_VALUE_ERROR, /* name, # */ + BAD_SUBSTRING_INDICES_ERROR, + INVALID_ASSERT_CONDITION_ERROR, + INVALID_ASSERT_MESSAGE_ERROR, + ASSERT_WITH_MESSAGE_ERROR, + ASSERT_ERROR, + INVALID_SWITCH_VALUE_KIND, + INVALID_CASE_VALUE_KIND, + CANT_FORWARD_REFERENCE_BLOCK_ERROR, + MACRO_EXPANSION_WITHOUT_LISTING_ERROR, + INAPPROPRIATE_ADDRESS_MODES_ERROR, + CANT_DO_BYTE_ADDRESS_OP_ERROR, + QUICK_DATA_OUT_OF_RANGE_ERROR, + CCR_OP_IS_BYTE_OP_ERROR, + SR_OP_IS_WORD_OP_ERROR, + SHIFT_OP_IS_WORD_OP_ERROR, + CMP_ADDRESS_NOT_BYTE_OP_ERROR, + USP_MOVE_IS_LONG_OP_ERROR, + CCR_MOVE_IS_WORD_OP_ERROR, + SR_MOVE_IS_WORD_OP_ERROR, + CR_MOVE_IS_LONG_OP_ERROR, + ADDRESS_MOVE_NOT_BYTE_OP_ERROR, + TRAP_DATA_TOO_LARGE_ERROR, + RELATIVE_OFFSET_VALUE_TOO_LARGE_ERROR, + CANT_DO_OP_FROM_A_REGISTER_ERROR, + FORWARD_REFERENCE_NOT_ALLOWED_HERE_ERROR, + ADDRESS_OUTSIDE_ADDRESS_SPACE_ERROR, + APPLY_ARGUMENT_IS_NOT_MACRO_ERROR, + CANT_TARGET_IN_RELOCATABLE_MODE_ERROR, + BAD_TARGET_ADDRESS_ERROR, + UNDEFINED_MACRO_ERROR, + BAD_POSITION_ARGUMENT_TO_NTH_CHAR_ERROR, + SYMBOL_DEFINE_VALUE_NOT_EXPRESSION_OPND_ERROR, + ATTEMPT_TO_INDEX_NON_ARRAY_ERROR, + NON_INTEGER_INDEX_ERROR, + ARRAY_INDEX_OUT_OF_RANGE_ERROR, + TOO_MANY_VARIABLE_INITIALIZERS_ERROR, + NEGATIVE_ARRAY_INDEX_ERROR, + NON_ADDRESS_LONG_VALUE_ERROR, + CANT_POSTPREOP_STRING_ERROR, + NON_CHARACTER_STRING_ASSIGNMENT_ERROR, + NEGATIVE_ARRAY_SIZE_TO_MAKEARRAY_ERROR, + TOO_MANY_INITIALIZATION_ARGS_TO_MAKEARRAY_ERROR, + VALUELESS_ARRAY_ELEMENT_ERROR, + CANT_USE_PREOP_WITH_FORWARD_REFERENCE_ERROR, + CANT_USE_POSTOP_WITH_FORWARD_REFERENCE_ERROR, + CANT_USE_ASSIGNMENT_WITH_FORWARD_REFERENCE_ERROR, + TOO_MANY_ERRORS_ERROR, + EXPRESSION_TOO_BIG_TO_FIT_IN_OBJECT_ERROR, + FUNNY_ASSIGNMENT_KIND_IN_OBJECT_EXPRESSION_ERROR, + TEMP_SYMBOL_IN_OBJECT_ERROR, + } errorTypeX; +typedef enum {/* horrible kludge due to C compiler bug on Sun */ + BLOCK_OPERAND_IN_OBJECT_EXPRESSION_ERROR = + (int)TEMP_SYMBOL_IN_OBJECT_ERROR + 1, + REGISTER_OPERAND_IN_OBJECT_EXPRESSION_ERROR, + SELECTION_OPERAND_IN_OBJECT_EXPRESSION_ERROR, + WRONG_KIND_OF_VALUE_IN_OBJECT_EXPRESSION_ERROR, + ARRAY_TERM_IN_OBJECT_EXPRESSION_ERROR, + ILLEGAL_STATEMENT_IN_OBJECT_FILE_FUNCTION_ERROR, + ARRAY_MVARIABLE_IN_OBJECT_FUNCTION_ERROR, + BUILT_IN_FUNCTION_NOT_AVAILABLE_IN_OBJECT_ERROR, + NO_DASH_D_FILE_NAME_ERROR, + BAD_COMMAND_LINE_DEFINE_ERROR, + PERFORM_WITHOUT_SIDE_EFFECT_ERROR, + } errorType; + +#define ERROR_LIMIT 300 + +/* Misc. macros: */ + +#define qfree(thing) if (freeFlag) free(thing); +#define qsfree(thing) if (freeFlag&&statementEvaluationDepth<=1)free(thing); +#define toLowerCase(c) (lowerCaseCharacterTable[(c)]) +#define dupValue(new, v) {(new)=typeAlloc(valueType);*(new)= *(v);} +#define amListing() (listingOn && !listingControlCounter) +#define amExpanding() (expandMacros && !beneathFunction && \ + macroCallDepth > 0) +#define expand(x) if(amExpanding()){x;} + +#define EXPAND 1 +/* Boy, is this macro useful! */ + +#define typeAlloc(type) (type *)malloc(sizeof(type)) diff --git a/macross_6502.y b/macross_6502.y new file mode 100644 index 0000000..c149e4c --- /dev/null +++ b/macross_6502.y @@ -0,0 +1,1202 @@ +/* + macross.y -- Grammar and semantic rules for Macross parser + + Chip Morningstar -- Lucasfilm Ltd. + + 1-November-1984 + +*/ +%{ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +%} + +/* Token list is target system dependent */ +%token A ALIGN ASSERT BLOCK BYTE CONSTRAIN DBYTE DEFINE DO ELSE ELSEIF +%token ENDFILE EOL EXTERN FRETURN FUNCTION HERE IF INCLUDE LONG MACRO MCASE +%token MDEFAULT MDEFINE MDO MELSE MELSEIF MFOR MIF MSWITCH MUNTIL MVARIABLE +%token MWHILE ORG REL START STRING STRUCT TARGET UNDEFINE UNTIL VARIABLE +%token WHILE WORD X Y +%token ConditionCode Identifier MacroName Number Opcode TextString + +/* funny characters used literally: + + : , @ ( ) { } [ ] + +*/ + +%right ASSIGN /* = += *= -= /= %= <<= >>= &= |= + ^= */ +%left LOGICAL_OR /* || */ +%left LOGICAL_XOR /* ^^ */ +%left LOGICAL_AND /* && */ +%left BITWISE_OR /* | */ +%left BITWISE_XOR /* ^ */ +%left BITWISE_AND /* & */ +%nonassoc EQUAL_TO NOT_EQUAL_TO /* == != */ +%nonassoc LESS_THAN LESS_THAN_OR_EQUAL_TO GREATER_THAN GREATER_THAN_OR_EQUAL_TO + /* < <= > >= */ +%nonassoc '[' +%left LEFT_SHIFT RIGHT_SHIFT /* << >> */ +%left ADD SUB /* + - */ +%left MUL DIV MOD /* * / % */ +%right UNARY_MINUS LOGICAL_NOT BITWISE_NOT HI_BYTE LO_BYTE + /* - ! ~ ? / */ +%left SELECT /* . */ +%token INCREMENT DECREMENT /* ++ -- */ + +%% + +/* + In what follows, the comment "da" indicates that we are taking the default + action: + $$ = $1; + If this comment is not present, then then we intend there to be no action + even though yacc will give us the default. (The author's stylistic + tendencies being what they are, the default would have been entered + wherever it was intended, but this was found to clutter up the listing + excessively. +*/ + +program: beginProgram statementList EOL ENDFILE +{ + $$ = $2; +} + | ENDFILE +{ + $$ = 0; +} + ; + +beginProgram: /* null string */ +{ + statementListNestingDepth = 0; + errorFlag = FALSE; +} + ; + +/* "_" represents an optional newline (i.e., a whitespace newline as opposed + to an end-of-statement newline */ +_: eolList + | /* null string */ + ; + +eolList: EOL +{ + if (amListing()) + saveEOLForListing(); +} + | eolList EOL +{ + if (amListing()) + saveEOLForListing(); +} + ; + +statementList: statement +{ + if (statementListNestingDepth == 0) { + $$ = eatStatement($1); + } else { + $$ = buildStatementList($1, NULL); + } +} + | statementList EOL statement +{ + if (statementListNestingDepth == 0) { + $$ = eatStatement($3); + } else { + $$ = buildStatementList($3, $1); + } +} + ; + +statement: labeledStatement /* da */ + | unlabeledStatement /* da */ + | error ENDFILE +{ + $$ = NULL; + YYACCEPT; +} + | error +{ + yyerrok; + yyclearin; + resynchronizeInput(); + $$ = NULL; +} + ; + +labeledStatement: + labelList labelableStatement +{ + $$ = addLabelToStatement($1, $2); +} + ; + +unlabeledStatement: + labelableStatement /* da */ + ; + +labelList: label +{ + $$ = buildLabelList($1, NULL); +} + | labelList label +{ + $$ = buildLabelList($2, $1); +} + ; + +label: Identifier ':' +{ + $$ = lookupOrEnterSymbol($1, LABEL_SYMBOL); +} + | Identifier ':' ':' +{ + $$ = lookupOrEnterSymbol($1, LABEL_SYMBOL); + addAttributeToSymbol($$, TENTATIVE_GLOBAL_ATT); +} + ; + +labelableStatement: + ifStatement /* da */ + | whileStatement /* da */ + | doStatement /* da */ + | wordStatement /* da */ + | dbyteStatement /* da */ + | byteStatement /* da */ + | blockStatement /* da */ + | stringStatement /* da */ + | nullStatement /* da */ + | structStatement /* da */ + | performStatement /* da */ + | instructionStatement /* da */ + | groupStatement /* da */ + | defineStatement /* da */ + | macroDefineStatement /* da */ + | variableStatement /* da */ + | macroVariableStatement /* da */ + | macroStatement /* da */ + | functionStatement /* da */ + | functionReturnStatement /* da */ + | undefineStatement /* da */ + | macroIfStatement /* da */ + | macroWhileStatement /* da */ + | macroDoStatement /* da */ + | macroForStatement /* da */ + | macroSwitchStatement /* da */ + | includeStatement /* da */ + | externStatement /* da */ + | startStatement /* da */ + | alignStatement /* da */ + | orgStatement /* da */ + | relStatement /* da */ + | constrainStatement /* da */ + | assertStatement /* da */ + | longStatement /* da */ + | targetStatement /* da */ + ; + +ifStatement: IF _ ifHead +{ + $$ = buildIfStatement($3, NULL, NO_CONTINUATION); +} + | IF _ ifHead elsePart +{ + $$ = buildIfStatement($3, $4, ELSE_CONTINUATION); +} + | IF _ ifHead elseIf +{ + $$ = buildIfStatement($3, $4, ELSEIF_CONTINUATION); +} + ; + +ifHead: condition _ block +{ + $$ = buildIfHead($1, $3); +} + ; + +condition: '(' _ conditionExpression _ ')' +{ + $$ = $3; +} + ; + +conditionExpression: + ConditionCode /* da */ + | LOGICAL_NOT conditionExpression +{ + $$ = invertConditionCode($2); +} + | '(' _ conditionExpression _ ')' +{ + $$ = $3; +} + ; + +elsePart: ELSE _ block +{ + $$ = $3; +} + ; + +elseIf: ELSE _ ifStatement +{ + $$ = extractIfBody($3); +} + | ELSEIF _ ifHead +{ + $$ = extractIfBody(buildIfStatement($3, NULL, NO_CONTINUATION)); +} + | ELSEIF _ ifHead elsePart +{ + $$ = extractIfBody(buildIfStatement($3, $4, ELSE_CONTINUATION)); +} + | ELSEIF _ ifHead elseIf +{ + $$ = extractIfBody(buildIfStatement($3, $4, ELSEIF_CONTINUATION)); +} + ; + +whileStatement: WHILE _ condition _ block +{ + $$ = buildWhileStatement($3, $5); +} + ; + +doStatement: DO _ block _ doEnd +{ + $$ = buildDoStatement($3, $5); +} + ; + +doEnd: WHILE _ condition +{ + $$ = buildDoEnd($3, WHILE_END); +} + | UNTIL _ condition +{ + $$ = buildDoEnd($3, UNTIL_END); +} + ; + +wordStatement: WORD _ expressionList +{ + $$ = buildWordStatement($3); +} + ; + +longStatement: LONG _ expressionList +{ + $$ = buildLongStatement($3); +} + ; + +expressionList: expression +{ + $$ = buildExpressionList($1, NULL); +} + | expressionList ',' _ expression +{ + $$ = buildExpressionList($4, $1); +} + ; + +constrainStatement: + CONSTRAIN _ '(' _ expression _ ')' _ block +{ + $$ = buildConstrainStatement($5, $9); +} + ; + +assertStatement: + ASSERT _ '(' _ expression _ ')' expression +{ + $$ = buildAssertStatement($5, $8); +} + | ASSERT _ '(' _ expression _ ')' +{ + $$ = buildAssertStatement($5, NULL); +} + ; + +dbyteStatement: DBYTE _ expressionList +{ + $$ = buildDbyteStatement($3); +} + ; + +byteStatement: BYTE _ expressionList +{ + $$ = buildByteStatement($3); +} + ; + +blockStatement: BLOCK _ expressionList +{ + $$ = buildBlockStatement($3); +} + ; + +stringStatement: + STRING _ expressionList +{ + $$ = buildStringStatement($3); +} + ; + +structStatement: + STRUCT _ structName +{ + $$ = buildStructStatement($3, NULL); +} + | STRUCT _ structBody _ structName +{ + $$ = buildStructStatement($5, $3); +} + ; + +structName: Identifier +{ + $$ = lookupOrEnterSymbol($1, STRUCT_NAME_SYMBOL); +} + ; + +structBody: '{' structBodyStatementList '}' +{ + $$ = $2; +} + ; + +structBodyStatementList: + structBodyStatement +{ + $$ = buildStatementList($1, NULL); +} + | structBodyStatementList EOL structBodyStatement +{ + $$ = buildStatementList($3, $1); +} + ; + +structBodyStatement: + basicStructBodyStatement /* da */ + | labelList basicStructBodyStatement +{ + $$ = addLabelToStatement($1, $2); +} + ; + +basicStructBodyStatement: + wordStatement /* da */ + | dbyteStatement /* da */ + | byteStatement /* da */ + | blockStatement /* da */ + | stringStatement /* da */ + | alignStatement /* da */ + | nullStatement /* da */ + | structStatement /* da */ + | longStatement /* da */ + ; + +nullStatement: /* null string */ +{ + $$ = buildNullStatement(); +} + ; + +instructionStatement: + Opcode +{ + $$ = buildInstructionStatement($1, NULL); +} + | Opcode operandList +{ + $$ = buildInstructionStatement($1, $2); +} + | MacroName +{ + $$ = buildMacroInstructionStatement($1, NULL); +} + | MacroName operandList +{ + $$ = buildMacroInstructionStatement($1, $2); +} + ; + +groupStatement: block +{ + $$ = buildGroupStatement($1); +} + +defineStatement: + DEFINE _ defineTail +{ + $$ = $3; +} + ; + +defineTail: + Identifier +{ + $$ = buildDefineStatement($1, UNASSIGNED); +} + | Identifier ASSIGN /* must be '=' */ _ expression +{ + checkDefineAssignmentOperator($2); + $$ = buildDefineStatement($1, $4); +} + ; + +mdefineTail: + Identifier +{ + $$ = buildMdefineStatement($1, UNASSIGNED); +} + | Identifier ASSIGN /* must be '=' */ _ expression +{ + checkDefineAssignmentOperator($2); + $$ = buildMdefineStatement($1, $4); +} + ; + +macroStatement: + MACRO enter _ Identifier macroArguments _ block +{ + $$ = buildMacroStatement(createMacro($4), $5, $7); + popMacroOrFunctionNestingDepth(); +} + | MACRO enter _ Identifier _ block +{ + $$ = buildMacroStatement(createMacro($4), NULL, $6); + popMacroOrFunctionNestingDepth(); +} + | MACRO enter _ MacroName macroArguments _ block +{ + $$ = buildMacroStatement($4, $5, $7); + popMacroOrFunctionNestingDepth(); +} + | MACRO enter _ MacroName _ block +{ + $$ = buildMacroStatement($4, NULL, $6); + popMacroOrFunctionNestingDepth(); +} + ; + +enter: /* null string */ +{ + pushMacroOrFunctionNestingDepth(); +} + +macroArguments: argumentList; /* da */ + +functionStatement: + FUNCTION enter _ Identifier _ functionArguments _ block +{ + $$ = buildFunctionStatement($4, $6, $8); + popMacroOrFunctionNestingDepth(); +} + ; + +undefineStatement: + UNDEFINE _ identifierList +{ + $$ = buildUndefineStatement($3); +} + ; + +identifierList: Identifier +{ + $$ = buildIdentifierList($1, NULL, unknownSymbolTag); +} + | identifierList ',' _ Identifier +{ + $$ = buildIdentifierList($4, $1, unknownSymbolTag); +} + ; + +functionArguments: '(' ')' +{ + $$ = NULL; +} + | '(' argumentList ')' +{ + $$ = $2; +} + ; + +argumentList: basicArgumentList +{ + $$ = $1; +} + | basicArgumentList ',' _ variableArg +{ + $$ = buildArgumentList($4, $1, TRUE); +} + | variableArg +{ + $$ = buildArgumentList($1, NULL, TRUE); +} + ; + +basicArgumentList: + argument +{ + $$ = buildArgumentList($1, NULL, FALSE); +} + | basicArgumentList ',' _ argument +{ + $$ = buildArgumentList($4, $1, FALSE); +} + ; + +variableArg: Identifier '[' _ ']' /* da */ + ; + +argument: Identifier /* da */ + ; + +variableStatement: + VARIABLE _ variableTail +{ + $$ = $3; +} + ; + +variableTail: + Identifier +{ + $$ = buildVariableStatement($1, UNASSIGNED, NULL); +} + | Identifier ASSIGN /* must be '=' */ _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildVariableStatement($1, $4, NULL); +} + | Identifier '[' _ expression _ ']' +{ + $$ = buildVariableStatement($1, UNASSIGNED, $4); +} + | Identifier '[' _ expression _ ']' ASSIGN _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildVariableStatement($1, $9, $4); +} + | Identifier '[' ']' ASSIGN _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildVariableStatement($1, $6, -1); +} + ; + +macroVariableStatement: + MVARIABLE _ mvariableTail +{ + $$ = $3; +} + ; + +mvariableTail: + Identifier +{ + $$ = buildMvariableStatement($1, UNASSIGNED, NULL); +} + | Identifier ASSIGN /* must be '=' */ _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildMvariableStatement($1, $4, NULL); +} + | Identifier '[' _ expression _ ']' +{ + $$ = buildMvariableStatement($1, UNASSIGNED, $4); +} + | Identifier '[' _ expression _ ']' ASSIGN _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildMvariableStatement($1, $9, $4); +} + | Identifier '[' ']' ASSIGN _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildMvariableStatement($1, $6, -1); +} + ; + +macroDefineStatement: + MDEFINE _ mdefineTail +{ + $$ = $3; +} + ; + +macroIfStatement: + MIF _ mIfHead +{ + $$ = buildMifStatement($3, NULL, NO_CONTINUATION); +} + | MIF _ mIfHead mElsePart +{ + $$ = buildMifStatement($3, $4, ELSE_CONTINUATION); +} + | MIF _ mIfHead mElseIf +{ + $$ = buildMifStatement($3, $4, ELSEIF_CONTINUATION); +} + ; + +mIfHead: macroCondition _ block +{ + $$ = buildMifHead($1, $3); +} + ; + +macroCondition: '(' _ expression _ ')' +{ + $$ = $3; +} + ; + +mElsePart: MELSE _ block +{ + $$ = $3; +} + ; + +mElseIf: MELSE _ macroIfStatement +{ + $$ = extractMifBody($3); +} + | MELSEIF _ mIfHead +{ + $$ = extractMifBody(buildMifStatement($3, NULL, NO_CONTINUATION)); +} + | MELSEIF _ mIfHead mElsePart +{ + $$ = extractMifBody(buildMifStatement($3, $4, ELSE_CONTINUATION)); +} + | MELSEIF _ mIfHead mElseIf +{ + $$ = extractMifBody(buildMifStatement($3, $4, ELSEIF_CONTINUATION)); +} + ; + +macroSwitchStatement: + MSWITCH _ switch _ cases +{ + $$ = buildMswitchStatement($3, $5); +} + ; + +switch: '(' _ expression _ ')' +{ + $$ = $3; +} + ; + +cases: '{' _ caseList _ '}' +{ + $$ = $3; +} + | + '{' _ '}' +{ + $$ = NULL; +} + ; + +caseList: case +{ + $$ = buildCaseList($1, NULL); +} + | caseList _ case +{ + $$ = buildCaseList($3, $1); +} + ; + +case: caseTag _ block +{ + $$ = buildCase($1, $3); +} + ; + +caseTag: MCASE _ '(' _ expressionList _ ')' +{ + $$ = $5; +} + | MDEFAULT +{ + $$ = NULL; +} + ; + +macroWhileStatement: + MWHILE _ macroCondition _ block +{ + $$ = buildMwhileStatement($3, $5); +} + ; + +macroDoStatement: + MDO _ block _ macroDoEnd +{ + $$ = buildMdoStatement($3, $5); +} + ; + +macroDoEnd: WHILE _ macroCondition +{ + $$ = buildMdoEnd($3, WHILE_END); +} + | MWHILE _ macroCondition +{ + $$ = buildMdoEnd($3, WHILE_END); +} + | UNTIL _ macroCondition +{ + $$ = buildMdoEnd($3, UNTIL_END); +} + | MUNTIL _ macroCondition +{ + $$ = buildMdoEnd($3, UNTIL_END); +} + ; + +functionReturnStatement: + FRETURN +{ + $$ = buildFreturnStatement(NULL); +} + | FRETURN thingToReturn +{ + $$ = buildFreturnStatement($2); +} + ; + +thingToReturn: expression /* da */ + ; + +macroForStatement: + MFOR _ '(' _ forExpressions _ ')' _ block +{ + $$ = buildMforStatement($5, $9); +} + ; + +forExpressions: + expression ',' _ expression ',' _ expression +{ + $$ = buildForExpressions($1, $4, $7); +} + ; + +includeStatement: + INCLUDE _ expression +{ + $$ = buildIncludeStatement($3); +} + ; + +externStatement: + EXTERN _ identifierList +{ + $$ = buildExternStatement($3); +} + ; + +startStatement: START _ expression +{ + $$ = buildStartStatement($3); +} + ; + +alignStatement: ALIGN _ expression +{ + $$ = buildAlignStatement($3); +} + ; + +orgStatement: ORG _ expression +{ + $$ = buildOrgStatement($3); +} + ; + +targetStatement: + TARGET _ expression +{ + $$ = buildTargetStatement($3); +} + ; + +relStatement: REL +{ + $$ = buildRelStatement(); +} + ; + +performStatement: + expression +{ + $$ = buildPerformStatement($1); +} + ; + +operandList: blockEndingOperandList /* da */ + | nonBlockEndingOperandList /* da */ + ; + +blockEndingOperandList: + blockOperand +{ + $$ = buildOperandList($1, NULL); +} + | blockEndingOperandList blockOperand +{ + $$ = buildOperandList($2, $1); +} + | blockEndingOperandList ',' _ blockOperand +{ + $$ = buildOperandList($4, $1); +} + | nonBlockEndingOperandList blockOperand +{ + $$ = buildOperandList($2, $1); +} + | nonBlockEndingOperandList ',' _ blockOperand +{ + $$ = buildOperandList($4, $1); +} + ; + +nonBlockEndingOperandList: + nonBlockOperand +{ + $$ = buildOperandList($1, NULL); +} + | nonBlockEndingOperandList ',' _ nonBlockOperand +{ + $$ = buildOperandList($4, $1); +} + | blockEndingOperandList nonBlockOperand +{ + $$ = buildOperandList($2, $1); +} + | blockEndingOperandList ',' _ nonBlockOperand +{ + $$ = buildOperandList($4, $1); +} + ; + +blockOperand: block +{ + $$ = buildOperand(BLOCK_OPND, $1); +} + ; + +block: '{' nestDeeper statementList '}' +{ + $$ = $3; + statementListNestingDepth--; +} + ; + +nestDeeper: /* null string */ +{ + statementListNestingDepth++; +} + +selectionList: SELECT _ Identifier +{ + $$ = buildSelectionList($3, NULL); +} + | selectionList SELECT _ Identifier +{ + $$ = buildSelectionList($4, $1); +} + ; + +array: variable '[' _ expression _ ']' +{ + $$ = buildExpressionTerm(ARRAY_EXPR, $1, $4); +} + | array '[' _ expression _ ']' +{ + $$ = buildExpressionTerm(ARRAY_EXPR, $1, $4); +} + ; + +variable: Identifier +{ + $$ = buildExpressionTerm(IDENTIFIER_EXPR, lookupOrEnterSymbol($1, + unknownSymbolTag)); +} + ; + +lvalue: array /* da */ + | variable /* da */ + ; + +expression: lvalue +{ + $$ = $1; +} + | functionCall +{ + $$ = buildExpressionTerm(FUNCTION_CALL_EXPR, $1); +} + | Number +{ + $$ = buildExpressionTerm(NUMBER_EXPR, $1); +} + | ConditionCode +{ + $$ = buildExpressionTerm(CONDITION_CODE_EXPR, $1); +} + | HERE +{ + $$ = buildExpressionTerm(HERE_EXPR); +} + | TextString +{ + $$ = buildExpressionTerm(STRING_EXPR, $1); +} + | '(' _ expression _ ')' +{ + $$ = buildExpressionTerm(SUBEXPRESSION_EXPR, $3); +} + | SUB _ expression %prec UNARY_MINUS +{ + $$ = buildExpressionTerm(UNOP_EXPR, UNARY_MINUS, $3); +} + | LOGICAL_NOT _ expression +{ + $$ = buildExpressionTerm(UNOP_EXPR, LOGICAL_NOT, $3); +} + | BITWISE_NOT _ expression +{ + $$ = buildExpressionTerm(UNOP_EXPR, BITWISE_NOT, $3); +} + | DIV _ expression %prec LO_BYTE +{ + $$ = buildExpressionTerm(UNOP_EXPR, LO_BYTE, $3); +} + | HI_BYTE _ expression +{ + $$ = buildExpressionTerm(UNOP_EXPR, HI_BYTE, $3); +} + | expression MUL _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, MUL, $1, $4); +} + | expression DIV _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, DIV, $1, $4); +} + | expression MOD _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, MOD, $1, $4); +} + | expression SUB _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, SUB, $1, $4); +} + | expression ADD _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, ADD, $1, $4); +} + | expression LEFT_SHIFT _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LEFT_SHIFT, $1, $4); +} + | expression RIGHT_SHIFT _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, RIGHT_SHIFT, $1, $4); +} + | expression LESS_THAN _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LESS_THAN, $1, $4); +} + | expression GREATER_THAN _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, GREATER_THAN, $1, $4); +} + | expression LESS_THAN_OR_EQUAL_TO _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LESS_THAN_OR_EQUAL_TO, $1, $4); +} + | expression GREATER_THAN_OR_EQUAL_TO _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, GREATER_THAN_OR_EQUAL_TO, $1,$4); +} + | expression EQUAL_TO _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, EQUAL_TO, $1, $4); +} + | expression NOT_EQUAL_TO _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, NOT_EQUAL_TO, $1, $4); +} + | expression BITWISE_AND _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, BITWISE_AND, $1, $4); +} + | expression BITWISE_OR _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, BITWISE_OR, $1, $4); +} + | expression BITWISE_XOR _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, BITWISE_XOR, $1, $4); +} + | expression LOGICAL_AND _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LOGICAL_AND, $1, $4); +} + | expression LOGICAL_OR _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LOGICAL_OR, $1, $4); +} + | expression LOGICAL_XOR _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LOGICAL_XOR, $1, $4); +} + | expression SELECT _ Identifier +{ + $$ = buildExpressionTerm(BINOP_EXPR, SELECT, $1, + lookupOrEnterSymbol($4, STRUCT_FIELD_SYMBOL)); +} + | lvalue ASSIGN _ expression +{ + $$ = buildExpressionTerm(ASSIGN_EXPR, $2, $1, $4); +} + | lvalue INCREMENT +{ + $$ = buildExpressionTerm(POSTOP_EXPR, INCREMENT, $1); +} + | lvalue DECREMENT +{ + $$ = buildExpressionTerm(POSTOP_EXPR, DECREMENT, $1); +} + | INCREMENT _ lvalue +{ + $$ = buildExpressionTerm(PREOP_EXPR, INCREMENT, $3); +} + | DECREMENT _ lvalue +{ + $$ = buildExpressionTerm(PREOP_EXPR, DECREMENT, $3); +} + ; + +functionCall: + functionName '(' _ ')' +{ + $$ = buildFunctionCall($1, NULL); +} + | functionName '(' _ functionArgumentList _ ')' +{ + $$ = buildFunctionCall($1, $4); +} + ; + +functionName: Identifier /* da */ + ; + +functionArgumentList: + operandList /* da */ + ; + +/* Stuff above this point is target independent (except for token list), stuff + below this points is target dependent (operand syntax) */ + +nonBlockOperand: + directExpression /* da */ + | indirectExpression /* da */ + | immediateExpression /* da */ + | registerExpression /* da */ + | indexedExpression /* da */ + | preIndexedXExpression /* da */ + | postIndexedYExpression /* da */ + ; + +directExpression: expression +{ + $$ = buildOperand(EXPRESSION_OPND, $1); +} + ; + +indirectExpression: '@' _ expression +{ + $$ = buildOperand(INDIRECT_OPND, $3); +} + ; + +immediateExpression: '#' _ expression +{ + $$ = buildOperand(IMMEDIATE_OPND, $3); +} + ; + +registerExpression: + A +{ + $$ = buildOperand(A_REGISTER_OPND, NULL); +} + | X +{ + $$ = buildOperand(X_REGISTER_OPND, NULL); +} + | Y +{ + $$ = buildOperand(Y_REGISTER_OPND, NULL); +} + ; + +indexedExpression: + X '[' _ expression _ ']' +{ + $$ = buildOperand(X_INDEXED_OPND, $4); +} + | Y '[' _ expression _ ']' +{ + $$ = buildOperand(Y_INDEXED_OPND, $4); +} + | X selectionList +{ + $$ = buildOperand(X_SELECTED_OPND, $2); +} + | Y selectionList +{ + $$ = buildOperand(Y_SELECTED_OPND, $2); +} + | '@' _ X +{ + $$ = buildOperand(X_INDEXED_OPND, NULL); +} + | '@' _ Y +{ + $$ = buildOperand(Y_INDEXED_OPND, NULL); +} + ; + +preIndexedXExpression: + '@' _ X '[' _ expression _ ']' +{ + $$ = buildOperand(PRE_INDEXED_X_OPND, $6); +} + | '@' _ X selectionList +{ + $$ = buildOperand(PRE_SELECTED_X_OPND, $4); +} + ; + +postIndexedYExpression: + Y '[' _ '@' _ expression _ ']' +{ + $$ = buildOperand(POST_INDEXED_Y_OPND, $6); +} + ; diff --git a/macross_68000.y b/macross_68000.y new file mode 100644 index 0000000..cc52c66 --- /dev/null +++ b/macross_68000.y @@ -0,0 +1,1362 @@ +/* + macross.y -- Grammar and semantic rules for Macross parser + + Chip Morningstar -- Lucasfilm Ltd. + + 1-November-1984 + +*/ +%{ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +%} + +/* Token list is target system dependent */ +%token A0 A1 A2 A3 A4 A5 A6 A7 ALIGN ASSERT BLOCK BYTE CCR CONSTRAIN D0 D1 D2 +%token D3 D4 D5 D6 D7 DBYTE DEFINE DFC DO ELSE ELSEIF ENDFILE EOL EXTERN +%token FRETURN FUNCTION HERE IF INCLUDE L LONG MACRO MCASE MDEFAULT MDEFINE +%token MDO MELSE MELSEIF MFOR MIF MSWITCH MUNTIL MVARIABLE MWHILE ORG PC REL +%token SFC SR START STRING STRUCT TARGET UNDEFINE UNTIL USP VARIABLE VBR W +%token WHILE WORD +%token ConditionCode Identifier MacroName Number Opcode TextString + +/* funny characters used literally: + + : , @ ( ) { } [ ] + +*/ + +%right ASSIGN /* = += *= -= /= %= <<= >>= &= |= + ^= */ +%left LOGICAL_OR /* || */ +%left LOGICAL_XOR /* ^^ */ +%left LOGICAL_AND /* && */ +%left BITWISE_OR /* | */ +%left BITWISE_XOR /* ^ */ +%left BITWISE_AND /* & */ +%nonassoc EQUAL_TO NOT_EQUAL_TO /* == != */ +%nonassoc LESS_THAN LESS_THAN_OR_EQUAL_TO GREATER_THAN GREATER_THAN_OR_EQUAL_TO + /* < <= > >= */ +/* %nonassoc '['*/ +%left LEFT_SHIFT RIGHT_SHIFT /* << >> */ +%left ADD SUB /* + - */ +%left MUL DIV MOD /* * / % */ +%right UNARY_MINUS LOGICAL_NOT BITWISE_NOT HI_BYTE LO_BYTE + /* - ! ~ ? / */ +%left SELECT /* . */ +%token INCREMENT DECREMENT /* ++ -- */ + +%% + +/* + In what follows, the comment "da" indicates that we are taking the default + action: + $$ = $1; + If this comment is not present, then then we intend there to be no action + even though yacc will give us the default. (The author's stylistic + tendencies being what they are, the default would have been entered + wherever it was intended, but this was found to clutter up the listing + excessively. +*/ + +program: beginProgram statementList EOL ENDFILE +{ + $$ = $2; +} + | ENDFILE +{ + $$ = 0; +} + ; + +beginProgram: /* null string */ +{ + statementListNestingDepth = 0; + errorFlag = FALSE; +} + ; + +/* "_" represents an optional newline (i.e., a whitespace newline as opposed + to an end-of-statement newline */ +_: eolList + | /* null string */ + ; + +eolList: EOL +{ + if (amListing()) + saveEOLForListing(); +} + | eolList EOL +{ + if (amListing()) + saveEOLForListing(); +} + ; + +statementList: statement +{ + if (statementListNestingDepth == 0) { + $$ = eatStatement($1); + } else { + $$ = buildStatementList($1, NULL); + } +} + | statementList EOL statement +{ + if (statementListNestingDepth == 0) { + $$ = eatStatement($3); + } else { + $$ = buildStatementList($3, $1); + } +} + ; + +statement: labeledStatement /* da */ + | unlabeledStatement /* da */ + | error ENDFILE +{ + $$ = NULL; + YYACCEPT; +} + | error +{ + yyerrok; + yyclearin; + resynchronizeInput(); + $$ = NULL; +} + ; + +labeledStatement: + labelList labelableStatement +{ + $$ = addLabelToStatement($1, $2); +} + ; + +unlabeledStatement: + labelableStatement /* da */ + ; + +labelList: label +{ + $$ = buildLabelList($1, NULL); +} + | labelList label +{ + $$ = buildLabelList($2, $1); +} + ; + +label: Identifier ':' +{ + $$ = lookupOrEnterSymbol($1, LABEL_SYMBOL); +} + | Identifier ':' ':' +{ + $$ = lookupOrEnterSymbol($1, LABEL_SYMBOL); + addAttributeToSymbol($$, TENTATIVE_GLOBAL_ATT); +} + ; + +labelableStatement: + ifStatement /* da */ + | whileStatement /* da */ + | doStatement /* da */ + | wordStatement /* da */ + | dbyteStatement /* da */ + | byteStatement /* da */ + | blockStatement /* da */ + | stringStatement /* da */ + | nullStatement /* da */ + | structStatement /* da */ + | performStatement /* da */ + | instructionStatement /* da */ + | groupStatement /* da */ + | defineStatement /* da */ + | macroDefineStatement /* da */ + | variableStatement /* da */ + | macroVariableStatement /* da */ + | macroStatement /* da */ + | functionStatement /* da */ + | functionReturnStatement /* da */ + | undefineStatement /* da */ + | macroIfStatement /* da */ + | macroWhileStatement /* da */ + | macroDoStatement /* da */ + | macroForStatement /* da */ + | macroSwitchStatement /* da */ + | includeStatement /* da */ + | externStatement /* da */ + | startStatement /* da */ + | alignStatement /* da */ + | orgStatement /* da */ + | relStatement /* da */ + | constrainStatement /* da */ + | assertStatement /* da */ + | longStatement /* da */ + | targetStatement /* da */ + ; + +ifStatement: IF _ ifHead +{ + $$ = buildIfStatement($3, NULL, NO_CONTINUATION); +} + | IF _ ifHead elsePart +{ + $$ = buildIfStatement($3, $4, ELSE_CONTINUATION); +} + | IF _ ifHead elseIf +{ + $$ = buildIfStatement($3, $4, ELSEIF_CONTINUATION); +} + ; + +ifHead: condition _ block +{ + $$ = buildIfHead($1, $3); +} + ; + +condition: '(' _ conditionExpression _ ')' +{ + $$ = $3; +} + ; + +conditionExpression: + ConditionCode /* da */ + | LOGICAL_NOT conditionExpression +{ + $$ = invertConditionCode($2); +} + | '(' _ conditionExpression _ ')' +{ + $$ = $3; +} + ; + +elsePart: ELSE _ block +{ + $$ = $3; +} + ; + +elseIf: ELSE _ ifStatement +{ + $$ = extractIfBody($3); +} + | ELSEIF _ ifHead +{ + $$ = extractIfBody(buildIfStatement($3, NULL, NO_CONTINUATION)); +} + | ELSEIF _ ifHead elsePart +{ + $$ = extractIfBody(buildIfStatement($3, $4, ELSE_CONTINUATION)); +} + | ELSEIF _ ifHead elseIf +{ + $$ = extractIfBody(buildIfStatement($3, $4, ELSEIF_CONTINUATION)); +} + ; + +whileStatement: WHILE _ condition _ block +{ + $$ = buildWhileStatement($3, $5); +} + ; + +doStatement: DO _ block _ doEnd +{ + $$ = buildDoStatement($3, $5); +} + ; + +doEnd: WHILE _ condition +{ + $$ = buildDoEnd($3, WHILE_END); +} + | UNTIL _ condition +{ + $$ = buildDoEnd($3, UNTIL_END); +} + ; + +wordStatement: WORD _ expressionList +{ + $$ = buildWordStatement($3); +} + ; + +longStatement: LONG _ expressionList +{ + $$ = buildLongStatement($3); +} + ; + +expressionList: expression +{ + $$ = buildExpressionList($1, NULL); +} + | expressionList ',' _ expression +{ + $$ = buildExpressionList($4, $1); +} + ; + +constrainStatement: + CONSTRAIN _ '(' _ expression _ ')' _ block +{ + $$ = buildConstrainStatement($5, $9); +} + ; + +assertStatement: + ASSERT _ '(' _ expression _ ')' expression +{ + $$ = buildAssertStatement($5, $8); +} + | ASSERT _ '(' _ expression _ ')' +{ + $$ = buildAssertStatement($5, NULL); +} + ; + +dbyteStatement: DBYTE _ expressionList +{ + $$ = buildDbyteStatement($3); +} + ; + +byteStatement: BYTE _ expressionList +{ + $$ = buildByteStatement($3); +} + ; + +blockStatement: BLOCK _ expressionList +{ + $$ = buildBlockStatement($3); +} + ; + +stringStatement: + STRING _ expressionList +{ + $$ = buildStringStatement($3); +} + ; + +structStatement: + STRUCT _ structName +{ + $$ = buildStructStatement($3, NULL); +} + | STRUCT _ structBody _ structName +{ + $$ = buildStructStatement($5, $3); +} + ; + +structName: Identifier +{ + $$ = lookupOrEnterSymbol($1, STRUCT_NAME_SYMBOL); +} + ; + +structBody: '{' structBodyStatementList '}' +{ + $$ = $2; +} + ; + +structBodyStatementList: + structBodyStatement +{ + $$ = buildStatementList($1, NULL); +} + | structBodyStatementList EOL structBodyStatement +{ + $$ = buildStatementList($3, $1); +} + ; + +structBodyStatement: + basicStructBodyStatement /* da */ + | labelList basicStructBodyStatement +{ + $$ = addLabelToStatement($1, $2); +} + ; + +basicStructBodyStatement: + wordStatement /* da */ + | dbyteStatement /* da */ + | byteStatement /* da */ + | blockStatement /* da */ + | stringStatement /* da */ + | alignStatement /* da */ + | nullStatement /* da */ + | structStatement /* da */ + | longStatement /* da */ + ; + +nullStatement: /* null string */ +{ + $$ = buildNullStatement(); +} + ; + +instructionStatement: + Opcode +{ + $$ = buildInstructionStatement($1, NULL); +} + | Opcode operandList +{ + $$ = buildInstructionStatement($1, $2); +} + | MacroName +{ + $$ = buildMacroInstructionStatement($1, NULL); +} + | MacroName operandList +{ + $$ = buildMacroInstructionStatement($1, $2); +} + ; + +groupStatement: block +{ + $$ = buildGroupStatement($1); +} + +defineStatement: + DEFINE _ defineTail +{ + $$ = $3; +} + ; + +defineTail: + Identifier +{ + $$ = buildDefineStatement($1, UNASSIGNED); +} + | Identifier ASSIGN /* must be '=' */ _ expression +{ + checkDefineAssignmentOperator($2); + $$ = buildDefineStatement($1, $4); +} + ; + +mdefineTail: + Identifier +{ + $$ = buildMdefineStatement($1, UNASSIGNED); +} + | Identifier ASSIGN /* must be '=' */ _ expression +{ + checkDefineAssignmentOperator($2); + $$ = buildMdefineStatement($1, $4); +} + ; + +macroStatement: + MACRO enter _ Identifier macroArguments _ block +{ + $$ = buildMacroStatement(createMacro($4), $5, $7); + popMacroOrFunctionNestingDepth(); +} + | MACRO enter _ Identifier _ block +{ + $$ = buildMacroStatement(createMacro($4), NULL, $6); + popMacroOrFunctionNestingDepth(); +} + | MACRO enter _ MacroName macroArguments _ block +{ + $$ = buildMacroStatement($4, $5, $7); + popMacroOrFunctionNestingDepth(); +} + | MACRO enter _ MacroName _ block +{ + $$ = buildMacroStatement($4, NULL, $6); + popMacroOrFunctionNestingDepth(); +} + ; + +enter: /* null string */ +{ + pushMacroOrFunctionNestingDepth(); +} + +macroArguments: argumentList; /* da */ + +functionStatement: + FUNCTION enter _ Identifier _ functionArguments _ block +{ + $$ = buildFunctionStatement($4, $6, $8); + popMacroOrFunctionNestingDepth(); +} + ; + +undefineStatement: + UNDEFINE _ identifierList +{ + $$ = buildUndefineStatement($3); +} + ; + +identifierList: Identifier +{ + $$ = buildIdentifierList($1, NULL, unknownSymbolTag); +} + | identifierList ',' _ Identifier +{ + $$ = buildIdentifierList($4, $1, unknownSymbolTag); +} + ; + +functionArguments: '(' ')' +{ + $$ = NULL; +} + | '(' argumentList ')' +{ + $$ = $2; +} + ; + +argumentList: basicArgumentList +{ + $$ = $1; +} + | basicArgumentList ',' _ variableArg +{ + $$ = buildArgumentList($4, $1, TRUE); +} + | variableArg +{ + $$ = buildArgumentList($1, NULL, TRUE); +} + ; + +basicArgumentList: + argument +{ + $$ = buildArgumentList($1, NULL, FALSE); +} + | basicArgumentList ',' _ argument +{ + $$ = buildArgumentList($4, $1, FALSE); +} + ; + +variableArg: Identifier '[' _ ']' /* da */ + ; + +argument: Identifier /* da */ + ; + +variableStatement: + VARIABLE _ variableTail +{ + $$ = $3; +} + ; + +variableTail: + Identifier +{ + $$ = buildVariableStatement($1, UNASSIGNED, NULL); +} + | Identifier ASSIGN /* must be '=' */ _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildVariableStatement($1, $4, NULL); +} + | Identifier '[' _ expression _ ']' +{ + $$ = buildVariableStatement($1, UNASSIGNED, $4); +} + | Identifier '[' _ expression _ ']' ASSIGN _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildVariableStatement($1, $9, $4); +} + | Identifier '[' ']' ASSIGN _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildVariableStatement($1, $6, -1); +} + ; + +macroVariableStatement: + MVARIABLE _ mvariableTail +{ + $$ = $3; +} + ; + +mvariableTail: + Identifier +{ + $$ = buildMvariableStatement($1, UNASSIGNED, NULL); +} + | Identifier ASSIGN /* must be '=' */ _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildMvariableStatement($1, $4, NULL); +} + | Identifier '[' _ expression _ ']' +{ + $$ = buildMvariableStatement($1, UNASSIGNED, $4); +} + | Identifier '[' _ expression _ ']' ASSIGN _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildMvariableStatement($1, $9, $4); +} + | Identifier '[' ']' ASSIGN _ expressionList +{ + checkDefineAssignmentOperator($2); + $$ = buildMvariableStatement($1, $6, -1); +} + ; + +macroDefineStatement: + MDEFINE _ mdefineTail +{ + $$ = $3; +} + ; + +macroIfStatement: + MIF _ mIfHead +{ + $$ = buildMifStatement($3, NULL, NO_CONTINUATION); +} + | MIF _ mIfHead mElsePart +{ + $$ = buildMifStatement($3, $4, ELSE_CONTINUATION); +} + | MIF _ mIfHead mElseIf +{ + $$ = buildMifStatement($3, $4, ELSEIF_CONTINUATION); +} + ; + +mIfHead: macroCondition _ block +{ + $$ = buildMifHead($1, $3); +} + ; + +macroCondition: '(' _ expression _ ')' +{ + $$ = $3; +} + ; + +mElsePart: MELSE _ block +{ + $$ = $3; +} + ; + +mElseIf: MELSE _ macroIfStatement +{ + $$ = extractMifBody($3); +} + | MELSEIF _ mIfHead +{ + $$ = extractMifBody(buildMifStatement($3, NULL, NO_CONTINUATION)); +} + | MELSEIF _ mIfHead mElsePart +{ + $$ = extractMifBody(buildMifStatement($3, $4, ELSE_CONTINUATION)); +} + | MELSEIF _ mIfHead mElseIf +{ + $$ = extractMifBody(buildMifStatement($3, $4, ELSEIF_CONTINUATION)); +} + ; + +macroSwitchStatement: + MSWITCH _ switch _ cases +{ + $$ = buildMswitchStatement($3, $5); +} + ; + +switch: '(' _ expression _ ')' +{ + $$ = $3; +} + ; + +cases: '{' _ caseList _ '}' +{ + $$ = $3; +} + | + '{' _ '}' +{ + $$ = NULL; +} + ; + +caseList: case +{ + $$ = buildCaseList($1, NULL); +} + | caseList _ case +{ + $$ = buildCaseList($3, $1); +} + ; + +case: caseTag _ block +{ + $$ = buildCase($1, $3); +} + ; + +caseTag: MCASE _ '(' _ expressionList _ ')' +{ + $$ = $5; +} + | MDEFAULT +{ + $$ = NULL; +} + ; + +macroWhileStatement: + MWHILE _ macroCondition _ block +{ + $$ = buildMwhileStatement($3, $5); +} + ; + +macroDoStatement: + MDO _ block _ macroDoEnd +{ + $$ = buildMdoStatement($3, $5); +} + ; + +macroDoEnd: WHILE _ macroCondition +{ + $$ = buildMdoEnd($3, WHILE_END); +} + | MWHILE _ macroCondition +{ + $$ = buildMdoEnd($3, WHILE_END); +} + | UNTIL _ macroCondition +{ + $$ = buildMdoEnd($3, UNTIL_END); +} + | MUNTIL _ macroCondition +{ + $$ = buildMdoEnd($3, UNTIL_END); +} + ; + +functionReturnStatement: + FRETURN +{ + $$ = buildFreturnStatement(NULL); +} + | FRETURN thingToReturn +{ + $$ = buildFreturnStatement($2); +} + ; + +thingToReturn: expression /* da */ + ; + +macroForStatement: + MFOR _ '(' _ forExpressions _ ')' _ block +{ + $$ = buildMforStatement($5, $9); +} + ; + +forExpressions: + expression ',' _ expression ',' _ expression +{ + $$ = buildForExpressions($1, $4, $7); +} + ; + +includeStatement: + INCLUDE _ expression +{ + $$ = buildIncludeStatement($3); +} + ; + +externStatement: + EXTERN _ identifierList +{ + $$ = buildExternStatement($3); +} + ; + +startStatement: START _ expression +{ + $$ = buildStartStatement($3); +} + ; + +alignStatement: ALIGN _ expression +{ + $$ = buildAlignStatement($3); +} + ; + +orgStatement: ORG _ expression +{ + $$ = buildOrgStatement($3); +} + ; + +targetStatement: + TARGET _ expression +{ + $$ = buildTargetStatement($3); +} + ; + +relStatement: REL +{ + $$ = buildRelStatement(); +} + ; + +performStatement: + expression +{ + $$ = buildPerformStatement($1); +} + ; + +operandList: blockEndingOperandList /* da */ + | nonBlockEndingOperandList /* da */ + ; + +blockEndingOperandList: + blockOperand +{ + $$ = buildOperandList($1, NULL); +} + | blockEndingOperandList blockOperand +{ + $$ = buildOperandList($2, $1); +} + | blockEndingOperandList ',' _ blockOperand +{ + $$ = buildOperandList($4, $1); +} + | nonBlockEndingOperandList blockOperand +{ + $$ = buildOperandList($2, $1); +} + | nonBlockEndingOperandList ',' _ blockOperand +{ + $$ = buildOperandList($4, $1); +} + ; + +nonBlockEndingOperandList: + nonBlockOperand +{ + $$ = buildOperandList($1, NULL); +} + | nonBlockEndingOperandList ',' _ nonBlockOperand +{ + $$ = buildOperandList($4, $1); +} + | blockEndingOperandList nonBlockOperand +{ + $$ = buildOperandList($2, $1); +} + | blockEndingOperandList ',' _ nonBlockOperand +{ + $$ = buildOperandList($4, $1); +} + ; + +blockOperand: block +{ + $$ = buildOperand(BLOCK_OPND, $1); +} + ; + +block: '{' nestDeeper statementList '}' +{ + $$ = $3; + statementListNestingDepth--; +} + ; + +nestDeeper: /* null string */ +{ + statementListNestingDepth++; +} + +selectionList: SELECT _ Identifier +{ + $$ = buildSelectionList($3, NULL); +} + | selectionList SELECT _ Identifier +{ + $$ = buildSelectionList($4, $1); +} + ; + +array: variable '[' _ expression _ ']' +{ + $$ = buildExpressionTerm(ARRAY_EXPR, $1, $4); +} + | array '[' _ expression _ ']' +{ + $$ = buildExpressionTerm(ARRAY_EXPR, $1, $4); +} + ; + +variable: Identifier +{ + $$ = buildExpressionTerm(IDENTIFIER_EXPR, lookupOrEnterSymbol($1, + unknownSymbolTag)); +} + ; + +lvalue: array /* da */ + | variable /* da */ + ; + +expression: lvalue +{ + $$ = $1; +} + | functionCall +{ + $$ = buildExpressionTerm(FUNCTION_CALL_EXPR, $1); +} + | Number +{ + $$ = buildExpressionTerm(NUMBER_EXPR, $1); +} + | ConditionCode +{ + $$ = buildExpressionTerm(CONDITION_CODE_EXPR, $1); +} + | HERE +{ + $$ = buildExpressionTerm(HERE_EXPR); +} + | TextString +{ + $$ = buildExpressionTerm(STRING_EXPR, $1); +} + | '(' _ expression _ ')' +{ + $$ = buildExpressionTerm(SUBEXPRESSION_EXPR, $3); +} + | SUB _ expression %prec UNARY_MINUS +{ + $$ = buildExpressionTerm(UNOP_EXPR, UNARY_MINUS, $3); +} + | LOGICAL_NOT _ expression +{ + $$ = buildExpressionTerm(UNOP_EXPR, LOGICAL_NOT, $3); +} + | BITWISE_NOT _ expression +{ + $$ = buildExpressionTerm(UNOP_EXPR, BITWISE_NOT, $3); +} + | DIV _ expression %prec LO_BYTE +{ + $$ = buildExpressionTerm(UNOP_EXPR, LO_BYTE, $3); +} + | HI_BYTE _ expression +{ + $$ = buildExpressionTerm(UNOP_EXPR, HI_BYTE, $3); +} + | expression MUL _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, MUL, $1, $4); +} + | expression DIV _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, DIV, $1, $4); +} + | expression MOD _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, MOD, $1, $4); +} + | expression SUB _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, SUB, $1, $4); +} + | expression ADD _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, ADD, $1, $4); +} + | expression LEFT_SHIFT _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LEFT_SHIFT, $1, $4); +} + | expression RIGHT_SHIFT _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, RIGHT_SHIFT, $1, $4); +} + | expression LESS_THAN _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LESS_THAN, $1, $4); +} + | expression GREATER_THAN _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, GREATER_THAN, $1, $4); +} + | expression LESS_THAN_OR_EQUAL_TO _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LESS_THAN_OR_EQUAL_TO, $1, $4); +} + | expression GREATER_THAN_OR_EQUAL_TO _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, GREATER_THAN_OR_EQUAL_TO, $1,$4); +} + | expression EQUAL_TO _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, EQUAL_TO, $1, $4); +} + | expression NOT_EQUAL_TO _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, NOT_EQUAL_TO, $1, $4); +} + | expression BITWISE_AND _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, BITWISE_AND, $1, $4); +} + | expression BITWISE_OR _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, BITWISE_OR, $1, $4); +} + | expression BITWISE_XOR _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, BITWISE_XOR, $1, $4); +} + | expression LOGICAL_AND _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LOGICAL_AND, $1, $4); +} + | expression LOGICAL_OR _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LOGICAL_OR, $1, $4); +} + | expression LOGICAL_XOR _ expression +{ + $$ = buildExpressionTerm(BINOP_EXPR, LOGICAL_XOR, $1, $4); +} + | expression SELECT _ Identifier +{ + $$ = buildExpressionTerm(BINOP_EXPR, SELECT, $1, + lookupOrEnterSymbol($4, STRUCT_FIELD_SYMBOL)); +} + | lvalue ASSIGN _ expression +{ + $$ = buildExpressionTerm(ASSIGN_EXPR, $2, $1, $4); +} + | lvalue INCREMENT +{ + $$ = buildExpressionTerm(POSTOP_EXPR, INCREMENT, $1); +} + | lvalue DECREMENT +{ + $$ = buildExpressionTerm(POSTOP_EXPR, DECREMENT, $1); +} + | INCREMENT _ lvalue +{ + $$ = buildExpressionTerm(PREOP_EXPR, INCREMENT, $3); +} + | DECREMENT _ lvalue +{ + $$ = buildExpressionTerm(PREOP_EXPR, DECREMENT, $3); +} + ; + +functionCall: + functionName '(' _ ')' +{ + $$ = buildFunctionCall($1, NULL); +} + | functionName '(' _ functionArgumentList _ ')' +{ + $$ = buildFunctionCall($1, $4); +} + ; + +functionName: Identifier /* da */ + ; + +functionArgumentList: + operandList /* da */ + ; + +/* Stuff above this point is target independent (except for token list), stuff + below this points is target dependent (operand syntax) */ + +nonBlockOperand: + dataRegisterExpression /* da */ + | addressRegisterExpression /* da */ + | addressRegisterIndirectExpression /* da */ + | postincrementExpression /* da */ + | predecrementExpression /* da */ + | displacementExpression /* da */ + | indexedExpression /* da */ + | pcDisplacementExpression /* da */ + | pcIndexedExpression /* da */ + | immediateExpression /* da */ + | absoluteShortExpression /* da */ + | absoluteLongExpression /* da */ + | normalExpression /* da */ + | conditionCodeRegisterExpression /* da */ + | statusRegisterExpression /* da */ + | userStackPointerExpression /* da */ + | controlRegisterExpression /* da */ + ; + +dataRegister: D0 { $$ = 0; } + | D1 { $$ = 1; } + | D2 { $$ = 2; } + | D3 { $$ = 3; } + | D4 { $$ = 4; } + | D5 { $$ = 5; } + | D6 { $$ = 6; } + | D7 { $$ = 7; } + ; + +addressRegister:A0 { $$ = 0; } + | A1 { $$ = 1; } + | A2 { $$ = 2; } + | A3 { $$ = 3; } + | A4 { $$ = 4; } + | A5 { $$ = 5; } + | A6 { $$ = 6; } + | A7 { $$ = 7; } + ; + +register: dataRegister +{ + $$ = $1; +} + | addressRegister +{ + $$ = $1 + 8; +} + ; + +controlRegister:SFC { $$ = 0; } + | DFC { $$ = 1; } + | VBR { $$ = 2; } + ; + +dataRegisterExpression: dataRegister +{ + $$ = buildOperand(D_REGISTER_OPND, $1); +} + ; + +addressRegisterExpression: addressRegister +{ + $$ = buildOperand(A_REGISTER_OPND, $1); +} + ; + +addressRegisterIndirectExpression: + '[' _ addressRegister _ ']' +{ + $$ = buildOperand(A_REGISTER_INDIRECT_OPND, $3); +} + | addressRegister '@' +{ + $$ = buildOperand(A_REGISTER_INDIRECT_OPND, $1); +} + ; + +postincrementExpression: + '[' _ addressRegister _ ']' ADD +{ + $$ = buildOperand(POSTINCREMENT_OPND, $3); +} + | addressRegister '@' ADD +{ + $$ = buildOperand(POSTINCREMENT_OPND, $1); +} + ; + +predecrementExpression: + SUB '[' _ addressRegister _ ']' +{ + $$ = buildOperand(PREDECREMENT_OPND, $4); +} + | addressRegister '@' SUB +{ + $$ = buildOperand(PREDECREMENT_OPND, $1); +} + ; + +displacementExpression: + expression '[' _ addressRegister _ ']' +{ + $$ = buildOperand(DISPLACEMENT_OPND, $4, $1); +} + | addressRegister '@' '(' _ expression _ ')' +{ + $$ = buildOperand(DISPLACEMENT_OPND, $1, $5); +} + | addressRegister selectionList +{ + $$ = buildOperand(SELECTED_OPND, $1, $2); +} + ; + +indexedExpression: + expression '[' _ addressRegister ',' _ register _ SELECT _ W _ ']' +{ + $$ = buildOperand(INDEXED_OPND, $1, $4, $7, 0); +} + | expression '[' _ addressRegister ',' _ register _ SELECT _ L _ ']' +{ + $$ = buildOperand(INDEXED_OPND, $1, $4, $7, 1); +} + | expression '[' _ addressRegister ',' _ register _ ']' +{ + $$ = buildOperand(INDEXED_OPND, $1, $4, $7, 1); +} + | addressRegister '[' _ register _ SELECT _ W _ ']' selectionList +{ + $$ = buildOperand(INDEX_SELECTED_OPND, $11, $1, $4, 0); +} + | addressRegister '[' _ register _ SELECT _ L _ ']' selectionList +{ + $$ = buildOperand(INDEX_SELECTED_OPND, $11, $1, $4, 1); +} + | addressRegister '[' _ register _ ']' selectionList +{ + $$ = buildOperand(INDEX_SELECTED_OPND, $7, $1, $4, 1); +} + | addressRegister '(' _ expression ',' _ register _ ':' _ W _ ')' +{ + $$ = buildOperand(INDEXED_OPND, $4, $1, $7, 0); +} + | addressRegister '(' _ expression ',' _ register _ ':' _ L _ ')' +{ + $$ = buildOperand(INDEXED_OPND, $4, $1, $7, 1); +} + | addressRegister '(' _ expression ',' _ register _ ')' +{ + $$ = buildOperand(INDEXED_OPND, $4, $1, $7, 1); +} + ; + +pcDisplacementExpression: + expression '[' _ PC _ ']' +{ + $$ = buildOperand(PC_DISPLACEMENT_OPND, $1); +} + | PC '@' '(' _ expression _ ')' +{ + $$ = buildOperand(PC_DISPLACEMENT_OPND, $4); +} + ; + +pcIndexedExpression: + expression '[' _ PC ',' _ register _ SELECT _ W _ ']' +{ + $$ = buildOperand(PC_INDEXED_OPND, $1, $7, 0); +} + | expression '[' _ PC ',' _ register _ SELECT _ L _ ']' +{ + $$ = buildOperand(PC_INDEXED_OPND, $1, $7, 1); +} + | PC '@' '(' _ expression ',' _ register _ ':' _ W _ ')' +{ + $$ = buildOperand(PC_INDEXED_OPND, $5, $8, 0); +} + | PC '@' '(' _ expression ',' _ register _ ':' _ L _ ')' +{ + $$ = buildOperand(PC_INDEXED_OPND, $5, $8, 1); +} + ; + +immediateExpression: '#' _ expression +{ + $$ = buildOperand(IMMEDIATE_OPND, $3); +} + ; + +absoluteShortExpression: + expression SELECT _ W +{ + $$ = buildOperand(ABSOLUTE_SHORT_OPND, $1); +} + | expression ': ' _ W +{ + $$ = buildOperand(ABSOLUTE_SHORT_OPND, $1); +} + ; + +absoluteLongExpression: + expression SELECT _ L +{ + $$ = buildOperand(ABSOLUTE_LONG_OPND, $1); +} + | expression ':' _ L +{ + $$ = buildOperand(ABSOLUTE_LONG_OPND, $1); +} + ; + +normalExpression: + expression +{ + $$ = buildOperand(EXPRESSION_OPND, $1); +} + ; + +conditionCodeRegisterExpression: + CCR +{ + $$ = buildOperand(CC_REGISTER_OPND); +} + ; + +statusRegisterExpression: + SR +{ + $$ = buildOperand(STATUS_REGISTER_OPND); +} + ; + +userStackPointerExpression: + USP +{ + $$ = buildOperand(USP_REGISTER_OPND); +} + ; + +controlRegisterExpression: + controlRegister +{ + $$ = buildOperand(CONTROL_REGISTER_OPND, $1); +} + ; diff --git a/main.c b/main.c new file mode 100644 index 0000000..1afc86a --- /dev/null +++ b/main.c @@ -0,0 +1,37 @@ +/* + main.c -- Top level of the Macross assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 5-December-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +main(argc, argv) + int argc; + char *argv[]; +{ + extern char end; + char *sbrk(); + + fflush(stdout); + initializeStuff(argc, argv); + yyparse(); + finishUp(); + if (emitPrint) + printf("storage high water mark 0x%x == %d\n", sbrk(0) - &end, + sbrk(0) - &end); + if (errorFlag) + chokePukeAndDie(); + else + exit(0); +} + + void +printVersion() +{ + printf("Macross %s version 4.20.\n", TARGET_CPU_STRING); +} + diff --git a/main.o b/main.o new file mode 100644 index 0000000..565ac43 Binary files /dev/null and b/main.o differ diff --git a/malloc.c b/malloc.c new file mode 100644 index 0000000..7f1488c --- /dev/null +++ b/malloc.c @@ -0,0 +1,331 @@ +#ifndef lint +static char sccsid[] = "@(#)malloc.c 1.2 (Lucasfilm) 84/10/17"; +/* from malloc.c 4.3 (Berkeley) 9/16/83 */ +#endif + +/* + * malloc.c (Caltech) 2/21/82 + * Chris Kingsley, kingsley@cit-20. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks that + * don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long. + * This is designed for use in a program that uses vast quantities of memory, + * but bombs when it runs out. + */ + +#include + +#define NULL 0 + +/* + * The overhead on a block is at least 4 bytes. When free, this space + * contains a pointer to the next free block, and the bottom two bits must + * be zero. When in use, the first byte is set to MAGIC, and the second + * byte is the size index. The remaining bytes are for alignment. + * If range checking is enabled and the size of the block fits + * in two bytes, then the top two bytes hold the size of the requested block + * plus the range checking words, and the header word MINUS ONE. + */ +union overhead { + union overhead *ov_next; /* when free */ + struct { + u_char ovu_magic; /* magic number */ + u_char ovu_index; /* bucket # */ +#ifdef RCHECK + u_short ovu_size; /* actual block size */ + u_int ovu_rmagic; /* range magic number */ +#endif + } ovu; +#define ov_magic ovu.ovu_magic +#define ov_index ovu.ovu_index +#define ov_size ovu.ovu_size +#define ov_rmagic ovu.ovu_rmagic +}; + +#define MAGIC 0xff /* magic # on accounting info */ +#define RMAGIC 0x55555555 /* magic # on range info */ +#ifdef RCHECK +#define RSLOP sizeof (u_int) +#else +#define RSLOP 0 +#endif + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information + * precedes the data area returned to the user. + */ +#define NBUCKETS 30 +static union overhead *nextf[NBUCKETS]; +extern char *sbrk(); + +#ifdef MSTATS +/* + * nmalloc[i] is the difference between the number of mallocs and frees + * for a given block size. + */ +static u_int nmalloc[NBUCKETS]; +#include +#endif + +#ifdef debug +#define ASSERT(p) if (!(p)) botch("p"); else +static +botch(s) + char *s; +{ + + printf("assertion botched: %s\n", s); + abort(); +} +#else +#define ASSERT(p) +#endif + +char * +malloc(nbytes) + register unsigned nbytes; +{ + register union overhead *p; + register int bucket = 0; + register unsigned shiftr; + + /* + * Convert amount of memory requested into + * closest block size stored in hash buckets + * which satisfies request. Account for + * space used per block for accounting. + */ + nbytes += sizeof (union overhead) + RSLOP; + nbytes = (nbytes + 3) &~ 3; + shiftr = (nbytes - 1) >> 2; + /* apart from this loop, this is O(1) */ + while (shiftr >>= 1) + bucket++; + /* + * If nothing in hash bucket right now, + * request more memory from the system. + */ + if (nextf[bucket] == NULL) + morecore(bucket); + if ((p = (union overhead *)nextf[bucket]) == NULL) + return (NULL); + /* remove from linked list */ + nextf[bucket] = nextf[bucket]->ov_next; + p->ov_magic = MAGIC; + p->ov_index= bucket; +#ifdef MSTATS + nmalloc[bucket]++; +#endif +#ifdef RCHECK + /* + * Record allocated size of block and + * bound space with magic numbers. + */ + if (nbytes <= 0x10000) + p->ov_size = nbytes - 1; + p->ov_rmagic = RMAGIC; + *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC; +#endif + return ((char *)(p + 1)); +} + +/* + * Allocate more memory to the indicated bucket. + */ +static +morecore(bucket) + register bucket; +{ + register union overhead *op; + register int rnu; /* 2^rnu bytes will be requested */ + register int nblks; /* become nblks blocks of the desired size */ + register int siz; + + if (nextf[bucket]) + return; + /* + * Insure memory is allocated + * on a page boundary. Should + * make getpageize call? + */ + op = (union overhead *)sbrk(0); + if ((int)op & 0x3ff) + sbrk(1024 - ((int)op & 0x3ff)); + /* take 2k unless the block is bigger than that */ + /* rnu = (bucket <= 8) ? 11 : bucket + 3; */ + rnu = (bucket <= 10) ? 13 : bucket + 3; /* now grab 8k 'cbm' */ + nblks = 1 << (rnu - (bucket + 3)); /* how many blocks to get */ + if (rnu < bucket) + rnu = bucket; + op = (union overhead *)sbrk(1 << rnu); + /* no more room! */ + if ((int)op == -1) + return; + /* + * Round up to minimum allocation size boundary + * and deduct from block count to reflect. + */ + if ((int)op & 7) { + op = (union overhead *)(((int)op + 8) &~ 7); + nblks--; + } + /* + * Add new memory allocated to that on + * free list for this hash bucket. + */ + nextf[bucket] = op; + siz = 1 << (bucket + 3); + while (--nblks > 0) { + op->ov_next = (union overhead *)((caddr_t)op + siz); + op = (union overhead *)((caddr_t)op + siz); + } +} + +free(cp) + char *cp; +{ + register int size; + register union overhead *op; + + if (cp == NULL) + return; + op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); +#ifdef debug + ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */ +#else + if (op->ov_magic != MAGIC) + return; /* sanity */ +#endif +#ifdef RCHECK + ASSERT(op->ov_rmagic == RMAGIC); + if (op->ov_index <= 13) + ASSERT(*(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC); +#endif + ASSERT(op->ov_index < NBUCKETS); + size = op->ov_index; + op->ov_next = nextf[size]; + nextf[size] = op; +#ifdef MSTATS + nmalloc[size]--; +#endif +} + +/* + * When a program attempts "storage compaction" as mentioned in the + * old malloc man page, it realloc's an already freed block. Usually + * this is the last block it freed; occasionally it might be farther + * back. We have to search all the free lists for the block in order + * to determine its bucket: 1st we make one pass thru the lists + * checking only the first block in each; if that fails we search + * ``realloc_srchlen'' blocks in each list for a match (the variable + * is extern so the caller can modify it). If that fails we just copy + * however many bytes was given to realloc() and hope it's not huge. + */ +int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */ + +char * +realloc(cp, nbytes) + char *cp; + unsigned nbytes; +{ + register u_int onb; + union overhead *op; + char *res; + register int i; + int was_alloced = 0; + + if (cp == NULL) + return (malloc(nbytes)); + op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); + if (op->ov_magic == MAGIC) { + was_alloced++; + i = op->ov_index; + } else { + /* + * Already free, doing "compaction". + * + * Search for the old block of memory on the + * free list. First, check the most common + * case (last element free'd), then (this failing) + * the last ``realloc_srchlen'' items free'd. + * If all lookups fail, then assume the size of + * the memory block being realloc'd is the + * smallest possible. + */ + if ((i = findbucket(op, 1)) < 0 && + (i = findbucket(op, realloc_srchlen)) < 0) + i = 0; + } + onb = (1 << (i + 3)) - sizeof (*op) - RSLOP; + /* avoid the copy if same size block */ + if (was_alloced && + nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP) + return(cp); + if ((res = malloc(nbytes)) == NULL) + return (NULL); + if (cp != res) /* common optimization */ + bcopy(cp, res, (nbytes < onb) ? nbytes : onb); + if (was_alloced) + free(cp); + return (res); +} + +/* + * Search ``srchlen'' elements of each free list for a block whose + * header starts at ``freep''. If srchlen is -1 search the whole list. + * Return bucket number, or -1 if not found. + */ +static +findbucket(freep, srchlen) + union overhead *freep; + int srchlen; +{ + register union overhead *p; + register int i, j; + + for (i = 0; i < NBUCKETS; i++) { + j = 0; + for (p = nextf[i]; p && j != srchlen; p = p->ov_next) { + if (p == freep) + return (i); + j++; + } + } + return (-1); +} + +#ifdef MSTATS +/* + * mstats - print out statistics about malloc + * + * Prints two lines of numbers, one showing the length of the free list + * for each size category, the second showing the number of mallocs - + * frees for each size category. + */ +mstats(s) + char *s; +{ + register int i, j; + register union overhead *p; + int totfree = 0, + totused = 0; + + fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s); + for (i = 0; i < NBUCKETS; i++) { + for (j = 0, p = nextf[i]; p; p = p->ov_next, j++) + ; + fprintf(stderr, " %d", j); + totfree += j * (1 << (i + 3)); + } + fprintf(stderr, "\nused:\t"); + for (i = 0; i < NBUCKETS; i++) { + fprintf(stderr, " %d", nmalloc[i]); + totused += nmalloc[i] * (1 << (i + 3)); + } + fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n", + totused, totfree); +} +#endif diff --git a/malloc.o b/malloc.o new file mode 100644 index 0000000..c7e1ecf Binary files /dev/null and b/malloc.o differ diff --git a/notes68/1.am b/notes68/1.am new file mode 100644 index 0000000..09c4874 --- /dev/null +++ b/notes68/1.am @@ -0,0 +1,51 @@ +Address Modes +------------- + Notation +Number Motorola Name Motorola Sun Sun Name +------ ------------- -------- --- -------- +1 Data Register Direct Dn Dn Register + +2 Address Register Direct An An Register + +3 Address Register Indirect (An) An@ Register + Deferred + +4 Address Register Indirect w/ (An)+ An@+ Postincrement + Postincrement + +5 Address Register Indirect w/ -(An) An@- Predecrement + Predecrement + +6 Address Register Indirect w/ d(An) An@(d) Displacement + Displacement + +7 Address Register Indirect w/ d(An,Rx.W) An@(d,Rx:W) Word Index + Index d(An,Rx.L) An@(d,Rx:L) Long Index + +8 Program Counter w/ Displacement d(PC) PC@(d) PC Displacement + +9 Program Counter w/ Index d(PC,Rx.W) PC@(d,Rx:W) PC Word + Index + d(PC,Rx.L) PC@(d,Rx:L) PC Long + Index + +10 Immediate #xxx #xxx Immediate + +11 Absolute Short xxx.W xxx:W Absolute Short + +12 Absolute Long xxx.L xxx:L Absolute Long + +13 -- -- xxx Normal + +14 (condition code register) CCR CC -- + +15 (status register) SR SR -- + +16 Implied + +17 (user stack pointer) USP USP -- + +18 (control register) SFC SFC -- + DFC DFC + VBR VBR + diff --git a/notes68/2.amg b/notes68/2.amg new file mode 100644 index 0000000..c3fa2c2 --- /dev/null +++ b/notes68/2.amg @@ -0,0 +1,45 @@ +Address Mode Groups +------------------- +ID Mode set Mnemonic +-- -------- -------- +A 1 DATA_REGISTER + +B 2 ADDRESS_REGISTER + +C 4 POSTINCREMENT + +D 5 PREDECREMENT + +E 6 DISPLACEMENT + +F 10 IMMEDIATE + +G 13 NORMAL + +H 14 CONDITION_CODE_REGISTER + +I 15 STATUS_REGISTER + +J 16 (no operand at all!) + +K 17 USER_STACK_POINTER + +L { 17-18 } CONTROL_REGISTER + +M { 1-2 } REGISTER + +N { 1-7, 11-13 } STORABLE + +O { 1-13 } FULL_EA + +P { 1, 3-7, 11-13 } STORABLE_NO_A_REGISTER + +Q { 1, 3-13 } FULL_EA_NO_A_REG + +R { 3-4, 6-9, 11-13 } MISC_1 + +S { 3-7, 11-13 } STORABLE_NO_REGISTER + +T { 3, 5-7, 11-13 } MISC_2 + +U { 3, 6-9, 11-13 } MISC_3 diff --git a/notes68/3.os b/notes68/3.os new file mode 100644 index 0000000..11ce3f8 --- /dev/null +++ b/notes68/3.os @@ -0,0 +1,60 @@ +Operand Sets +------------ + 1 A + 2 AA + 3 AE + 4 AG + 5 AP + 6 AS + + 7 B + 8 BF + 9 BK + +10 CC + +11 DD + +12 EA + +13 F +14 FA +15 FH +16 FI +17 FN +18 FP + +19 G + +20 HP + +21 IP + +22 J + +23 KB + +24 LM + +25 ML +26 MM +27 MP +28 MS +29 M*T + +30 OA +31 OB + +32 P + +33 QA +34 QH +35 QI + +36 RM* + +37 S +38 SM + +39 U +40 UB diff --git a/notes68/4.ic b/notes68/4.ic new file mode 100644 index 0000000..e693f1e --- /dev/null +++ b/notes68/4.ic @@ -0,0 +1,115 @@ +Instruction Classes +------------------- +i ABCD - | AA + ADDX bwl | DD + SBCD - | + SUBX bwl | + +ii ADD bwl | AS + SUB bwl | FP __I + | OA + | OB __A + +iii ADDQ bwl | FN + SUBQ bwl | + +iv AND bwl | AS + OR bwl | FH __CCR + | FI __SR + | FN __I + | GA + +v ASL bwl | AA + ASR bwl | FA + LSL bwl | S + LSR bwl | + ROL bwl | + ROR bwl | + ROXL bwl | + ROXR bwl | + +vi Bcc - | G + BRA - | + BSR - | + +vii BCHG - | AP + BCLR - | FP + BSET - | + BTST - | + +viii CHK - | QA + DIVS - | + DIVU - | + MULS - | + MULU - | + +ix CLR bwl | P + NBCD - | + NEG bwl | + NEGX bwl | + NOT bwl | + Scc - | + TAS - | + TST bwl | + +x CMP bwl | FP __I + | OA + | OB __A + +xi CMPM bwl | CC + +xii DBcc - | AG + +xiii EOR bwl | AP + | FH __CCR + | FI __SR + | FP __I + +xiv EXG - | MM + +xv EXT bwl | A + SWAP - | + +xvi ILLEGAL - | J + NOP - | + RESET - | + RTE - | + RTR - | + RTS - | + TRAPV - | + +xvii JMP - | U + JSR - | + PEA - | + +xviii LEA - | UB + +xix LINK - | BF + +xx MOV bwl | BK __USP + | HP CCR__ + | IP SR__ + | KB __USP + | LM __C + | ML __C + | OB __I + | OP + | QH __CCR + | QI __SR + +xxi MOVEM wl | M*T + | RM* + +xxii MOVEP wl | AE + | EA + +xxiii MOVEQ - | FA + +xxiv MOVS bwl | MS + | SM + +xxv RTD - | F + STOP - | + TRAP - | + +xxvi UNLK - | B diff --git a/object.c b/object.c new file mode 100644 index 0000000..8a4b662 --- /dev/null +++ b/object.c @@ -0,0 +1,612 @@ +/* + object.c -- Routines to output object files for the Macross assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 20-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +static int symbolTableSize; +static int symbolTableStringSize; +bool encodingFunction; + + void +outputObjectFile() +{ + void outputPartition(); + void outputReferenceInfo(); + void outputSymbolTableInfo(); + void outputAbsoluteCode(); + void outputRelocatableCode(); + void outputReservations(); + void outputExpressions(); + void outputFunctions(); + void dumpSymbolTable(); + void enumerateAndCountSymbols(); + + if (debug || emitPrint) + printCodeBuffers(); + outputPartition(); + outputAbsoluteCode(); + if (produceLinkableObject) { + outputPartition(); + outputRelocatableCode(); + outputPartition(); + outputReservations(); + outputPartition(); + enumerateAndCountSymbols(); + outputReferenceInfo(); + outputSymbolTableInfo(); + outputExpressions(); + outputFunctions(); + } + if (symbolTableDumpOn) + dumpSymbolTable(); + fclose(objectFileOutput); +} + + void +outputWord(aWord) + int aWord; +{ + putc(aWord & 0xFF, objectFileOutput); + putc((aWord >> 8) & 0xFF, objectFileOutput); +} + + void +outputPartition() +{ + outputWord(0xFFFF); +} + + void +outputBigword(bigword) + unsigned long bigword; +{ + int i; + + for (i=1; i<=4; i++) { + putc(bigword & 0xFF, objectFileOutput); + bigword >>= 8; + } +} + + void +outputByte(aByte) + byte aByte; +{ + putc(aByte, objectFileOutput); +} + + void +outputString(string) + stringType *string; +{ + do { + putc(*string, objectFileOutput); + } while (*string++ != '\0'); +} + + void +outputStartAddress(startAddress) + addressType startAddress; +{ + outputWord(startAddress); + if (produceLinkableObject) { + outputWord(startAddress - 3); + outputByte(0); + } else { + outputWord(startAddress); + outputByte(0); + } +} + + void +outputRelocatableCode() +{ + int i; + addressType codeStartAddress; + addressType codeEndAddress; + + void outputPseudoSegment(); + void outputBreak(); + + if (haveUserStartAddress && !fixupStartAddress && startAddress-> + kindOfValue == RELOCATABLE_VALUE) + outputStartAddress(startAddress->value); + else if (haveUserStartAddress && fixupStartAddress) + outputStartAddress(0xFFFE); + if (relocatableHighWaterMark < 0) + return; + codeEndAddress = -1; + do { + codeStartAddress = codeEndAddress + 1; + while (codeBreakList != NULL && codeBreakList->breakAddress + == codeStartAddress) { + outputBreak(codeBreakList); + codeBreakList = codeBreakList->nextBreak; + } + if (codeBreakList == NULL) + codeEndAddress = relocatableHighWaterMark; + else + codeEndAddress = codeBreakList->breakAddress - 1; + outputPseudoSegment(codeStartAddress, codeEndAddress); + } while (codeEndAddress < relocatableHighWaterMark); +} + + void +outputBreak(codeBreak) + codeBreakType *codeBreak; +{ + switch (codeBreak->kindOfBreak) { + case BREAK_BREAK: + case END_CONSTRAIN_BREAK: + /* do nothing */ + break; + + case ALIGN_BREAK: + outputWord(codeBreak->breakAddress); + outputWord(codeBreak->breakAddress - 2); + outputWord(codeBreak->breakData); + break; + + case CONSTRAIN_BREAK: + outputWord(codeBreak->breakAddress); + outputWord(codeBreak->breakAddress - 1); + outputWord(codeBreak->breakData); + break; + } +} + + void +outputAbsoluteCode() +{ + int i; + int startSegment; + int endSegment; + int nextSegment; + void outputOneCodeBuffer(); + + if (haveUserStartAddress && !fixupStartAddress && startAddress-> + kindOfValue==ABSOLUTE_VALUE) + outputStartAddress(startAddress->value); + for (startSegment=0; startSegmentcodeEndAddress+1 == + absoluteCodeRegion.codeSegments[nextSegment] + ->codeStartAddress) { + ++endSegment; + ++nextSegment; + } + if (absoluteCodeRegion.codeSegments[startSegment] != NULL) { + outputWord(absoluteCodeRegion.codeSegments[ + startSegment]->codeStartAddress); + outputWord(absoluteCodeRegion.codeSegments[ + endSegment]->codeEndAddress); + for (i=startSegment; i<=endSegment; ++i) + outputOneCodeBuffer(absoluteCodeRegion. + codeSegments[i]); + } + } +} + + void +outputOneCodeBuffer(segment) + codeSegmentType *segment; +{ + int i; + + if (segment != NULL) { +/* outputWord(segment->codeStartAddress); + outputWord(segment->codeEndAddress);*/ + for (i=bufferPosition(segment->codeStartAddress); i<= + bufferPosition(segment->codeEndAddress); i++) + outputByte((*segment->codeBuffer)[i]); + } +} + + void +outputPseudoSegment(codeStartAddress, codeEndAddress) + addressType codeStartAddress; + addressType codeEndAddress; +{ + int startSegment; + int endSegment; + int startPosition; + int endPosition; + int originalStartPosition; + int ultimateEndPosition; + int position; + int segment; + codeSegmentType *segmentPtr; + + void outputWord(); + void outputByte(); + + outputWord(codeStartAddress); + outputWord(codeEndAddress); + startSegment = bufferNumber(codeStartAddress); + endSegment = bufferNumber(codeEndAddress); + originalStartPosition = bufferPosition(codeStartAddress); + ultimateEndPosition = bufferPosition(codeEndAddress); + for (segment=startSegment; segment<=endSegment; segment++) { + segmentPtr = relocatableCodeRegion.codeSegments[segment]; + startPosition = (segment == startSegment) ? + originalStartPosition : 0; + endPosition = (segment == endSegment) ? ultimateEndPosition : + CODE_BUFFER_SIZE - 1; + for(position=startPosition; position<=endPosition; position++) + outputByte((*segmentPtr->codeBuffer)[position]); + } +} + + bool +isObjectSymbol(symbol) + symbolTableEntryType *symbol; +{ + return(symbol != NULL && symbol->context->value != NULL && + symbol->context->value->kindOfValue != FUNCTION_VALUE && + symbol->context->value->kindOfValue != BUILT_IN_FUNCTION_VALUE + && symbol->context->value->kindOfValue != MACRO_VALUE && + ((isExternal(symbol) && symbol->context->value->kindOfValue + != UNDEFINED_VALUE) || symbol->referenceCount > 0)); +/* return(symbol != NULL && symbol->context->value != NULL && + (symbol->context->value->kindOfValue == RELOCATABLE_VALUE || + symbol->context->value->kindOfValue == ABSOLUTE_VALUE || + isExternal(symbol)));*/ +} + + void +enumerateAndCountSymbols() +{ + int i; + symbolTableEntryType *symb; + + symbolTableSize = 0; + symbolTableStringSize = 0; + for (i=0; inextSymbol) + if (isObjectSymbol(symb)) { + symbolTableStringSize += strlen(symb->symbolName) + 1; + symb->ordinal = symbolTableSize++; + } +} + + int +enumerateAndCountReferences() +{ + int result; + int codeMode; + expressionReferenceListType *theReferences; + + result = 0; + for (codeMode=0; codeMode<=1; codeMode++) { + theReferences = expressionReferenceList[codeMode]; + while (theReferences != NULL) { + theReferences->relocation.referenceExpression = result++; + theReferences = theReferences->nextReference; + } + } + return(result); +} + + void +outputReference(reference) + expressionReferenceType *reference; +{ + byte funnyByte; + bigWord funnyWord; + + /* This nonsense is to maintain byte-order and bit-order independence + across host machines so that Macross object files will be + portable. */ + funnyByte = reference->referenceMode | + (reference->referenceRelative << 1) | + (reference->referenceExternal << 2) | + (reference->referenceKind << 3); + funnyWord = ((reference->referenceAddress) & 0xFFFFFF) | + (funnyByte << 24); + outputBigword(funnyWord); + outputBigword(reference->referenceExpression); + +} + +static int referenceCount; + + void +outputReferenceInfo() +{ + expressionReferenceListType *theReferences; + int codeMode; + + outputBigword(referenceCount = enumerateAndCountReferences()); + + for (codeMode=0; codeMode<=1; codeMode++) { + theReferences = expressionReferenceList[codeMode]; + while (theReferences != NULL) { + outputReference(&(theReferences->relocation)); + theReferences = theReferences->nextReference; + } + } +} + + void +outputOneSymbol(symbol) + symbolTableEntryType *symbol; +{ + byte symbolClass; + valueType *symbolValue; + valueType *evaluateIdentifier(); + + if (symbol->context->usage == DEFINE_SYMBOL) + symbolValue = evaluateIdentifier(symbol, FALSE, NO_FIXUP_OK); + else + symbolValue = symbol->context->value; + if (symbolValue->kindOfValue == ABSOLUTE_VALUE) + symbolClass = SYMBOL_ABSOLUTE; + else if (symbolValue->kindOfValue == RELOCATABLE_VALUE) + symbolClass = SYMBOL_RELOCATABLE; + else + symbolClass = SYMBOL_UNDEFINED; + if (isExternal(symbol)) + symbolClass |= SYMBOL_EXTERNAL; + else if (symbolClass == SYMBOL_UNDEFINED) + symbolClass = SYMBOL_ABSOLUTE; + outputByte(symbolClass); + outputBigword(symbolValue->value); + outputString(symbol->symbolName); +} + + void +outputSymbolTableInfo() +{ + int i; + symbolTableEntryType *symb; + + outputBigword(symbolTableSize); + outputBigword(symbolTableStringSize); + for (i=0; inextSymbol) + if (isObjectSymbol(symb)) + outputOneSymbol(symb); +} + + int +symbolCompare(symbol1, symbol2) + symbolTableEntryType **symbol1; + symbolTableEntryType **symbol2; +{ + return(strcmplc((*symbol1)->symbolName, (*symbol2)->symbolName)); +} + + bool +shouldDumpSymbol(symbol) + symbolTableEntryType *symbol; +{ + return(symbolTableDumpOn == 2 + || (symbol->context->usage != BUILT_IN_FUNCTION_SYMBOL + && (symbol->context->usage != DEFINE_SYMBOL + || symbol->context->referenceCount != 0 + || showAllSymbolsFlag + ) + && symbol->symbolName[0] != '$' + && symbol->symbolName[0] != '_' + ) + ); +} + + void +dumpSymbolTable() +{ + int i; + symbolTableEntryType *symb; + symbolTableEntryType **symbolVector; + int numberOfSymbols; + int symbolPtr; + valueType *value; + + valueType *evaluateIdentifier(); + void printValueTersely(); + + numberOfSymbols = 0; + for (i=0; inextSymbol) { + if (symb->context != NULL && symb->context->value != NULL && + (symb->context->value->kindOfValue != + UNDEFINED_VALUE || symb->context->usage == + LABEL_SYMBOL || symb->context->usage == + EXTERNAL_SYMBOL || symb->context->usage == + UNKNOWN_SYMBOL || symb->context->usage == + NESTED_UNKNOWN_SYMBOL)) { + if (shouldDumpSymbol(symb)) { + numberOfSymbols++; + } + } + } + symbolVector = (symbolTableEntryType **)malloc( + sizeof(symbolTableEntryType *) * numberOfSymbols); + symbolPtr = 0; + for (i=0; inextSymbol) { + if (symb->context != NULL && symb->context->value != NULL && + (symb->context->value->kindOfValue != + UNDEFINED_VALUE || symb->context->usage == + LABEL_SYMBOL || symb->context->usage == + EXTERNAL_SYMBOL || symb->context->usage == + UNKNOWN_SYMBOL || symb->context->usage == + NESTED_UNKNOWN_SYMBOL)) { + if (shouldDumpSymbol(symb)) { + symbolVector[symbolPtr++] = symb; + } + } + } + qsort(symbolVector, numberOfSymbols, sizeof(symbolTableEntryType *), + symbolCompare); + for (symbolPtr=0; symbolPtr + symbolName, value->value); + } + } else if (symb->context->usage == FUNCTION_SYMBOL) { + fprintf(symbolDumpFileOutput, "%-20s = FUNCTION\n", + symb->symbolName); + } else if (symbolTableDumpOn == 2 || symb->context->usage != + BUILT_IN_FUNCTION_SYMBOL) { + value = evaluateIdentifier(symb, TRUE, NO_FIXUP_OK); + fprintf(symbolDumpFileOutput, "%-20s = ", symb-> + symbolName); + printValueTersely(value); + fprintf(symbolDumpFileOutput, " [%d]", symb-> + context->referenceCount - 1); + if (isExternal(symb)) + fprintf(symbolDumpFileOutput, " ext"); + fprintf(symbolDumpFileOutput, "\n"); + } + } + free(symbolVector); +} + + bool +hackableSymbol(symbol) + symbolTableEntryType *symbol; +{ + return(symbol->context->usage == DEFINE_SYMBOL || symbol->context-> + usage == LABEL_SYMBOL); +} + + void +printValueTersely(value) + valueType *value; +{ + static char *valueKindTable[NUM_OF_VALUE_KINDS] = { + "ABS", + "DAT", + "REL", + "BSS", + "STT", + "FLD", + "MAC", + "OPN", + "STR", + "CND", + "UND", + "FUN", + "BLK", + "BIF", + "FAL", + }; + + if (value != NULL) + fprintf(symbolDumpFileOutput, "%s: %#6x %d", valueKindTable[ + (int)value->kindOfValue], value->value, value->value); + else + fprintf(symbolDumpFileOutput, "(no value)"); +} + + void +outputReservations() +{ + while (reservationList != NULL) { + outputWord(reservationList->startAddress); + outputWord(reservationList->blockSize); + reservationList = reservationList->nextReservation; + } +} + + void +outputExpressionBuffer() +{ + int i; + + outputBigword(expressionBufferSize); + if (debug || emitPrint) + printExpressionBuffer(); + for (i=0; iexpressionReferenced); + theReferences = theReferences->nextReference; + } + } + if (haveUserStartAddress && fixupStartAddress) + outputOneExpression(startAddress); +} + + void +outputOneFunction(function) + functionDefinitionType *function; +{ + argumentDefinitionListType *argumentList; + bool encodeBlock(); + int countArguments(); + + outputByte((byte)countArguments(function)); + argumentList = function->arguments; + while (argumentList != NULL) { + outputBigword(argumentList->theArgument->ordinal); + argumentList = argumentList->nextArgument; + } + expressionBufferSize = 0; + if (encodeBlock(function->body)) + outputExpressionBuffer(); +} + + void +outputFunctions() +{ + outputBigword(externalFunctionCount); + encodingFunction = TRUE; + while (externalFunctionCount-- > 0) { + outputOneFunction(externalFunctionList); + externalFunctionList = externalFunctionList-> + nextExternalFunction; + } +} diff --git a/object.o b/object.o new file mode 100644 index 0000000..66ba718 Binary files /dev/null and b/object.o differ diff --git a/operandBody_6502.h b/operandBody_6502.h new file mode 100644 index 0000000..bc1af12 --- /dev/null +++ b/operandBody_6502.h @@ -0,0 +1,59 @@ +/* + operandBody_6502.h -- Define parser tree types for 6502 operands. + + Chip Morningstar -- Lucasfilm Ltd. + + 18-April-1985 +*/ + +typedef stringType stringOperandBodyType; + +typedef expressionType xIndexedOperandBodyType; + +typedef expressionType yIndexedOperandBodyType; + +typedef expressionType preIndexedXOperandBodyType; + +typedef expressionType postIndexedYOperandBodyType; + +typedef nullType yRegisterOperandBodyType; + +typedef nullType xRegisterOperandBodyType; + +typedef nullType aRegisterOperandBodyType; + +typedef expressionType immediateOperandBodyType; + +typedef expressionType indirectOperandBodyType; + +typedef expressionType expressionOperandBodyType; + +typedef BlockType blockOperandBodyType; + +typedef selectionListType xSelectedOperandBodyType; + +typedef selectionListType ySelectedOperandBodyType; + +typedef selectionListType preSelectedOperandBodyType; + +#define BlockOperandBodyType anyOldThing /* kludge */ +/* doing above right confuses compiler as it is a forward reference inside + yon union: */ + +typedef union { + expressionOperandBodyType *expressionUnion; + immediateOperandBodyType *immediateUnion; + indirectOperandBodyType *indirectUnion; + aRegisterOperandBodyType *aRegisterUnion; + xRegisterOperandBodyType *xRegisterUnion; + yRegisterOperandBodyType *yRegisterUnion; + postIndexedYOperandBodyType *postIndexedYUnion; + preIndexedXOperandBodyType *preIndexedXUnion; + xIndexedOperandBodyType *xIndexedUnion; + yIndexedOperandBodyType *yIndexedUnion; + xSelectedOperandBodyType *xSelectedUnion; + ySelectedOperandBodyType *ySelectedUnion; + preSelectedOperandBodyType *preSelectedUnion; + stringOperandBodyType *stringUnion; + BlockOperandBodyType *blockUnion; + } operandBodyType; diff --git a/operandBody_68000.h b/operandBody_68000.h new file mode 100644 index 0000000..b8fda7f --- /dev/null +++ b/operandBody_68000.h @@ -0,0 +1,81 @@ +/* + operandBody_68000.h -- Define parser tree types for 68000 operands. + + Chip Morningstar -- Lucasfilm Ltd. + + 25-April-1985 +*/ + +typedef expressionType expressionOperandBodyType; + +typedef stringType stringOperandBodyType; + +typedef BlockType blockOperandBodyType; + +typedef nullType dRegisterOperandBodyType; + +typedef nullType aRegisterOperandBodyType; + +typedef nullType aRegisterIndirectOperandBodyType; + +typedef nullType postincrementOperandBodyType; + +typedef nullType predecrementOperandBodyType; + +typedef expressionType displacementOperandBodyType; + +typedef selectionListType selectedOperandBodyType; + +typedef expressionType indexedOperandBodyType; + +typedef selectionListType indexSelectedOperandBodyType; + +typedef expressionType pcDisplacementOperandBodyType; + +typedef expressionType pcIndexedOperandBodyType; + +typedef expressionType immediateOperandBodyType; + +typedef expressionType absoluteShortOperandBodyType; + +typedef expressionType absoluteLongOperandBodyType; + +typedef nullType ccRegisterOperandBodyType; + +typedef nullType statusRegisterOperandBodyType; + +typedef nullType uspRegisterOperandBodyType; + +typedef nullType controlRegisterOperandBodyType; + +#define BlockOperandBodyType anyOldThing /* kludge */ +/* doing above right confuses compiler as it is a forward reference inside + yon union: */ + +typedef union { + expressionOperandBodyType *expressionUnion; + stringOperandBodyType *stringUnion; + BlockOperandBodyType *blockUnion; + dRegisterOperandBodyType *dRegisterUnion; + aRegisterOperandBodyType *aRegisterUnion; + aRegisterIndirectOperandBodyType *aRegisterIndirectUnion; + postincrementOperandBodyType *postincrementUnion; + predecrementOperandBodyType *predecrementUnion; + displacementOperandBodyType *displacementUnion; + selectedOperandBodyType *selectionUnion; + indexedOperandBodyType *indexedUnion; + indexSelectedOperandBodyType *indexSelectedUnion; + pcDisplacementOperandBodyType *pcDisplacementUnion; + pcIndexedOperandBodyType *pcIndexedUnion; + immediateOperandBodyType *immediateUnion; + absoluteShortOperandBodyType *absoluteShortUnion; + absoluteLongOperandBodyType *absoluteLongUnion; + ccRegisterOperandBodyType *ccRegisterUnion; + statusRegisterOperandBodyType *statusRegisterUnion; + uspRegisterOperandBodyType *uspRegisterUnion; + controlRegisterOperandBodyType *controlRegisterUnion; + } operandBodyType; + +#define SFC_REGISTER 0 +#define DFC_REGISTER 1 +#define VBR_REGISTER 2 diff --git a/operandDefs_6502.h b/operandDefs_6502.h new file mode 100644 index 0000000..0466578 --- /dev/null +++ b/operandDefs_6502.h @@ -0,0 +1,80 @@ +/* + operandDefs_6502.h -- Define operand types and flag bits for 6502. + + Chip Morningstar -- Lucasfilm Ltd. + + 18-April-1985 +*/ + +typedef enum { + EXPRESSION_OPND, IMMEDIATE_OPND, INDIRECT_OPND, + A_REGISTER_OPND, X_REGISTER_OPND, Y_REGISTER_OPND, + POST_INDEXED_Y_OPND, PRE_INDEXED_X_OPND, X_INDEXED_OPND, + Y_INDEXED_OPND, X_SELECTED_OPND, Y_SELECTED_OPND, + PRE_SELECTED_X_OPND, STRING_OPND, BLOCK_OPND + } operandKindType; + +#define operandKindField(op) op + +/* Opcodes: */ +/* In the opcode table we want to have information that tells which possible + address modes the corresponding instruction can utilize. The + instruction set of the 6502 breaks up into classes of instructions, such + that all of the instructions in a class accept the same address modes. + We encode the instructions by class and the classes by permissible address + modes. This helps us reduce errors in construction of the opcode table, + since getting one instruction of a given class right means getting all the + others right too. */ +typedef enum { + RELATIVE, DIR_1, DIR_2, DIR_INDIR, DIR_X_1, DIR_X_2, DIR_X_3, + DIR_Y, IMM_DIR, IMM_DIR_X, IMM_DIR_Y, NONE, INDEX, IMM_INDEX + } addressClassType; + +#define NO_OPND_BIT 0x0000 +#define EXPRESSION_OPND_BIT 0x0001 +#define IMMEDIATE_OPND_BIT 0x0002 +#define INDIRECT_OPND_BIT 0x0004 +#define A_REGISTER_OPND_BIT 0x0008 +#define X_REGISTER_OPND_BIT 0x0010 +#define Y_REGISTER_OPND_BIT 0x0020 +#define POST_INDEXED_Y_OPND_BIT 0x0040 +#define PRE_INDEXED_X_OPND_BIT 0x0080 +#define X_INDEXED_OPND_BIT 0x0100 +#define Y_INDEXED_OPND_BIT 0x0200 +#define X_SELECTED_OPND_BIT 0x0400 +#define Y_SELECTED_OPND_BIT 0x0800 +#define PRE_SELECTED_X_OPND_BIT 0x1000 +#define STRING_OPND_BIT 0x2000 +#define BLOCK_OPND_BIT 0x4000 +#define ANY_OPND_BITS 0xFFFF + +#define REL_CLASS_BITS EXPRESSION_OPND_BIT +#define DIR_1_CLASS_BITS EXPRESSION_OPND_BIT +#define DIR_2_CLASS_BITS EXPRESSION_OPND_BIT +#define DIR_INDIR_CLASS_BITS EXPRESSION_OPND_BIT | INDIRECT_OPND_BIT +#define DIR_X_1_CLASS_BITS EXPRESSION_OPND_BIT | X_INDEXED_OPND_BIT | \ + X_SELECTED_OPND_BIT | A_REGISTER_OPND_BIT +#define DIR_X_2_CLASS_BITS EXPRESSION_OPND_BIT | X_INDEXED_OPND_BIT | \ + X_SELECTED_OPND_BIT +#define DIR_X_3_CLASS_BITS EXPRESSION_OPND_BIT | X_INDEXED_OPND_BIT | \ + X_SELECTED_OPND_BIT +#define DIR_Y_CLASS_BITS EXPRESSION_OPND_BIT | Y_INDEXED_OPND_BIT | \ + Y_SELECTED_OPND_BIT +#define IMM_DIR_CLASS_BITS EXPRESSION_OPND_BIT | IMMEDIATE_OPND_BIT +#define IMM_DIR_X_CLASS_BITS EXPRESSION_OPND_BIT | IMMEDIATE_OPND_BIT | \ + X_INDEXED_OPND_BIT | X_SELECTED_OPND_BIT +#define IMM_DIR_Y_CLASS_BITS EXPRESSION_OPND_BIT | IMMEDIATE_OPND_BIT | \ + Y_INDEXED_OPND_BIT | Y_SELECTED_OPND_BIT +#define NONE_CLASS_BITS NO_OPND_BIT +#define IMM_INDEX_CLASS_BITS X_INDEXED_OPND_BIT | Y_INDEXED_OPND_BIT | \ + X_SELECTED_OPND_BIT | Y_SELECTED_OPND_BIT | \ + IMMEDIATE_OPND_BIT | PRE_INDEXED_X_OPND_BIT |\ + POST_INDEXED_Y_OPND_BIT | \ + EXPRESSION_OPND_BIT | PRE_SELECTED_X_OPND_BIT +#define INDEX_CLASS_BITS X_INDEXED_OPND_BIT | Y_INDEXED_OPND_BIT | \ + X_SELECTED_OPND_BIT | Y_SELECTED_OPND_BIT | \ + PRE_INDEXED_X_OPND_BIT | \ + POST_INDEXED_Y_OPND_BIT | \ + EXPRESSION_OPND_BIT | PRE_SELECTED_X_OPND_BIT + +#define MAX_NUMBER_OF_OPERANDS 1 diff --git a/operandDefs_68000.h b/operandDefs_68000.h new file mode 100644 index 0000000..5a951d3 --- /dev/null +++ b/operandDefs_68000.h @@ -0,0 +1,279 @@ +/* + operandDefs_68000.h -- Define operand types and flag bits for 68000. + + Chip Morningstar -- Lucasfilm Ltd. + + 25-April-1985 +*/ + +typedef enum { + EXPRESSION_OPND, STRING_OPND, BLOCK_OPND, D_REGISTER_OPND, + A_REGISTER_OPND, A_REGISTER_INDIRECT_OPND, POSTINCREMENT_OPND, + PREDECREMENT_OPND, DISPLACEMENT_OPND, INDEXED_OPND, + PC_DISPLACEMENT_OPND, PC_INDEXED_OPND, IMMEDIATE_OPND, + ABSOLUTE_SHORT_OPND, ABSOLUTE_LONG_OPND, CC_REGISTER_OPND, + STATUS_REGISTER_OPND, USP_REGISTER_OPND, + CONTROL_REGISTER_OPND, SELECTED_OPND, INDEX_SELECTED_OPND, + } operandKindType; + +/*** Hack warning ***/ + +/* We know that enumerated types are actually just ints. Some of the address + modes require some additional information in the form of one or two + register numbers. We want to still encode this information in one int. + Therefor, we are going to OR some bits representing the register into the + higher-order bits of the type word, thus violating the principle of + enumerated types (it's just that the 'enum' syntax above is so much cleaner + than a bunch of '#define's) */ + +#define getRegisterField(op, n) ((((int)op)>>(8+(n-1)*4)) & 0xF) +#define setRegisterField(op, n, r) (op=((int)op | \ + (((r)&0xF)<<(8+((n)-1)*4)))) + +#define getAddressRegister(op) (getRegisterField(op, 1) - 8) +#define getDataRegister(op) getRegisterField(op, 1) +#define getRegister(op) getRegisterField(op, 1) +#define getIndexRegister(op) getRegisterField(op, 2) +#define getWL(op) (((int)op >> 16) & 1) + +#define setAddressRegister(op, r) setRegisterField(op, 1, (int)r + 8) +#define setDataRegister(op, r) setRegisterField(op, 1, (int)r) +#define setRegister(op, r) setRegisterField(op, 1, (int)r) +#define setIndexRegister(op, r) setRegisterField(op, 2, (int)r) +#define setWL(op, wl) (op = ((int)op | (((wl) & 1) << 16))) + +#define operandKindField(op) (operandKindType)((int)op & 0xFF) + +/* Opcodes: */ +/* In the opcode table we want to have information that tells which possible + address modes the corresponding instruction can utilize. The + instruction set of the 68000 breaks up into classes of instructions, such + that all of the instructions in a class accept the same address modes. + We encode the instructions by class and the classes by permissible address + modes. This helps us reduce errors in construction of the opcode table, + since getting one instruction of a given class right means getting all the + others right too. Ordinarily we'd give each class a nice mnemonic name, + but the 68000 has 26 idiosyncratic classes and a unique name for each + would confuse more than it would help. */ + +typedef enum { + CLASS_I, CLASS_II, CLASS_III, CLASS_IV, CLASS_V, CLASS_VI, + CLASS_VII, CLASS_VIII, CLASS_IX, CLASS_X, CLASS_XI, CLASS_XII, + CLASS_XIII, CLASS_XIV, CLASS_XV, CLASS_XVI, CLASS_XVII, + CLASS_XVIII, CLASS_XIX, CLASS_XX, CLASS_XXI, CLASS_XXII, + CLASS_XXIII, CLASS_XXIV, CLASS_XXV, CLASS_XXVI, CLASS_XXVII, + CLASS_XXVIII, + } addressClassType; + +/* The various address modes as required by the various instructions manage to + sort themselves into a number of independent groups. We will give these + groups names to facilitate operand address mode checking */ + +#define NO_OPND_BIT 0x000000 +#define EXPRESSION_OPND_BIT 0x000001 +#define STRING_OPND_BIT 0x000002 +#define BLOCK_OPND_BIT 0x000004 +#define D_REGISTER_OPND_BIT 0x000008 +#define A_REGISTER_OPND_BIT 0x000010 +#define A_REGISTER_INDIRECT_OPND_BIT 0x000020 +#define POSTINCREMENT_OPND_BIT 0x000040 +#define PREDECREMENT_OPND_BIT 0x000080 +#define DISPLACEMENT_OPND_BIT 0x000100 +#define INDEXED_OPND_BIT 0x000200 +#define PC_DISPLACEMENT_OPND_BIT 0x000400 +#define PC_INDEXED_OPND_BIT 0x000800 +#define IMMEDIATE_OPND_BIT 0x001000 +#define ABSOLUTE_SHORT_OPND_BIT 0x002000 +#define ABSOLUTE_LONG_OPND_BIT 0x004000 +#define CC_REGISTER_OPND_BIT 0x008000 +#define STATUS_REGISTER_OPND_BIT 0x010000 +#define USP_REGISTER_OPND_BIT 0x020000 +#define CONTROL_REGISTER_OPND_BIT 0x040000 +#define SELECTED_OPND_BIT 0x080000 +#define INDEX_SELECTED_OPND_BIT 0x100000 +#define ANY_OPND_BITS 0xFFFFFF + +#define D_REGISTER_GROUP_BITS D_REGISTER_OPND_BIT +#define GROUP_A D_REGISTER_GROUP_BITS + +#define A_REGISTER_GROUP_BITS A_REGISTER_OPND_BIT +#define GROUP_B A_REGISTER_GROUP_BITS + +#define POSTINCREMENT_GROUP_BITS POSTINCREMENT_OPND_BIT +#define GROUP_C POSTINCREMENT_GROUP_BITS + +#define PREDECREMENT_GROUP_BITS PREDECREMENT_OPND_BIT +#define GROUP_D PREDECREMENT_GROUP_BITS + +#define DISPLACEMENT_GROUP_BITS (DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT) +#define GROUP_E DISPLACEMENT_GROUP_BITS + +#define IMMEDIATE_GROUP_BITS IMMEDIATE_OPND_BIT +#define GROUP_F IMMEDIATE_GROUP_BITS + +#define NORMAL_GROUP_BITS EXPRESSION_OPND_BIT +#define GROUP_G NORMAL_GROUP_BITS + +#define CC_REGISTER_GROUP_BITS CC_REGISTER_OPND_BIT +#define GROUP_H CC_REGISTER_GROUP_BITS + +#define STATUS_REGISTER_GROUP_BITS STATUS_REGISTER_OPND_BIT +#define GROUP_I STATUS_REGISTER_GROUP_BITS + +#define IMPLIED_GROUP_BITS NO_OPND_BIT +#define GROUP_J IMPLIED_GROUP_BITS + +#define USP_REGISTER_GROUP_BITS USP_REGISTER_OPND_BIT +#define GROUP_K USP_REGISTER_GROUP_BITS + +#define CONTROL_REGISTER_GROUP_BITS (USP_REGISTER_OPND_BIT | \ + CONTROL_REGISTER_OPND_BIT) +#define GROUP_L CONTROL_REGISTER_GROUP_BITS + +#define REGISTER_GROUP_BITS (D_REGISTER_OPND_BIT | \ + A_REGISTER_OPND_BIT) +#define GROUP_M REGISTER_GROUP_BITS + +#define STORABLE_GROUP_BITS (D_REGISTER_OPND_BIT | \ + A_REGISTER_OPND_BIT | \ + A_REGISTER_INDIRECT_OPND_BIT | \ + POSTINCREMENT_OPND_BIT | \ + PREDECREMENT_OPND_BIT | \ + DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT | \ + INDEXED_OPND_BIT | \ + INDEX_SELECTED_OPND_BIT | \ + ABSOLUTE_SHORT_OPND_BIT | \ + ABSOLUTE_LONG_OPND_BIT | \ + EXPRESSION_OPND_BIT) +#define GROUP_N STORABLE_GROUP_BITS + +#define FULL_EA_GROUP_BITS (D_REGISTER_OPND_BIT | \ + A_REGISTER_OPND_BIT | \ + A_REGISTER_INDIRECT_OPND_BIT | \ + POSTINCREMENT_OPND_BIT | \ + PREDECREMENT_OPND_BIT | \ + DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT | \ + INDEXED_OPND_BIT | \ + INDEX_SELECTED_OPND_BIT | \ + PC_DISPLACEMENT_OPND_BIT | \ + PC_INDEXED_OPND_BIT | \ + IMMEDIATE_OPND_BIT | \ + ABSOLUTE_SHORT_OPND_BIT | \ + ABSOLUTE_LONG_OPND_BIT | \ + EXPRESSION_OPND_BIT) +#define GROUP_O FULL_EA_GROUP_BITS + +#define STORABLE_NO_A_REGISTER_GROUP_BITS \ + (D_REGISTER_OPND_BIT | \ + A_REGISTER_INDIRECT_OPND_BIT | \ + POSTINCREMENT_OPND_BIT | \ + PREDECREMENT_OPND_BIT | \ + DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT | \ + INDEXED_OPND_BIT | \ + INDEX_SELECTED_OPND_BIT | \ + ABSOLUTE_SHORT_OPND_BIT | \ + ABSOLUTE_LONG_OPND_BIT | \ + EXPRESSION_OPND_BIT) +#define GROUP_P STORABLE_NO_A_REGISTER_GROUP_BITS + +#define FULL_EA_NO_A_REGISTER_GROUP_BITS (D_REGISTER_OPND_BIT | \ + A_REGISTER_INDIRECT_OPND_BIT | \ + POSTINCREMENT_OPND_BIT | \ + PREDECREMENT_OPND_BIT | \ + DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT | \ + INDEXED_OPND_BIT | \ + INDEX_SELECTED_OPND_BIT | \ + PC_DISPLACEMENT_OPND_BIT | \ + PC_INDEXED_OPND_BIT | \ + IMMEDIATE_OPND_BIT | \ + ABSOLUTE_SHORT_OPND_BIT | \ + ABSOLUTE_LONG_OPND_BIT | \ + EXPRESSION_OPND_BIT) +#define GROUP_Q FULL_EA_NO_A_REGISTER_GROUP_BITS + +#define MISC_1_GROUP_BITS (A_REGISTER_INDIRECT_OPND_BIT | \ + POSTINCREMENT_OPND_BIT | \ + DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT | \ + INDEXED_OPND_BIT | \ + INDEX_SELECTED_OPND_BIT | \ + PC_DISPLACEMENT_OPND_BIT | \ + PC_INDEXED_OPND_BIT | \ + ABSOLUTE_SHORT_OPND_BIT | \ + ABSOLUTE_LONG_OPND_BIT | \ + EXPRESSION_OPND_BIT) +#define GROUP_R MISC_1_GROUP_BITS + +#define STORABLE_NO_REGISTER_GROUP_BITS (A_REGISTER_INDIRECT_OPND_BIT | \ + POSTINCREMENT_OPND_BIT | \ + PREDECREMENT_OPND_BIT | \ + DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT | \ + INDEXED_OPND_BIT | \ + INDEX_SELECTED_OPND_BIT | \ + ABSOLUTE_SHORT_OPND_BIT | \ + ABSOLUTE_LONG_OPND_BIT | \ + EXPRESSION_OPND_BIT) +#define GROUP_S STORABLE_NO_REGISTER_GROUP_BITS + +#define MISC_2_GROUP_BITS (A_REGISTER_INDIRECT_OPND_BIT | \ + PREDECREMENT_OPND_BIT | \ + DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT | \ + INDEXED_OPND_BIT | \ + INDEX_SELECTED_OPND_BIT | \ + ABSOLUTE_SHORT_OPND_BIT | \ + ABSOLUTE_LONG_OPND_BIT | \ + EXPRESSION_OPND_BIT) +#define GROUP_T MISC_2_GROUP_BITS + +#define MISC_3_GROUP_BITS (A_REGISTER_INDIRECT_OPND_BIT | \ + DISPLACEMENT_OPND_BIT | \ + SELECTED_OPND_BIT | \ + INDEXED_OPND_BIT | \ + INDEX_SELECTED_OPND_BIT | \ + PC_DISPLACEMENT_OPND_BIT | \ + PC_INDEXED_OPND_BIT | \ + ABSOLUTE_SHORT_OPND_BIT | \ + ABSOLUTE_LONG_OPND_BIT | \ + EXPRESSION_OPND_BIT) +#define GROUP_U MISC_3_GROUP_BITS + +#define CLASS_I_BITS (GROUP_A | GROUP_D) +#define CLASS_II_BITS (GROUP_A | GROUP_B | GROUP_F | GROUP_O | \ + GROUP_P | GROUP_S) +#define CLASS_III_BITS (GROUP_F | GROUP_N) +#define CLASS_IV_BITS (GROUP_A | GROUP_F | GROUP_H | GROUP_I | \ + GROUP_P | GROUP_Q | GROUP_S) +#define CLASS_V_BITS (GROUP_A | GROUP_F | GROUP_S) +#define CLASS_VI_BITS GROUP_G +#define CLASS_VII_BITS (GROUP_A | GROUP_F | GROUP_P) +#define CLASS_VIII_BITS (GROUP_A | GROUP_Q) +#define CLASS_IX_BITS GROUP_P +#define CLASS_X_BITS (GROUP_A | GROUP_B | GROUP_F | GROUP_O | GROUP_P) +#define CLASS_XI_BITS GROUP_C +#define CLASS_XII_BITS (GROUP_A | GROUP_G) +#define CLASS_XIII_BITS (GROUP_A | GROUP_F | GROUP_H | GROUP_I | GROUP_P) +#define CLASS_XIV_BITS GROUP_M +#define CLASS_XV_BITS GROUP_A +#define CLASS_XVI_BITS GROUP_J +#define CLASS_XVII_BITS GROUP_U +#define CLASS_XVIII_BITS (GROUP_B | GROUP_U) +#define CLASS_XIX_BITS (GROUP_B | GROUP_F) +#define CLASS_XX_BITS (GROUP_B | GROUP_H | GROUP_I | GROUP_K | \ + GROUP_L | GROUP_M | GROUP_O | GROUP_Q) +#define CLASS_XXI_BITS (GROUP_M | GROUP_R | GROUP_T) +#define CLASS_XXII_BITS (GROUP_A | GROUP_E) +#define CLASS_XXIII_BITS (GROUP_A | GROUP_F) +#define CLASS_XXIV_BITS (GROUP_M | GROUP_S) +#define CLASS_XXV_BITS GROUP_F +#define CLASS_XXVI_BITS GROUP_B +#define CLASS_XXVII_BITS GROUP_F +#define CLASS_XXVIII_BITS GROUP_F + +#define MAX_NUMBER_OF_OPERANDS 17 diff --git a/operandStuffSD.o b/operandStuffSD.o new file mode 100644 index 0000000..010a02a Binary files /dev/null and b/operandStuffSD.o differ diff --git a/operandStuffSD_6502.c b/operandStuffSD_6502.c new file mode 100644 index 0000000..64828b7 --- /dev/null +++ b/operandStuffSD_6502.c @@ -0,0 +1,389 @@ +/* + operandStuff_6502.c -- Various target processor routines to handle + operands in the Macross assembler (6502 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 23-April-1985 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* corresponds to routines in buildStuff2.c */ + + operandType * +buildOperand(kindOfOperand, arg) + operandKindType kindOfOperand; + anyOldThing *arg; +{ + operandType *result; + + result = typeAlloc(operandType); + result->kindOfOperand = kindOfOperand; + result->nextOperand = NULL; + switch (kindOfOperand) { + + case EXPRESSION_OPND: + result->theOperand.expressionUnion = + (expressionOperandBodyType *) arg; + break; + + case IMMEDIATE_OPND: + result->theOperand.immediateUnion = + (immediateOperandBodyType *) arg; + break; + + case INDIRECT_OPND: + result->theOperand.indirectUnion = + (indirectOperandBodyType *) arg; + break; + + case A_REGISTER_OPND: + result->theOperand.aRegisterUnion = + (aRegisterOperandBodyType *) NULL; + break; + + case X_REGISTER_OPND: + result->theOperand.xRegisterUnion = + (xRegisterOperandBodyType *) NULL; + break; + + case Y_REGISTER_OPND: + result->theOperand.yRegisterUnion = + (yRegisterOperandBodyType *) NULL; + break; + + case POST_INDEXED_Y_OPND: + result->theOperand.postIndexedYUnion = + (postIndexedYOperandBodyType *) arg; + break; + + case PRE_INDEXED_X_OPND: + result->theOperand.preIndexedXUnion = + (preIndexedXOperandBodyType *) arg; + break; + + case X_INDEXED_OPND: + result->theOperand.xIndexedUnion = + (xIndexedOperandBodyType *) arg; + break; + + case Y_INDEXED_OPND: + result->theOperand.yIndexedUnion = + (yIndexedOperandBodyType *) arg; + break; + + case X_SELECTED_OPND: + result->theOperand.xSelectedUnion = + (xSelectedOperandBodyType *) arg; + break; + + case Y_SELECTED_OPND: + result->theOperand.ySelectedUnion = + (ySelectedOperandBodyType *) arg; + break; + + case PRE_SELECTED_X_OPND: + result->theOperand.preSelectedUnion = + (preSelectedOperandBodyType *) arg; + break; + + case STRING_OPND: + result->theOperand.stringUnion = + (stringOperandBodyType *) arg; + break; + + case BLOCK_OPND: + result->theOperand.blockUnion = (BlockOperandBodyType *) arg; + break; + + default: + botch("unknown operand kind: %d\n", kindOfOperand); + break; + } + return(result); +} + +/* corresponds to routines in fixups.c */ + + operandListType * +duplicateOperandForFixup(operand, isSpecialFunctionOperand) + operandListType *operand; + bool isSpecialFunctionOperand; +{ + operandListType *result; + + expressionType *duplicateExpressionForFixup(); + + result = typeAlloc(operandListType); + result->kindOfOperand = operand->kindOfOperand; + result->nextOperand = NULL; + if (operand->kindOfOperand != EXPRESSION_OPND) + newFixupAddressMode = operand->kindOfOperand; + switch (operand->kindOfOperand) { + case EXPRESSION_OPND: + case IMMEDIATE_OPND: + case INDIRECT_OPND: + case POST_INDEXED_Y_OPND: + case PRE_INDEXED_X_OPND: + case X_INDEXED_OPND: + case Y_INDEXED_OPND: + result->theOperand.expressionUnion = + duplicateExpressionForFixup(operand->theOperand, + FALSE, isSpecialFunctionOperand); + break; + case X_SELECTED_OPND: + case Y_SELECTED_OPND: + case PRE_SELECTED_X_OPND: + result->theOperand.expressionUnion = + duplicateExpressionForFixup(operand->theOperand, + FALSE, isSpecialFunctionOperand); + break; + case A_REGISTER_OPND: + case X_REGISTER_OPND: + case Y_REGISTER_OPND: + result->theOperand = operand->theOperand; + break; + case STRING_OPND: + result->theOperand = operand->theOperand; + break; + case BLOCK_OPND: + error(CANT_FORWARD_REFERENCE_BLOCK_ERROR); + result = NULL; + break; + } + return(result); +} + +/* corresponds to routines in garbage.c */ + +#define nullFree(thing) if (thing == NULL) return; + + void +freeOperand(operand) + operandType *operand; +{ + nullFree(operand); + switch (operand->kindOfOperand) { + + case EXPRESSION_OPND: + case IMMEDIATE_OPND: + case INDIRECT_OPND: + case POST_INDEXED_Y_OPND: + case PRE_INDEXED_X_OPND: + case X_INDEXED_OPND: + case Y_INDEXED_OPND: + freeExpression(operand->theOperand); + break; + + case A_REGISTER_OPND: + case X_REGISTER_OPND: + case Y_REGISTER_OPND: + break; + + case X_SELECTED_OPND: + case Y_SELECTED_OPND: + case PRE_SELECTED_X_OPND: + freeSelectionList(operand->theOperand); + break; + + case STRING_OPND: + freeString(operand->theOperand); + break; + + case BLOCK_OPND: + freeBlock(operand->theOperand); + break; + + default: + botch("bad operand kind in freeOperand %d\n", + operand->kindOfOperand); + break; + } + freeOperand(operand->nextOperand); + free(operand); +} + +/* corresponds to routines in listing.c */ + + void +expandOperand(addressMode) + operandKindType addressMode; +{ + switch (addressMode) { + case IMMEDIATE_OPND: moreText("#"); break; + case INDIRECT_OPND: moreText("@"); break; + case POST_INDEXED_Y_OPND: moreText("y[@"); break; + case PRE_INDEXED_X_OPND: moreText("@x["); break; + case X_INDEXED_OPND: moreText("x["); break; + case Y_INDEXED_OPND: moreText("y["); break; + case A_REGISTER_OPND: moreText("a"); break; + case X_REGISTER_OPND: moreText("x"); break; + case Y_REGISTER_OPND: moreText("y"); break; + case X_SELECTED_OPND: moreText("x"); break; + case Y_SELECTED_OPND: moreText("y"); break; + case PRE_SELECTED_X_OPND: moreText("@x"); break; + default: break; + } + expandExpression(NULL); + if (addressMode == POST_INDEXED_Y_OPND || + addressMode == PRE_INDEXED_X_OPND || + addressMode == X_INDEXED_OPND || + addressMode == Y_INDEXED_OPND) + moreText("]"); +} + +/* corresponds to routines in expressionSemantics.c */ + +#define nullEvaluate(thing) if (thing==NULL) return(NULL); +#define fail(err) if (!expressionFailed) {\ + error(err);\ + expressionFailed = TRUE;\ + } +#define fail1(err,arg) if (!expressionFailed) {\ + error(err,arg);\ + expressionFailed = TRUE;\ + } +#define fail2(err,arg1,arg2) if (!expressionFailed) {\ + error(err,arg1,arg2);\ + expressionFailed = TRUE;\ + } + +#define qfree2(a,b) if (freeFlag) { free(a); free(b); } + +#define expansionOff() {saveExpansion=expandMacros; expandMacros=FALSE;} +#define forceExpansion() {saveExpansion=expandMacros; expandMacros=TRUE;} +#define expansionOn() expandMacros=saveExpansion; + + valueType * +evaluateOperand(operand) + operandType *operand; +{ + valueType *result; + bool saveExpansion; + expressionType *expression; + + valueType *evaluateExpression(); + valueType *evaluateSelectionList(); + valueType *newValue(); + + nullEvaluate(operand); + if (operand->kindOfOperand != EXPRESSION_OPND) + newFixupAddressMode = operand->kindOfOperand; + switch (operand->kindOfOperand) { + + case EXPRESSION_OPND: + case IMMEDIATE_OPND: + case INDIRECT_OPND: + case POST_INDEXED_Y_OPND: + case PRE_INDEXED_X_OPND: + case X_INDEXED_OPND: + case Y_INDEXED_OPND: + result = evaluateExpression(operand->theOperand, + performingFixups ? NO_FIXUP : OPERAND_FIXUP); + if (operand->kindOfOperand != EXPRESSION_OPND) { + if (result->addressMode != EXPRESSION_OPND) { + error(BAD_ADDRESS_MODE_ERROR); + result->kindOfValue = FAIL; + } else { + result->addressMode = operand->kindOfOperand; + } + } + break; + + case A_REGISTER_OPND: + case X_REGISTER_OPND: + case Y_REGISTER_OPND: + result = newValue(UNDEFINED_VALUE, 0, operand-> + kindOfOperand); + break; + + case X_SELECTED_OPND: + case Y_SELECTED_OPND: + case PRE_SELECTED_X_OPND: + result = evaluateSelectionList(operand->theOperand); + if (result->addressMode != EXPRESSION_OPND) { + error(BAD_ADDRESS_MODE_ERROR); + result->kindOfValue = FAIL; + } else { + result->addressMode = operand->kindOfOperand; + } + break; + + case STRING_OPND: + result = newValue(STRING_VALUE, operand->theOperand, + STRING_OPND); + break; + + case BLOCK_OPND: + if (standaloneExpansionFlag) + forceExpansion(); + sideEffectFlag = TRUE; + assembleBlock(operand->theOperand); + expansionOn(); + result = newValue(FAIL, 0, BLOCK_OPND); + break; + + default: + botch("bad operand kind in evaluateOperand %d\n", + operand->kindOfOperand); + break; + } + return(result); +} + +/* from parserMisc.c */ + + conditionType +invertConditionCode(conditionCode) + conditionType conditionCode; +{ +#define cc (int)conditionCode + + if ((int)CARRY_COND<=cc && cc<=(int)ALWAYS_COND) + return((conditionType) + (cc - (int)CARRY_COND + (int)NOT_CARRY_COND)); + else if ((int)NOT_CARRY_COND<=cc && cc<=(int)NEVER_COND) + return((conditionType) + (cc + (int)CARRY_COND - (int)NOT_CARRY_COND)); + else + botch("invertConditionCode given %d, not a condition code\n"); +} + +/* from semanticMisc.c */ + + bool +shouldParenthesize(operand) + operandType *operand; +{ + expressionTermKindType kind; + + switch(operand->kindOfOperand) { + case EXPRESSION_OPND: + case IMMEDIATE_OPND: + case INDIRECT_OPND: + case POST_INDEXED_Y_OPND: + case PRE_INDEXED_X_OPND: + case X_INDEXED_OPND: + case Y_INDEXED_OPND: + kind = operand->theOperand.expressionUnion->kindOfTerm; + return (kind==UNOP_EXPR || kind==BINOP_EXPR || kind== + ASSIGN_EXPR); + break; + + case X_SELECTED_OPND: + case Y_SELECTED_OPND: + case PRE_SELECTED_X_OPND: + return(TRUE); + break; + + case A_REGISTER_OPND: + case X_REGISTER_OPND: + case Y_REGISTER_OPND: + case STRING_OPND: + case BLOCK_OPND: + return(FALSE); + break; + } +} diff --git a/operandStuffSD_68000.c b/operandStuffSD_68000.c new file mode 100644 index 0000000..f6d1a81 --- /dev/null +++ b/operandStuffSD_68000.c @@ -0,0 +1,559 @@ +/* + operandStuff_68000.c -- Various target processor routines to handle + operands in the Macross assembler (68000 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 26-April-1985 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* corresponds to routines in buildStuff2.c */ + + operandType * +buildOperand(kindOfOperand, arg1, arg2, arg3, arg4) + operandKindType kindOfOperand; + int arg1; + int arg2; + int arg3; + int arg4; +{ + operandType *result; + + result = typeAlloc(operandType); + result->kindOfOperand = kindOfOperand; + result->nextOperand = NULL; + switch (kindOfOperand) { + + case EXPRESSION_OPND: + result->theOperand.expressionUnion = + (expressionOperandBodyType *) arg1; + break; + + case STRING_OPND: + result->theOperand.stringUnion = + (stringOperandBodyType *) arg1; + break; + + case BLOCK_OPND: + result->theOperand.blockUnion = (BlockOperandBodyType *) arg1; + break; + + case D_REGISTER_OPND: + result->theOperand.dRegisterUnion = + (dRegisterOperandBodyType *) NULL; + setRegister(result->kindOfOperand, arg1); + break; + + case A_REGISTER_OPND: + result->theOperand.aRegisterUnion = + (aRegisterOperandBodyType *) NULL; + setRegister(result->kindOfOperand, arg1); + break; + + case A_REGISTER_INDIRECT_OPND: + result->theOperand.aRegisterIndirectUnion = + (aRegisterIndirectOperandBodyType *) NULL; + setRegister(result->kindOfOperand, arg1); + break; + + case POSTINCREMENT_OPND: + result->theOperand.postincrementUnion = + (postincrementOperandBodyType *) NULL; + setRegister(result->kindOfOperand, arg1); + break; + + case PREDECREMENT_OPND: + result->theOperand.predecrementUnion = + (predecrementOperandBodyType *) NULL; + setRegister(result->kindOfOperand, arg1); + break; + + case DISPLACEMENT_OPND: + result->theOperand.displacementUnion = + (displacementOperandBodyType *) arg2; + setRegister(result->kindOfOperand, arg1); + break; + + case SELECTED_OPND: + result->theOperand.selectionUnion = + (selectedOperandBodyType *) arg2; + setRegister(result->kindOfOperand, arg1); + break; + + case INDEXED_OPND: + result->theOperand.indexedUnion = + (indexedOperandBodyType *) arg1; + setRegister(result->kindOfOperand, arg2); + setIndexRegister(result->kindOfOperand, arg3); + setWL(result->kindOfOperand, (int)arg4); + break; + + case INDEX_SELECTED_OPND: + result->theOperand.indexSelectedUnion = + (indexSelectedOperandBodyType *) arg1; + setRegister(result->kindOfOperand, arg2); + setIndexRegister(result->kindOfOperand, arg3); + setWL(result->kindOfOperand, (int)arg4); + break; + + case PC_DISPLACEMENT_OPND: + result->theOperand.pcDisplacementUnion = + (pcDisplacementOperandBodyType *) arg1; + break; + + case PC_INDEXED_OPND: + result->theOperand.pcIndexedUnion = + (pcIndexedOperandBodyType *) arg1; + setIndexRegister(result->kindOfOperand, arg2); + setWL(result->kindOfOperand, (int)arg3); + break; + + case IMMEDIATE_OPND: + result->theOperand.immediateUnion = + (immediateOperandBodyType *) arg1; + break; + + case ABSOLUTE_SHORT_OPND: + result->theOperand.absoluteShortUnion = + (absoluteShortOperandBodyType *) arg1; + break; + + case ABSOLUTE_LONG_OPND: + result->theOperand.absoluteLongUnion = + (absoluteLongOperandBodyType *) arg1; + break; + + case CC_REGISTER_OPND: + result->theOperand.ccRegisterUnion = + (ccRegisterOperandBodyType *) NULL; + break; + + case STATUS_REGISTER_OPND: + result->theOperand.statusRegisterUnion = + (statusRegisterOperandBodyType *) NULL; + break; + + case USP_REGISTER_OPND: + result->theOperand.uspRegisterUnion = + (uspRegisterOperandBodyType *) NULL; + break; + + case CONTROL_REGISTER_OPND: + result->theOperand.controlRegisterUnion = + (controlRegisterOperandBodyType *) NULL; + setRegister(result->kindOfOperand, arg1); + break; + + default: + botch("unknown operand kind: %d\n", kindOfOperand); + break; + } + return(result); +} + +/* corresponds to routines in fixups.c */ + + operandListType * +duplicateOperandForFixup(operand, isSpecialFunctionOperand) + operandListType *operand; + bool isSpecialFunctionOperand; +{ + operandListType *result; + + expressionType *duplicateExpressionForFixup(); + + result = typeAlloc(operandListType); + result->kindOfOperand = operand->kindOfOperand; + result->nextOperand = NULL; + if (operand->kindOfOperand != EXPRESSION_OPND) + newFixupAddressMode = operand->kindOfOperand; + switch (operandKindField(operand->kindOfOperand)) { + + case EXPRESSION_OPND: + case DISPLACEMENT_OPND: + case SELECTED_OPND: + case INDEXED_OPND: + case INDEX_SELECTED_OPND: + case PC_DISPLACEMENT_OPND: + case PC_INDEXED_OPND: + case IMMEDIATE_OPND: + case ABSOLUTE_SHORT_OPND: + case ABSOLUTE_LONG_OPND: + result->theOperand.expressionUnion = + duplicateExpressionForFixup(operand->theOperand, + FALSE, isSpecialFunctionOperand); + break; + case D_REGISTER_OPND: + case A_REGISTER_OPND: + case A_REGISTER_INDIRECT_OPND: + case POSTINCREMENT_OPND: + case PREDECREMENT_OPND: + case CC_REGISTER_OPND: + case STATUS_REGISTER_OPND: + case USP_REGISTER_OPND: + case CONTROL_REGISTER_OPND: + result->theOperand = operand->theOperand; + break; + case STRING_OPND: + result->theOperand = operand->theOperand; + break; + case BLOCK_OPND: + error(CANT_FORWARD_REFERENCE_BLOCK_ERROR); + result = NULL; + break; + } + return(result); +} + +/* corresponds to routines in garbage.c */ + +#define nullFree(thing) if (thing == NULL) return; + + void +freeOperand(operand) + operandType *operand; +{ + nullFree(operand); + switch (operandKindField(operand->kindOfOperand)) { + + case EXPRESSION_OPND: + case DISPLACEMENT_OPND: + case INDEXED_OPND: + case PC_DISPLACEMENT_OPND: + case PC_INDEXED_OPND: + case IMMEDIATE_OPND: + case ABSOLUTE_SHORT_OPND: + case ABSOLUTE_LONG_OPND: + freeExpression(operand->theOperand); + break; + + case D_REGISTER_OPND: + case A_REGISTER_OPND: + case A_REGISTER_INDIRECT_OPND: + case POSTINCREMENT_OPND: + case PREDECREMENT_OPND: + case CC_REGISTER_OPND: + case STATUS_REGISTER_OPND: + case USP_REGISTER_OPND: + case CONTROL_REGISTER_OPND: + break; + + case SELECTED_OPND: + case INDEX_SELECTED_OPND: + freeSelectionList(operand->theOperand); + break; + + case STRING_OPND: + freeString(operand->theOperand); + break; + + case BLOCK_OPND: + freeBlock(operand->theOperand); + break; + + default: + botch("bad operand kind in freeOperand %d\n", + operand->kindOfOperand); + break; + } + freeOperand(operand->nextOperand); + free(operand); +} + +/* corresponds to routines in listing.c */ + + void +expandOperand(addressMode, buffer) + operandKindType addressMode; + char *buffer; +{ + char *bufferPtr; + + bufferPtr = buffer; + switch (operandKindField(addressMode)) { + case D_REGISTER_OPND: + moreTextOptional(buffer, &bufferPtr, "d"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + break; + case A_REGISTER_OPND: + moreTextOptional(buffer, &bufferPtr, "a"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + break; + case A_REGISTER_INDIRECT_OPND: + moreTextOptional(buffer, &bufferPtr, "[a"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + moreTextOptional(buffer, &bufferPtr, "]"); + break; + case POSTINCREMENT_OPND: + moreTextOptional(buffer, &bufferPtr, "[a"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + moreTextOptional(buffer, &bufferPtr, "]+"); + break; + case PREDECREMENT_OPND: + moreTextOptional(buffer, &bufferPtr, "-[a"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + moreTextOptional(buffer, &bufferPtr, "]"); + break; + case IMMEDIATE_OPND: + moreTextOptional(buffer, &bufferPtr, "#"); + break; + case CC_REGISTER_OPND: + moreTextOptional(buffer, &bufferPtr, "ccr"); + break; + case STATUS_REGISTER_OPND: + moreTextOptional(buffer, &bufferPtr, "sr"); + break; + case USP_REGISTER_OPND: + moreTextOptional(buffer, &bufferPtr, "usp"); + break; + case CONTROL_REGISTER_OPND: + if (getRegister(addressMode) == 1) + moreTextOptional(buffer, &bufferPtr, "sfc"); + else if (getRegister(addressMode) == 2) + moreTextOptional(buffer, &bufferPtr, "dfc"); + else + moreTextOptional(buffer, &bufferPtr, "vbr"); + break; + case SELECTED_OPND: + moreTextOptional(buffer, &bufferPtr, "a"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + break; + case INDEX_SELECTED_OPND: + moreTextOptional(buffer, &bufferPtr, "a"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + if (getIndexRegister(addressMode)<8) { + moreTextOptional(buffer, &bufferPtr, "[a"); + expandNum(buffer, &bufferPtr, + getIndexRegister(addressMode)); + } else { + moreTextOptional(buffer, &bufferPtr, "[d"); + expandNum(buffer, &bufferPtr, + getIndexRegister(addressMode)-8); + } + moreTextOptional(buffer, &bufferPtr, "]"); + break; + + default: + break; + } + expandExpression(buffer, &bufferPtr); + switch(operandKindField(addressMode)) { + case DISPLACEMENT_OPND: + moreTextOptional(buffer, &bufferPtr, "[a"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + moreTextOptional(buffer, &bufferPtr, "]"); + break; + case INDEXED_OPND: + moreTextOptional(buffer, &bufferPtr, "[a"); + expandNum(buffer, &bufferPtr, getRegister(addressMode)); + moreTextOptional(buffer, &bufferPtr, ","); + if (getIndexRegister(addressMode)<8) { + moreTextOptional(buffer, &bufferPtr, "a"); + expandNum(buffer, &bufferPtr, + getIndexRegister(addressMode)); + } else { + moreTextOptional(buffer, &bufferPtr, "d"); + expandNum(buffer, &bufferPtr, + getIndexRegister(addressMode)-8); + } + moreTextOptional(buffer, &bufferPtr, "."); + if (getWL(addressMode)) + moreTextOptional(buffer, &bufferPtr, "l]"); + else + moreTextOptional(buffer, &bufferPtr, "w]"); + break; + case PC_DISPLACEMENT_OPND: + moreTextOptional(buffer, &bufferPtr, "[pc]"); + break; + case PC_INDEXED_OPND: + moreTextOptional(buffer, &bufferPtr, "[pc,"); + if (getIndexRegister(addressMode)<8) { + moreTextOptional(buffer, &bufferPtr, "a"); + expandNum(buffer, &bufferPtr, + getIndexRegister(addressMode)); + } else { + moreTextOptional(buffer, &bufferPtr, "d"); + expandNum(buffer, &bufferPtr, + getIndexRegister(addressMode)-8); + } + moreTextOptional(buffer, &bufferPtr, "."); + if (getWL(addressMode)) + moreTextOptional(buffer, &bufferPtr, "l]"); + else + moreTextOptional(buffer, &bufferPtr, "w]"); + break; + case ABSOLUTE_SHORT_OPND: + moreTextOptional(buffer, &bufferPtr, ".w"); + break; + case ABSOLUTE_LONG_OPND: + moreTextOptional(buffer, &bufferPtr, ".l"); + break; + default: + break; + } +} + +/* corresponds to routines in expressionSemantics.c */ + +#define nullEvaluate(thing) if (thing==NULL) return(NULL); +#define fail(err) if (!expressionFailed) {\ + error(err);\ + expressionFailed = TRUE;\ + } +#define fail1(err,arg) if (!expressionFailed) {\ + error(err,arg);\ + expressionFailed = TRUE;\ + } +#define fail2(err,arg1,arg2) if (!expressionFailed) {\ + error(err,arg1,arg2);\ + expressionFailed = TRUE;\ + } + +#define qfree2(a,b) if (freeFlag) { free(a); free(b); } + +#define expansionOff() {saveExpansion=expandMacros; expandMacros=FALSE;} +#define forceExpansion() {saveExpansion=expandMacros; expandMacros=TRUE;} +#define expansionOn() expandMacros=saveExpansion; + + valueType * +evaluateOperand(operand) + operandType *operand; +{ + valueType *result; + bool saveExpansion; + expressionType *expression; + + valueType *evaluateExpression(); + valueType *evaluateSelectionList(); + valueType *newValue(); + + nullEvaluate(operand); + if (operand->kindOfOperand != EXPRESSION_OPND) + newFixupAddressMode = operand->kindOfOperand; + switch (operandKindField(operand->kindOfOperand)) { + + case EXPRESSION_OPND: + case DISPLACEMENT_OPND: + case INDEXED_OPND: + case PC_DISPLACEMENT_OPND: + case PC_INDEXED_OPND: + case IMMEDIATE_OPND: + case ABSOLUTE_SHORT_OPND: + case ABSOLUTE_LONG_OPND: + result = evaluateExpression(operand->theOperand, + performingFixups ? NO_FIXUP : OPERAND_FIXUP); + if (operand->kindOfOperand != EXPRESSION_OPND) { + if (result->addressMode != EXPRESSION_OPND) { + error(BAD_ADDRESS_MODE_ERROR); + result->kindOfValue = FAIL; + } else { + result->addressMode = operand->kindOfOperand; + } + } + break; + + case SELECTED_OPND: + case INDEX_SELECTED_OPND: + result = evaluateSelectionList(operand->theOperand); + if (result->addressMode != EXPRESSION_OPND) { + error(BAD_ADDRESS_MODE_ERROR); + result->kindOfValue = FAIL; + } else { + result->addressMode = operand->kindOfOperand; + } + break; + + case D_REGISTER_OPND: + case A_REGISTER_OPND: + case A_REGISTER_INDIRECT_OPND: + case POSTINCREMENT_OPND: + case PREDECREMENT_OPND: + case CC_REGISTER_OPND: + case STATUS_REGISTER_OPND: + case USP_REGISTER_OPND: + case CONTROL_REGISTER_OPND: + result = newValue(ABSOLUTE_VALUE, 0, operand-> + kindOfOperand); + break; + + case STRING_OPND: + result = newValue(STRING_VALUE, operand->theOperand, + STRING_OPND); + break; + + case BLOCK_OPND: + if (standaloneExpansionFlag) + forceExpansion(); + assembleBlock(operand->theOperand); + expansionOn(); + result = newValue(FAIL, 0, BLOCK_OPND); + break; + + default: + botch("bad operand kind in evaluateOperand %d\n", + operand->kindOfOperand); + break; + } + return(result); +} + +/* from parserMisc.c */ + + conditionType +invertConditionCode(conditionCode) + conditionType conditionCode; +{ +#define cc (int)conditionCode + + if ((int)CARRY_COND<=cc && cc<=(int)ALWAYS_COND) + return((conditionType) + (cc - (int)CARRY_COND + (int)NOT_CARRY_COND)); + else if ((int)NOT_CARRY_COND<=cc && cc<=(int)NEVER_COND) + return((conditionType) + (cc + (int)CARRY_COND - (int)NOT_CARRY_COND)); + else + botch("invertConditionCode given %d, not a condition code\n"); +} + +/* from semanticMisc.c */ + + bool +shouldParenthesize(operand) + operandType *operand; +{ + expressionTermKindType kind; + + switch(operandKindField(operand->kindOfOperand)) { + case EXPRESSION_OPND: + case DISPLACEMENT_OPND: + case INDEXED_OPND: + case PC_DISPLACEMENT_OPND: + case PC_INDEXED_OPND: + case IMMEDIATE_OPND: + case ABSOLUTE_SHORT_OPND: + case ABSOLUTE_LONG_OPND: + kind = operand->theOperand.expressionUnion->kindOfTerm; + return (kind==UNOP_EXPR || kind==BINOP_EXPR || kind== + ASSIGN_EXPR); + break; + + case STRING_OPND: + case BLOCK_OPND: + case D_REGISTER_OPND: + case A_REGISTER_OPND: + case A_REGISTER_INDIRECT_OPND: + case POSTINCREMENT_OPND: + case PREDECREMENT_OPND: + case CC_REGISTER_OPND: + case STATUS_REGISTER_OPND: + case USP_REGISTER_OPND: + case CONTROL_REGISTER_OPND: + case SELECTED_OPND: + case INDEX_SELECTED_OPND: + return(FALSE); + break; + } +} diff --git a/opt/.mark b/opt/.mark new file mode 100644 index 0000000..56fe325 --- /dev/null +++ b/opt/.mark @@ -0,0 +1 @@ +Mon Feb 2 23:18:37 PST 1987 diff --git a/opt/Makefile b/opt/Makefile new file mode 100644 index 0000000..9784005 --- /dev/null +++ b/opt/Makefile @@ -0,0 +1,165 @@ +.SUFFIXES: .o .c .h .run + +# to make for another target CPU, redefine PROC to the name of the target +# processor, e.g., 68000 +PROC =6502 + +OBJECTS = y.tab.o actions.o buildStuff1.o buildStuff2.o\ +buildStuff3.o builtInFunctions.o builtInFunsSD.o debugPrint.o debugPrintSD.o\ +emitBranch.o emitStuff.o encode.o errorStuff.o expressionSemantics.o fixups.o\ +garbage.o initialize.o lexer.o listing.o lookups.o macrossTables.o main.o\ +malloc.o object.o operandStuffSD.o parserMisc.o semanticMisc.o\ +statementSemantics.o structSemantics.o tokenStrings.o + +SOURCES = macross_$(PROC).y actions_$(PROC).c buildStuff1.c buildStuff2.c\ +buildStuff3.c builtInFunctions.c builtInFunsSD_$(PROC).c debugPrint.c\ +debugPrintSD_$(PROC).c emitBranch_$(PROC).c emitStuff.c encode.c errorStuff.c\ +expressionSemantics.c fixups.c garbage.c initialize.c lexer.c listing.c\ +lookups.c macrossTables_$(PROC).c main.c malloc.c object.c\ +operandStuffSD_$(PROC).c parserMisc.c semanticMisc.c statementSemantics.c\ +structSemantics.c tokenStrings_$(PROC).c lexerTables.h macrossGlobals.h\ +macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h driver.c + +HEADERS = macrossTypes.h macrossGlobals.h + +.c.o: + cc -c -O -DTARGET_CPU=CPU_$(PROC) $*.c + +.c.run: + cc -o $* $*.c + +macross: $(OBJECTS) + cc -O -o macross $(OBJECTS) + +driver: driver.c + cc -o driver driver.c + +update: .mark + kessel "(cd /u0/chip/macross; make macross >&errorfyle)" & + +install: macross + cp macross macross_tmp + strip macross_tmp + cp /u1/gg/bin/macross_$(PROC) /u1/gg/bin/macross_$(PROC).old + cp macross_tmp /u1/gg/bin/macross_$(PROC) + rm macross_tmp + cp /u1/gg/bin/macross_$(PROC) /net/mycroft/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/shem/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/weyr/u1/gg/bin + +dinstall: driver + cp driver /u1/gg/bin/driver_tmp + strip /u1/gg/bin/driver_tmp + mv /u1/gg/bin/driver_tmp /u1/gg/bin/driver/macross + cp /u1/gg/bin/driver /net/mycroft/u1/gg/bin/macross + cp /u1/gg/bin/driver /net/shem/u1/gg/bin/macross + cp /u1/gg/bin/driver /net/weyr/u1/gg/bin/macross + +change: + rm *.o + rm *.tab.* + cp Makefile_68000 Makefile + +move: .mark + +.mark: $(SOURCES) + cp $? /net/kessel/u0/chip/macross + cp $? /net/kessel/u0/chip/macross/prof + cp $? .. + date >.mark + date >/net/kessel/u0/chip/macross/.mark + date >/net/kessel/u0/chip/macross/prof/.mark + date >../.mark + +macrossTypes.h: macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h + +actions.o: actions_$(PROC).c $(HEADERS) + cc -c -O -DTARGET_CPU=CPU_$(PROC) actions_$(PROC).c + mv actions_$(PROC).o actions.o + +buildStuff1.o: buildStuff1.c $(HEADERS) + +buildStuff2.o: buildStuff2.c $(HEADERS) + +buildStuff3.o: buildStuff3.c $(HEADERS) + +builtInFunctions.o: builtInFunctions.c $(HEADERS) + +builtInFunsSD.o: builtInFunsSD_$(PROC).c $(HEADERS) + cc -c -O -DTARGET_CPU=CPU_$(PROC) builtInFunsSD_$(PROC).c + mv builtInFunsSD_$(PROC).o builtInFunsSD.o + +debugPrint.o: debugPrint.c y.tab.h $(HEADERS) + +debugPrintSD.o: debugPrintSD_$(PROC).c y.tab.h $(HEADERS) + cc -c -O -DTARGET_CPU=CPU_$(PROC) debugPrintSD_$(PROC).c + mv debugPrintSD_$(PROC).o debugPrintSD.o + +emitBranch.o: emitBranch_$(PROC).c $(HEADERS) + cc -c -O -DTARGET_CPU=CPU_$(PROC) emitBranch_$(PROC).c + mv emitBranch_$(PROC).o emitBranch.o + +emitStuff.o: emitStuff.c $(HEADERS) + cc -c -O -DBYTESWAPPED -DTARGET_CPU=CPU_$(PROC) emitStuff.c + +encode.o: encode.c $(HEADERS) + +errorStuff.o: errorStuff.c $(HEADERS) + +expressionSemantics.o: expressionSemantics.c y.tab.h $(HEADERS) + +fixups.o: fixups.c $(HEADERS) + +garbage.o: garbage.c y.tab.h $(HEADERS) + +initialize.o: initialize.c $(HEADERS) + +lexer.o: lexer.c lexerTables.h y.tab.h $(HEADERS) + +listing.o: listing.c $(HEADERS) + +lookups.o: lookups.c $(HEADERS) + +macrossTables.o: macrossTables_$(PROC).c y.tab.h macrossTypes.h + cc -c -O -DTARGET_CPU=CPU_$(PROC) macrossTables_$(PROC).c + mv macrossTables_$(PROC).o macrossTables.o + +malloc.o: malloc.c + +main.o: main.c $(HEADERS) + +object.o: object.c $(HEADERS) + +operandStuffSD.o: operandStuffSD_$(PROC).c $(HEADERS) + cc -c -O -DTARGET_CPU=CPU_$(PROC) operandStuffSD_$(PROC).c + mv operandStuffSD_$(PROC).o operandStuffSD.o + +parserMisc.o: parserMisc.c y.tab.h $(HEADERS) + +semanticMisc.o: semanticMisc.c $(HEADERS) + +statementSemantics.o: statementSemantics.c $(HEADERS) + +structSemantics.o: structSemantics.c $(HEADERS) + +tokenStrings.o: tokenStrings_$(PROC).c $(HEADERS) + cc -c -O -DTARGET_CPU=CPU_$(PROC) tokenStrings_$(PROC).c + mv tokenStrings_$(PROC).o tokenStrings.o + +y.tab.o: y.tab.c $(HEADERS) + cc -c -O -DYYDEBUG -DTARGET_CPU=CPU_$(PROC) y.tab.c + +y.tab.c y.tab.h: macross_$(PROC).y + yacc -d macross_$(PROC).y + +y.output: macross_$(PROC).y + yacc -vd macross_$(PROC).y + +cleanup: + /bin/rm -f *.o y.output y.tab.c y.tab.h macross + +love: + @echo "Not war?" + diff --git a/opt/Makefile_6502 b/opt/Makefile_6502 new file mode 100644 index 0000000..abe4bee --- /dev/null +++ b/opt/Makefile_6502 @@ -0,0 +1,162 @@ +.SUFFIXES: .o .c .h .run + +# to make for another target CPU, redefine PROC to the name of the target +# processor, e.g., 68000 +PROC =6502 + +OBJECTS = y.tab.o actions.o buildStuff1.o buildStuff2.o\ +buildStuff3.o builtInFunctions.o builtInFunsSD.o debugPrint.o debugPrintSD.o\ +emitBranch.o emitStuff.o errorStuff.o expressionSemantics.o fixups.o\ +garbage.o initialize.o lexer.o listing.o lookups.o macrossTables.o main.o\ +malloc.o object.o operandStuffSD.o parserMisc.o semanticMisc.o\ +statementSemantics.o structSemantics.o tokenStrings.o + +SOURCES = macross_$(PROC).y actions_$(PROC).c buildStuff1.c buildStuff2.c\ +buildStuff3.c builtInFunctions.c builtInFunsSD_$(PROC).c debugPrint.c\ +debugPrintSD_$(PROC).c emitBranch_$(PROC).c emitStuff.c errorStuff.c\ +expressionSemantics.c fixups.c garbage.c initialize.c lexer.c listing.c\ +lookups.c macrossTables_$(PROC).c main.c malloc.c object.c\ +operandStuffSD_$(PROC).c parserMisc.c semanticMisc.c statementSemantics.c\ +structSemantics.c tokenStrings_$(PROC).c lexerTables.h macrossGlobals.h\ +macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h driver.c + +HEADERS = macrossTypes.h macrossGlobals.h + +.c.o: + cc -O -c -DTARGET_CPU=CPU_$(PROC) $*.c + +.c.run: + cc -O -o $* $*.c + +macross: $(OBJECTS) + cc -O -o macross $(OBJECTS) + +driver: driver.c + cc -O -o driver driver.c + +update: .mark + kessel "(cd /u0/chip/macross; make macross >&errorfyle)" & + +install: macross + cp macross /u1/gg/bin/macross_tmp + strip /u1/gg/bin/macross_tmp + mv /u1/gg/bin/macross_$(PROC) /u1/gg/bin/macross_$(PROC).old + mv /u1/gg/bin/macross_tmp /u1/gg/bin/macross_$(PROC) + cp /u1/gg/bin/macross_$(PROC) /net/mycroft/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/shem/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/weyr/u1/gg/bin + +dinstall: driver + cp driver /u1/gg/bin/driver_tmp + strip /u1/gg/bin/driver_tmp + mv /u1/gg/bin/driver_tmp /u1/gg/bin/macross + cp /u1/gg/bin/macross /net/mycroft/u1/gg/bin/macross + cp /u1/gg/bin/macross /net/shem/u1/gg/bin/macross + cp /u1/gg/bin/macross /net/weyr/u1/gg/bin/macross + +change: + rm *.o + rm *.tab.* + cp Makefile_68000 Makefile + +move: .mark + +.mark: $(SOURCES) + cp $? /net/kessel/u0/chip/macross + cp $? /net/kessel/u0/chip/macross/prof + cp $? .. + date >.mark + date >/net/kessel/u0/chip/macross/.mark + date >/net/kessel/u0/chip/macross/prof/.mark + date >../.mark + +macrossTypes.h: macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h + +actions.o: actions_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) actions_$(PROC).c + mv actions_$(PROC).o actions.o + +buildStuff1.o: buildStuff1.c $(HEADERS) + +buildStuff2.o: buildStuff2.c $(HEADERS) + +buildStuff3.o: buildStuff3.c $(HEADERS) + +builtInFunctions.o: builtInFunctions.c $(HEADERS) + +builtInFunsSD.o: builtInFunsSD_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) builtInFunsSD_$(PROC).c + mv builtInFunsSD_$(PROC).o builtInFunsSD.o + +debugPrint.o: debugPrint.c y.tab.h $(HEADERS) + +debugPrintSD.o: debugPrintSD_$(PROC).c y.tab.h $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) debugPrintSD_$(PROC).c + mv debugPrintSD_$(PROC).o debugPrintSD.o + +emitBranch.o: emitBranch_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) emitBranch_$(PROC).c + mv emitBranch_$(PROC).o emitBranch.o + +emitStuff.o: emitStuff.c $(HEADERS) + cc -O -c -DBYTESWAPPED -DTARGET_CPU=CPU_$(PROC) emitStuff.c + +errorStuff.o: errorStuff.c $(HEADERS) + +expressionSemantics.o: expressionSemantics.c y.tab.h $(HEADERS) + +fixups.o: fixups.c $(HEADERS) + +garbage.o: garbage.c y.tab.h $(HEADERS) + +initialize.o: initialize.c $(HEADERS) + +lexer.o: lexer.c lexerTables.h y.tab.h $(HEADERS) + +listing.o: listing.c $(HEADERS) + +lookups.o: lookups.c $(HEADERS) + +macrossTables.o: macrossTables_$(PROC).c y.tab.h macrossTypes.h + cc -O -c -DTARGET_CPU=CPU_$(PROC) macrossTables_$(PROC).c + mv macrossTables_$(PROC).o macrossTables.o + +malloc.o: malloc.c + +main.o: main.c $(HEADERS) + +object.o: object.c $(HEADERS) + +operandStuffSD.o: operandStuffSD_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) operandStuffSD_$(PROC).c + mv operandStuffSD_$(PROC).o operandStuffSD.o + +parserMisc.o: parserMisc.c y.tab.h $(HEADERS) + +semanticMisc.o: semanticMisc.c $(HEADERS) + +statementSemantics.o: statementSemantics.c $(HEADERS) + +structSemantics.o: structSemantics.c $(HEADERS) + +tokenStrings.o: tokenStrings_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) tokenStrings_$(PROC).c + mv tokenStrings_$(PROC).o tokenStrings.o + +y.tab.o: y.tab.c $(HEADERS) + cc -O -c -DYYDEBUG -DTARGET_CPU=CPU_$(PROC) y.tab.c + +y.tab.c y.tab.h: macross_$(PROC).y + yacc -d macross_$(PROC).y + +y.output: macross_$(PROC).y + yacc -vd macross_$(PROC).y + +cleanup: + /bin/rm -f *.o y.output y.tab.c y.tab.h macross + +love: + @echo "Not war?" + diff --git a/opt/Makefile_68000 b/opt/Makefile_68000 new file mode 100644 index 0000000..5015fb6 --- /dev/null +++ b/opt/Makefile_68000 @@ -0,0 +1,162 @@ +.SUFFIXES: .o .c .h .run + +# to make for another target CPU, redefine PROC to the name of the target +# processor, e.g., 68000 +PROC =68000 + +OBJECTS = y.tab.o actions.o buildStuff1.o buildStuff2.o\ +buildStuff3.o builtInFunctions.o builtInFunsSD.o debugPrint.o debugPrintSD.o\ +emitBranch.o emitStuff.o errorStuff.o expressionSemantics.o fixups.o\ +garbage.o initialize.o lexer.o listing.o lookups.o macrossTables.o main.o\ +malloc.o object.o operandStuffSD.o parserMisc.o semanticMisc.o\ +statementSemantics.o structSemantics.o tokenStrings.o + +SOURCES = macross_$(PROC).y actions_$(PROC).c buildStuff1.c buildStuff2.c\ +buildStuff3.c builtInFunctions.c builtInFunsSD_$(PROC).c debugPrint.c\ +debugPrintSD_$(PROC).c emitBranch_$(PROC).c emitStuff.c errorStuff.c\ +expressionSemantics.c fixups.c garbage.c initialize.c lexer.c listing.c\ +lookups.c macrossTables_$(PROC).c main.c malloc.c object.c\ +operandStuffSD_$(PROC).c parserMisc.c semanticMisc.c statementSemantics.c\ +structSemantics.c tokenStrings_$(PROC).c lexerTables.h macrossGlobals.h\ +macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h driver.c + +HEADERS = macrossTypes.h macrossGlobals.h + +.c.o: + cc -O -c -DTARGET_CPU=CPU_$(PROC) $*.c + +.c.run: + cc -O -o $* $*.c + +macross: $(OBJECTS) + cc -O -o macross $(OBJECTS) + +driver: driver.c + cc -O -o driver driver.c + +update: .mark + kessel "(cd /u0/chip/macross; make macross >&errorfyle)" & + +install: macross + cp macross /u1/gg/bin/macross_tmp + strip /u1/gg/bin/macross_tmp + mv /u1/gg/bin/macross_$(PROC) /u1/gg/bin/macross_$(PROC).old + mv /u1/gg/bin/macross_tmp /u1/gg/bin/macross_$(PROC) + cp /u1/gg/bin/macross_$(PROC) /net/mycroft/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/shem/u1/gg/bin + cp /u1/gg/bin/macross_$(PROC) /net/weyr/u1/gg/bin + +dinstall: driver + cp driver /u1/gg/bin/driver_tmp + strip /u1/gg/bin/driver_tmp + mv /u1/gg/bin/driver_tmp /u1/gg/bin/macross + cp /u1/gg/bin/macross /net/mycroft/u1/gg/bin/macross + cp /u1/gg/bin/macross /net/shem/u1/gg/bin/macross + cp /u1/gg/bin/macross /net/weyr/u1/gg/bin/macross + +change: + rm *.o + rm *.tab.* + cp Makefile_6502 Makefile + +move: .mark + +.mark: $(SOURCES) + cp $? /net/kessel/u0/chip/macross + cp $? /net/kessel/u0/chip/macross/prof + cp $? .. + date >.mark + date >/net/kessel/u0/chip/macross/.mark + date >/net/kessel/u0/chip/macross/prof/.mark + date >../.mark + +macrossTypes.h: macrossTypes.h operandDefs_$(PROC).h operandBody_$(PROC).h\ +conditionDefs_$(PROC).h + +actions.o: actions_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) actions_$(PROC).c + mv actions_$(PROC).o actions.o + +buildStuff1.o: buildStuff1.c $(HEADERS) + +buildStuff2.o: buildStuff2.c $(HEADERS) + +buildStuff3.o: buildStuff3.c $(HEADERS) + +builtInFunctions.o: builtInFunctions.c $(HEADERS) + +builtInFunsSD.o: builtInFunsSD_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) builtInFunsSD_$(PROC).c + mv builtInFunsSD_$(PROC).o builtInFunsSD.o + +debugPrint.o: debugPrint.c y.tab.h $(HEADERS) + +debugPrintSD.o: debugPrintSD_$(PROC).c y.tab.h $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) debugPrintSD_$(PROC).c + mv debugPrintSD_$(PROC).o debugPrintSD.o + +emitBranch.o: emitBranch_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) emitBranch_$(PROC).c + mv emitBranch_$(PROC).o emitBranch.o + +emitStuff.o: emitStuff.c $(HEADERS) + cc -O -c -DBYTESWAPPED -DTARGET_CPU=CPU_$(PROC) emitStuff.c + +errorStuff.o: errorStuff.c $(HEADERS) + +expressionSemantics.o: expressionSemantics.c y.tab.h $(HEADERS) + +fixups.o: fixups.c $(HEADERS) + +garbage.o: garbage.c y.tab.h $(HEADERS) + +initialize.o: initialize.c $(HEADERS) + +lexer.o: lexer.c lexerTables.h y.tab.h $(HEADERS) + +listing.o: listing.c $(HEADERS) + +lookups.o: lookups.c $(HEADERS) + +macrossTables.o: macrossTables_$(PROC).c y.tab.h macrossTypes.h + cc -O -c -DTARGET_CPU=CPU_$(PROC) macrossTables_$(PROC).c + mv macrossTables_$(PROC).o macrossTables.o + +malloc.o: malloc.c + +main.o: main.c $(HEADERS) + +object.o: object.c $(HEADERS) + +operandStuffSD.o: operandStuffSD_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) operandStuffSD_$(PROC).c + mv operandStuffSD_$(PROC).o operandStuffSD.o + +parserMisc.o: parserMisc.c y.tab.h $(HEADERS) + +semanticMisc.o: semanticMisc.c $(HEADERS) + +statementSemantics.o: statementSemantics.c $(HEADERS) + +structSemantics.o: structSemantics.c $(HEADERS) + +tokenStrings.o: tokenStrings_$(PROC).c $(HEADERS) + cc -O -c -DTARGET_CPU=CPU_$(PROC) tokenStrings_$(PROC).c + mv tokenStrings_$(PROC).o tokenStrings.o + +y.tab.o: y.tab.c $(HEADERS) + cc -O -c -DYYDEBUG -DTARGET_CPU=CPU_$(PROC) y.tab.c + +y.tab.c y.tab.h: macross_$(PROC).y + yacc -d macross_$(PROC).y + +y.output: macross_$(PROC).y + yacc -vd macross_$(PROC).y + +cleanup: + /bin/rm -f *.o y.output y.tab.c y.tab.h macross + +love: + @echo "Not war?" + diff --git a/parserMisc.c b/parserMisc.c new file mode 100644 index 0000000..0617fcb --- /dev/null +++ b/parserMisc.c @@ -0,0 +1,128 @@ +/* + parserMisc.c -- Miscellaneous parser support routines for the Macross + assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 3-November-1984 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" + + statementType * +addLabelToStatement(labelList, statement) + labelListType *labelList; + statementType *statement; +{ + statementType *newStatement(); + + if (statement == NULL) + statement = newStatement(NULL_STATEMENT, NULL); + statement->labels = labelList; + return(statement); +} + + void +botch(message, arg1, arg2, arg3) + char *message; + anyOldThing *arg1; + anyOldThing *arg2; + anyOldThing *arg3; +{ + printf("Macross horrible terrible internal botch: "); + printf(message, arg1, arg2, arg3); + chokePukeAndDie(); +} + + void +checkDefineAssignmentOperator(assignmentOperator) + assignmentKindType assignmentOperator; +{ + if (assignmentOperator != ASSIGN_ASSIGN) + puntOnError(DEFINE_ASSIGNMENT_WRONG_ERROR); +} + + statementType * +convertDefineToMdefine(defineStatement) + statementType *defineStatement; +{ + if (defineStatement->kindOfStatement != DEFINE_STATEMENT) + botch("convertDefineToMdefine got statement kind: %d\n", + defineStatement->kindOfStatement); + defineStatement->kindOfStatement = MDEFINE_STATEMENT; + return(defineStatement); +} + + ifStatementBodyType * +extractIfBody(ifStatement) + statementType *ifStatement; +{ + ifStatementBodyType *result; + + result = ifStatement->statementBody.ifUnion; + if (ifStatement->labels != NULL) + botch("extract if body with non-null labels\n"); + else if (ifStatement->nextStatement != NULL) + botch("extract if body with non-null next\n"); + else + qfree(ifStatement); + return(result); +} + + mifStatementBodyType * +extractMifBody(mifStatement) + statementType *mifStatement; +{ + mifStatementBodyType *result; + + result = mifStatement->statementBody.mifUnion; + if (mifStatement->labels != NULL) + botch("extract mif body with non-null labels\n"); + else if (mifStatement->nextStatement != NULL) + botch("extract mif body with non-null next\n"); + else + qfree(mifStatement); + return(result); +} + + stringType * +extractString(textExpression) + operandType *textExpression; +{ + stringType *result; + + if (textExpression->kindOfOperand != STRING_OPND) + botch("extract string got handed an opnd kind: %d\n", + textExpression->kindOfOperand); + result = textExpression->theOperand.stringUnion; + qfree(textExpression); + return(result); +} + + void +popMacroOrFunctionNestingDepth() +{ + if (--macroOrFunctionNestingDepth == 0) + unknownSymbolTag = UNKNOWN_SYMBOL; +} + + void +pushMacroOrFunctionNestingDepth() +{ + macroOrFunctionNestingDepth++; + unknownSymbolTag = NESTED_UNKNOWN_SYMBOL; +} + + char * +saveString(s) + char *s; +{ + char *result; + + result = (char *)malloc(strlen(s)+1); + strcpy(result, s); + return(result); +} diff --git a/parserMisc.o b/parserMisc.o new file mode 100644 index 0000000..b5261f2 Binary files /dev/null and b/parserMisc.o differ diff --git a/semanticMisc.c b/semanticMisc.c new file mode 100644 index 0000000..78ca693 --- /dev/null +++ b/semanticMisc.c @@ -0,0 +1,1337 @@ +/* + semanticMisc.c -- Miscellaneous helper routines for the semantic + portions of the Macross assembler. + + Chip Morningstar -- Lucasfilm Ltd. + + 12-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" +#include "y.tab.h" + +#define expansionOff() {saveExpansion=expandMacros; expandMacros=FALSE;} +#define expansionOn() expandMacros=saveExpansion; + +/* + These are miscellaneous routines called by the primary semantics routines. + */ + + bool +absoluteValue(address) + valueType *address; +{ + return(address->kindOfValue == ABSOLUTE_VALUE); +} + + void +addAttributeToSymbol(symbol, attribute) + symbolTableEntryType *symbol; + symbolAttributesType attribute; +{ + symbolInContextType *context; + + symbolInContextType *getBaseContext(); + + context = getBaseContext(symbol); + if (context != NULL) + context->attributes |= attribute; +} + + addressType +addressValue(value) + valueType *value; +{ + if (value->kindOfValue==STRING_VALUE || + value->kindOfValue==CONDITION_VALUE || + value->kindOfValue==FAIL) + error(VALUE_IS_NOT_AN_ADDRESS_ERROR); + else + return(value->value); +} + + valueKindType +addValueKind(leftOperand, rightOperand) + valueType *leftOperand; + valueType *rightOperand; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'valueKindType'. */ + static valueKindType addValueKindTable[NUM_OF_VALUE_KINDS] + [NUM_OF_VALUE_KINDS] = { +/* ABSOLUTE_VALUE , DATA_VALUE , RELOCATABLE_VALUE , + BSS_VALUE , STRUCT_VALUE , FIELD_VALUE , + MACRO_VALUE , OPERAND_VALUE , STRING_VALUE , + CONDITION_VALUE, UNDEFINED_VALUE, FUNCTION_VALUE , + BLOCK_VALUE , BUILT_IN_FUNCTI, ARRAY_VALUE , + FAIL ,*/ + +/*ABSOLUTE_VALUE */ ABSOLUTE_VALUE , DATA_VALUE , RELOCATABLE_VALUE , + BSS_VALUE , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , UNDEFINED_VALUE, FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*DATA_VALUE */ DATA_VALUE , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , UNDEFINED_VALUE, FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*RELOCATABLE_VAL*/ RELOCATABLE_VALUE, FAIL , UNDEFINED_VALUE, + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , UNDEFINED_VALUE, FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*BSS_VALUE */ BSS_VALUE , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , UNDEFINED_VALUE, FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*STRUCT_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*FIELD_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*MACRO_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*OPERAND_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*STRING_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , STRING_VALUE , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*CONDITION_VALUE*/ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*UNDEFINED_VALUE*/ UNDEFINED_VALUE, UNDEFINED_VALUE, UNDEFINED_VALUE, + UNDEFINED_VALUE, FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , UNDEFINED_VALUE, FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*FUNCTION_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*BLOCK_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*BUILT_IN_FUNCT-*/ FAIL , FAIL , FAIL , +/*-ION_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*ARRAY_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*FAIL */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + }; + + return(addValueKindTable[(int)leftOperand->kindOfValue] + [(int)rightOperand->kindOfValue]); +} + + bool +alreadyDefined(context) + symbolInContextType *context; +{ + return((context->attributes & DEFINED_VARIABLE_ATT) != 0); +} + + bool +booleanTest(expression) + expressionType *expression; +{ + bool result; + valueType *expressionResult; + bool saveExpansion; + valueType *evaluateExpression(); + + expansionOff(); + expressionResult = evaluateExpression(expression, NO_FIXUP); + expansionOn(); + if (expressionResult == NULL) { + return(FALSE); + } else if (expressionResult->kindOfValue != ABSOLUTE_VALUE) { + error(INVALID_BOOLEAN_VALUE_ERROR, + valueKindString(expressionResult->kindOfValue)); + result = FALSE; + } else { + result = (expressionResult->value != 0); + } + qfree(expressionResult); + return(result); +} + + int +countArguments(function) + functionDefinitionType *function; +{ + int result; + argumentDefinitionListType *arguments; + + arguments = function->arguments; + result = 0; + while (arguments != NULL) { + result++; + arguments = arguments->nextArgument; + } + return(result); +} + + int +countParameters(parameterList) + operandListType *parameterList; +{ + int result; + + result = 0; + while (parameterList != NULL) { + result++; + parameterList = parameterList->nextOperand; + } + return(result); +} + + arrayType * +allocArray(size, contentsPtr) + int size; + valueType ***contentsPtr; +{ + arrayType *result; + int i; + + result = typeAlloc(arrayType); + result->arraySize = size; + result->arrayContents = *contentsPtr = (valueType **) malloc(size * + sizeof(valueType *)); + for (i=0; ikindOfValue != ABSOLUTE_VALUE) { + return(newValue(FAIL, 0, EXPRESSION_OPND)); + } else { + arraySize = arraySizeValue->value; + } + } + result = allocArray(arraySize, &arrayContents); + if (initCount > arraySize) { + error(TOO_MANY_VARIABLE_INITIALIZERS_ERROR); + initCount = arraySize; + } + for (i=0; i + theExpression, NO_FIXUP); + initializers = initializers->nextExpression; + } + return(newValue(ARRAY_VALUE, result, EXPRESSION_OPND)); +} + + bool +decrementable(value) + valueType *value; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'valueKindType'. */ + static bool decrementableTable[NUM_OF_VALUE_KINDS] = { + /* ABSOLUTE_VALUE */ TRUE, + /* DATA_VALUE */ TRUE, + /* RELOCATABLE_VALUE */ TRUE, + /* BSS_VALUE */ TRUE, + /* STRUCT_VALUE */ FALSE, + /* FIELD_VALUE */ FALSE, + /* MACRO_VALUE */ FALSE, + /* OPERAND_VALUE */ FALSE, + /* STRING_VALUE */ FALSE, + /* CONDITION_VALUE */ FALSE, + /* UNDEFINED_VALUE */ TRUE, + /* FUNCTION_VALUE */ FALSE, + /* BLOCK_VALUE */ FALSE, + /* BUILT_IN_FUNCTION_VALUE */ FALSE, + /* ARRAY_VALUE */ FALSE, + /* FAIL */ FALSE, + }; + + if (value == NULL) + return(FALSE); + else + return(decrementableTable[(int)value->kindOfValue]); +} + + int +expressionListLength(expressionList) + expressionListType *expressionList; +{ + int result; + + result = 0; + while (expressionList != NULL) { + result++; + expressionList = expressionList->nextExpression; + } + return(result); +} + + int +fieldValue(symbol) + symbolTableEntryType *symbol; +{ + valueType *value; + valueType *evaluateIdentifier(); + + value = evaluateIdentifier(symbol, FALSE, NO_FIXUP); + if (value->kindOfValue != FIELD_VALUE) { + error(VALUE_IS_NOT_A_FIELD_ERROR, symbName(symbol)); + return(0); + } else { + return(value->value); + } +} + + bool +incrementable(value) + valueType *value; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'valueKindType'. */ + static bool incrementableTable[NUM_OF_VALUE_KINDS] = { + /* ABSOLUTE_VALUE */ TRUE, + /* DATA_VALUE */ TRUE, + /* RELOCATABLE_VALUE */ TRUE, + /* BSS_VALUE */ TRUE, + /* STRUCT_VALUE */ FALSE, + /* FIELD_VALUE */ FALSE, + /* MACRO_VALUE */ FALSE, + /* OPERAND_VALUE */ FALSE, + /* STRING_VALUE */ FALSE, + /* CONDITION_VALUE */ FALSE, + /* UNDEFINED_VALUE */ TRUE, + /* FUNCTION_VALUE */ FALSE, + /* BLOCK_VALUE */ FALSE, + /* BUILT_IN_FUNCTION_VALUE */ FALSE, + /* ARRAY_VALUE */ FALSE, + /* FAIL */ FALSE, + }; + + if (value == NULL) + return(FALSE); + else + return(incrementableTable[(int)value->kindOfValue]); +} + + int +intValue(value) + valueType *value; +{ + if (value->kindOfValue != ABSOLUTE_VALUE) { + error(VALUE_IS_NOT_AN_INT_ERROR); + return(0); + } else { + return(value->value); + } +} + + bool +isAssignable(context) + symbolInContextType *context; +{ + return( context->usage==ARGUMENT_SYMBOL || + context->usage==VARIABLE_SYMBOL || + context->usage==MVARIABLE_SYMBOL ); +} + + bool +isBuiltInFunction(context) + symbolInContextType *context; +{ + return(context!=NULL && context->usage==BUILT_IN_FUNCTION_SYMBOL); +} + + bool +isDefinable(context) + symbolInContextType *context; +{ + return( context->usage==DEFINE_SYMBOL || + context->usage==DEAD_SYMBOL || + context->usage==UNKNOWN_SYMBOL || + context->usage==NESTED_UNKNOWN_SYMBOL ); +} + + bool +isExternal(symbol) + symbolTableEntryType *symbol; +{ + symbolInContextType *context; + + symbolInContextType *getBaseContext(); + + context = getBaseContext(symbol); + return (context!=NULL && (context->attributes & GLOBAL_ATT)!=0 && + context->usage != DEAD_SYMBOL); +} + + bool +isFailure(value) + valueType *value; +{ + if (value == NULL) + return(FALSE); + else + return(value->kindOfValue == FAIL); +} + + bool +isFunction(context) + symbolInContextType *context; +{ + return(context!=NULL && context->usage==FUNCTION_SYMBOL); +} + + bool +isLastStatementInBlock(statement) + statementType *statement; +{ + statement = statement->nextStatement; + while (statement != NULL) { + if (statement->kindOfStatement != BLOCK_STATEMENT && + statement->kindOfStatement != BYTE_STATEMENT && + statement->kindOfStatement != CONSTRAIN_STATEMENT && + statement->kindOfStatement != DBYTE_STATEMENT && + statement->kindOfStatement != DO_UNTIL_STATEMENT && + statement->kindOfStatement != DO_WHILE_STATEMENT && + statement->kindOfStatement != GROUP_STATEMENT && + statement->kindOfStatement != IF_STATEMENT && + statement->kindOfStatement != INCLUDE_STATEMENT && + statement->kindOfStatement != INSTRUCTION_STATEMENT && + statement->kindOfStatement != LONG_STATEMENT && + statement->kindOfStatement != STRING_STATEMENT && + statement->kindOfStatement != STRUCT_STATEMENT && + statement->kindOfStatement != WHILE_STATEMENT && + statement->kindOfStatement != MIF_STATEMENT && + statement->kindOfStatement != MWHILE_STATEMENT && + statement->kindOfStatement != MFOR_STATEMENT && + statement->kindOfStatement != MDO_WHILE_STATEMENT && + statement->kindOfStatement != MDO_UNTIL_STATEMENT && + statement->kindOfStatement != MSWITCH_STATEMENT && + statement->kindOfStatement != WORD_STATEMENT) + statement = statement->nextStatement; + else + return(FALSE); + } + return(TRUE); +} + + bool +isLogicalOp(op) + int op; +{ + return (op==EQUAL_TO || op==GREATER_THAN || op== + GREATER_THAN_OR_EQUAL_TO || op==LESS_THAN || op== + LESS_THAN_OR_EQUAL_TO || op==NOT_EQUAL_TO || op== + LOGICAL_AND || op==LOGICAL_OR || op==LOGICAL_XOR); +} + + bool +isPotentialVariable(context) + symbolInContextType *context; +{ + return( context->usage == VARIABLE_SYMBOL || + context->usage == DEAD_SYMBOL || + context->usage == NESTED_UNKNOWN_SYMBOL ); +} + + bool +isUndefined(value) + valueType *value; +{ + return(value==NULL || value->kindOfValue==UNDEFINED_VALUE); +} + + bool +isUsable(value) + valueType *value; +{ + return(value!=NULL && value->kindOfValue!=UNDEFINED_VALUE && + value->kindOfValue!=FAIL); +} + + bool +logicalXOR(int1, int2) + int int1; + int int2; +{ + return((int1 && !int2) || (int2 && !int1)); +} + + valueType * +newValue(kindOfValue, value, addressMode) + valueKindType kindOfValue; + int value; + operandKindType addressMode; +{ + valueType *result; + + result = typeAlloc(valueType); + result->kindOfValue = kindOfValue; + result->value = value; + result->addressMode = addressMode; + return(result); +} + + valueKindType +opValueKind(leftOperand, rightOperand) + valueType *leftOperand; + valueType *rightOperand; +{ + if (leftOperand->kindOfValue==ABSOLUTE_VALUE && rightOperand-> + kindOfValue==ABSOLUTE_VALUE) + return(ABSOLUTE_VALUE); + else if ((leftOperand->kindOfValue==ABSOLUTE_VALUE && rightOperand-> + kindOfValue==UNDEFINED_VALUE) || + (leftOperand->kindOfValue==UNDEFINED_VALUE && rightOperand-> + kindOfValue==ABSOLUTE_VALUE) || + (leftOperand->kindOfValue==RELOCATABLE_VALUE &&rightOperand-> + kindOfValue==UNDEFINED_VALUE) || + (leftOperand->kindOfValue==UNDEFINED_VALUE && rightOperand-> + kindOfValue==RELOCATABLE_VALUE) || + (leftOperand->kindOfValue==RELOCATABLE_VALUE &&rightOperand-> + kindOfValue==ABSOLUTE_VALUE) || + (leftOperand->kindOfValue==ABSOLUTE_VALUE && rightOperand-> + kindOfValue==RELOCATABLE_VALUE) || + (leftOperand->kindOfValue==RELOCATABLE_VALUE &&rightOperand-> + kindOfValue==RELOCATABLE_VALUE) || + (leftOperand->kindOfValue==UNDEFINED_VALUE && rightOperand-> + kindOfValue==UNDEFINED_VALUE)) + return(UNDEFINED_VALUE); + else + return(FAIL); +} + + bool +relocatableValue(address) + valueType *address; +{ + return( address->kindOfValue==DATA_VALUE || + address->kindOfValue==RELOCATABLE_VALUE ); +} + + valueKindType +selectValueKind(leftOperand, rightOperand) + valueType *leftOperand; + valueType *rightOperand; +{ + if (rightOperand->kindOfValue!=FIELD_VALUE || + (leftOperand->kindOfValue!=ABSOLUTE_VALUE && + leftOperand->kindOfValue!=RELOCATABLE_VALUE && + leftOperand->kindOfValue!=DATA_VALUE)) + return(FAIL); + else + return(leftOperand->kindOfValue); +} + + valueKindType +subValueKind(leftOperand, rightOperand) + valueType *leftOperand; + valueType *rightOperand; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'valueKindType'. */ + static valueKindType subValueKindTable[NUM_OF_VALUE_KINDS] + [NUM_OF_VALUE_KINDS] = { +/* ABSOLUTE_VALUE , DATA_VALUE , RELOCATABLE_VALUE , + BSS_VALUE , STRUCT_VALUE , FIELD_VALUE , + MACRO_VALUE , OPERAND_VALUE , STRING_VALUE , + CONDITION_VALUE, UNDEFINED_VALUE, FUNCTION_VALUE , + BLOCK_VALUE , BUILT_IN_FUNCTI, ARRAY_VALUE , + FAIL , */ + +/*ABSOLUTE_VALUE */ ABSOLUTE_VALUE , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*DATA_VALUE */ DATA_VALUE , ABSOLUTE_VALUE , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*RELOCATABLE_VAL*/ RELOCATABLE_VALUE, FAIL , UNDEFINED_VALUE, + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*BSS_VALUE */ BSS_VALUE , FAIL , FAIL , + BSS_VALUE , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*STRUCT_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*FIELD_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*MACRO_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*OPERAND_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*STRING_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*CONDITION_VALUE*/ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*UNDEFINED_VALUE*/ UNDEFINED_VALUE, FAIL , UNDEFINED_VALUE, + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , UNDEFINED_VALUE, FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*FUNCTION_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*BLOCK_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*BUILT_IN_FUNCT-*/ FAIL , FAIL , FAIL , +/*-ION_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*ARRAY_VALUE */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + +/*FAIL */ FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL , FAIL , FAIL , + FAIL, + }; + + return(subValueKindTable[(int)leftOperand->kindOfValue] + [(int)rightOperand->kindOfValue]); +} + + int +swab(i) + int i; +{ + return(((i & 0xFF) << 8) | ((i & 0xFF00) >> 8)); +} + + valueType * +swabValue(value) + valueType *value; +{ + valueType *newValue(); + + return(newValue(value->kindOfValue, swab(value->value), value-> + addressMode)); +} + + valueKindType +unopValueKind(operand) + valueType *operand; +{ + return(operand->kindOfValue==ABSOLUTE_VALUE || operand->kindOfValue== + UNDEFINED_VALUE || operand->kindOfValue==RELOCATABLE_VALUE ? + operand->kindOfValue : FAIL); +} + + void +valueField(symbol, value) + symbolTableEntryType *symbol; + valueType *value; +{ + symbolInContextType *workingContext; + + symbolInContextType *getWorkingContext(); + symbolTableEntryType *effectiveSymbol(); + + symbol = effectiveSymbol(symbol, &workingContext); + expand(moreLabel("%s:", symbol->symbolName)); + if (workingContext->usage == DEAD_SYMBOL) + reincarnateSymbol(workingContext, STRUCT_FIELD_SYMBOL); + if (workingContext->usage!=LABEL_SYMBOL && workingContext->usage!= + UNKNOWN_SYMBOL && workingContext->usage!= + NESTED_UNKNOWN_SYMBOL) + error(SYMBOL_ALREADY_THERE_ERROR, symbName(symbol)); + else if (workingContext->value==NULL || workingContext->value-> + kindOfValue==UNDEFINED_VALUE) { + workingContext->value = value; + workingContext->usage = STRUCT_FIELD_SYMBOL; + workingContext->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; + } else + error(FIELD_ALREADY_DEFINED_ERROR, symbName(symbol)); +} + + void +valueLabel(symbol, value) + symbolTableEntryType *symbol; + valueType *value; +{ + symbolInContextType *workingContext; + + symbolTableEntryType *generateLocalLabel(); + symbolInContextType *getBaseContext(); + symbolTableEntryType *effectiveSymbol(); + + symbol = effectiveSymbol(symbol, &workingContext); + expand(moreLabel("%s:", symbol->symbolName)); + if (workingContext->usage == DEAD_SYMBOL) + reincarnateSymbol(workingContext, LABEL_SYMBOL); + if (workingContext->usage!=LABEL_SYMBOL && workingContext->usage!= + UNKNOWN_SYMBOL && workingContext->usage!= + NESTED_UNKNOWN_SYMBOL) + error(SYMBOL_ALREADY_THERE_ERROR, symbName(symbol)); + else if (symbName(symbol)[0] == '$') { + symbol = generateLocalLabel(symbol); + workingContext = getBaseContext(symbol); + workingContext->value = value; + if (targetOffset != 0) { + workingContext->value->kindOfValue = ABSOLUTE_VALUE; + workingContext->value->value -= targetOffset; + } + workingContext->usage = LABEL_SYMBOL; + workingContext->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; + } else if (workingContext->value==NULL || workingContext->value-> + kindOfValue==UNDEFINED_VALUE) { + workingContext->value = value; + if (targetOffset != 0) { + workingContext->value->value -= targetOffset; + workingContext->value->kindOfValue = ABSOLUTE_VALUE; + } + workingContext->usage = LABEL_SYMBOL; + workingContext->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; + if (workingContext->attributes & TENTATIVE_GLOBAL_ATT) + workingContext->attributes |= GLOBAL_ATT; + } else + error(LABEL_ALREADY_DEFINED_ERROR, symbName(symbol)); + symbol->referenceCount++; +} + +/* + These routines deal with fixups and references. + */ + + void +createFixup(expression, location, kindOfFixup, codeMode, whichFixup) + expressionType *expression; + addressType location; + fixupKindType kindOfFixup; + codeBufferKindType codeMode; + int whichFixup; +{ + fixupListType *newFixup; + + expressionType *generateFixupExpression(); + + if (debug || emitPrint) + printCreateFixup(expression, location, kindOfFixup); + newFixup = typeAlloc(fixupListType); + newFixup->locationToFixup = location; + newFixup->targetOffset = targetOffset; + newFixup->codeMode = codeMode; + newFixup->kindOfFixup = kindOfFixup; + newFixup->fileName = currentFileName; + newFixup->lineNumber = currentLineNumber; + expand(flushExpressionString()); + newFixupAddressMode = EXPRESSION_OPND; + newFixup->theFixupExpression = generateFixupExpression(expression); + if (newFixupAddressMode != EXPRESSION_OPND) + fixupAddressMode[whichFixup] = newFixupAddressMode; + expand(finishOperand ? expandOperand(fixupAddressMode[whichFixup], + operandBuffer[whichFixup]) : /*expandExpression(NULL)*/0); + finishOperand = FALSE; + if (structNestingDepth == 0) { + newFixup->nextFixup = fixupList; + fixupList = newFixup; + } else { + newFixup->nextFixup = newStruct->structFixups; + newStruct->structFixups = newFixup; + } +} + + void +finishUp() +{ + void performFixups(); + void performStartAddressFixup(); + + if (listingOn) + terminateListingFiles(); + performFixups(fixupList); + if (haveUserStartAddress && fixupStartAddress) + performStartAddressFixup(); + outputObjectFile(); + if (listingOn) + outputListing(); +} +/* + bool +isReferenceToRemember(reference) + expressionReferenceListType *reference; +{ + symbolInContextType *context; + + symbolInContextType *getWorkingContext(); + + context = getWorkingContext(reference->expressionReferenced); + if (context != NULL) + return ((context->usage == LABEL_SYMBOL && context->value-> + kindOfValue != ABSOLUTE_VALUE) || context->usage == + EXTERNAL_SYMBOL || context->usage == UNKNOWN_SYMBOL + || context->usage == NESTED_UNKNOWN_SYMBOL); + else + return(FALSE); +} +*/ + void +noteAnonymousReference() +{ + expressionReferenceListType *newReference; + + if (!produceLinkableObject || targetOffset != 0) + return; + + newReference = typeAlloc(expressionReferenceListType); + newReference->nextReference = expressionReferenceList[(int) + currentCodeMode]; + expressionReferenceList[(int)currentCodeMode] = newReference; + newReference->expressionReferenced = NULL; + newReference->relocation.referenceAddress = currentLocationCounter. + value; + newReference->relocation.referenceExpression = -1; + newReference->relocation.referenceRelative = FALSE; + newReference->relocation.referenceKind = REF_WORD; + newReference->relocation.referenceExternal = FALSE; + newReference->relocation.referenceMode = (int)currentCodeMode; +} + + void +noteReference(expression, kindOfFixup, location, codeMode) + expressionType *expression; + fixupKindType kindOfFixup; + addressType location; + codeBufferKindType codeMode; +{ + expressionReferenceListType *newReference; + + if (!produceLinkableObject) + return; + + newReference = typeAlloc(expressionReferenceListType); + numberOfReferencesInList[(int)codeMode]++; + newReference->nextReference = expressionReferenceList[(int)codeMode]; + expressionReferenceList[(int)codeMode] = newReference; + newReference->expressionReferenced = expression; + newReference->relocation.referenceAddress = location; + newReference->relocation.referenceMode = (int)codeMode; + newReference->relocation.referenceExpression = 0; + switch (kindOfFixup) { + case BYTE_FIXUP: + newReference->relocation.referenceRelative = FALSE; + newReference->relocation.referenceKind = REF_BYTE; + break; + case WORD_FIXUP: + newReference->relocation.referenceRelative = FALSE; + newReference->relocation.referenceKind = REF_WORD; + break; + case LONG_FIXUP: + newReference->relocation.referenceRelative = FALSE; + newReference->relocation.referenceKind = REF_LONG; + break; + case DBYTE_FIXUP: + newReference->relocation.referenceRelative = FALSE; + newReference->relocation.referenceKind = REF_DBYTE; + break; + case BYTE_RELATIVE_FIXUP: + newReference->relocation.referenceRelative = TRUE; + newReference->relocation.referenceKind = REF_BYTE; + break; + case WORD_RELATIVE_FIXUP: + newReference->relocation.referenceRelative = TRUE; + newReference->relocation.referenceKind = REF_WORD; + break; + default: + botch("bad fixup kind in noteReference %d\n", + kindOfFixup); + } + newReference->relocation.referenceExternal = FALSE; /* irrelevent? */ +} + + void +performFixups(fixups) + fixupListType *fixups; +{ + valueType *evaluateExpression(); + valueType *valueToPoke; + + performingFixups = TRUE; + statementEvaluationDepth = 2; /* don't throw away functions! */ + while (fixups != NULL) { + if (fixups->theFixupExpression == NULL) + break; + currentFileName = fixups->fileName; + currentLineNumber = fixups->lineNumber; + currentCodeMode = fixups->codeMode; + targetOffset = fixups->targetOffset; + valueToPoke = evaluateExpression(fixups->theFixupExpression, + NO_FIXUP); + if (isUndefined(valueToPoke)) { + noteReference(fixups->theFixupExpression, fixups-> + kindOfFixup, fixups->locationToFixup, fixups-> + codeMode); + } else { + switch (fixups->kindOfFixup) { + + case BYTE_FIXUP: + pokeByteValue(fixups->locationToFixup, + valueToPoke); + break; + + case WORD_FIXUP: + pokeWordValue(fixups->locationToFixup, + valueToPoke); + break; + + case LONG_FIXUP: + pokeLongValue(fixups->locationToFixup, + valueToPoke); + break; + + case DBYTE_FIXUP: + pokeWordValue(fixups->locationToFixup, + swabValue(valueToPoke)); + break; + + case BYTE_RELATIVE_FIXUP: + pokeRelativeByteValue(fixups->locationToFixup, + valueToPoke); + break; + + case WORD_RELATIVE_FIXUP: + pokeRelativeWordValue(fixups->locationToFixup, + valueToPoke); + break; + + default: + botch("bad fixup at end\n"); + } + } + fixups = fixups->nextFixup; + } +} + + void +performStartAddressFixup() +{ + expressionType *startAddressExpression; + + expressionType *generateFixupExpression(); + + startAddressExpression = (expressionType *)startAddress; + startAddress = evaluateExpression(startAddressExpression,NO_FIXUP_OK); + if (startAddress->kindOfValue == UNDEFINED_VALUE && + produceLinkableObject) { + startAddress = (valueType *)generateFixupExpression( + startAddressExpression); + } else if (startAddress->kindOfValue != ABSOLUTE_VALUE && + startAddress->kindOfValue != RELOCATABLE_VALUE) { + error(BAD_START_ADDRESS_ERROR); + haveUserStartAddress = FALSE; + } else { + fixupStartAddress = FALSE; + } +} + + void +putFixupsHere(kindOfFixupsToPut, whichFixup) + fixupKindType kindOfFixupsToPut; + int whichFixup; +{ + int location; + + location = structNestingDepth==0 ? currentLocationCounter.value : + currentFieldOffset; + if (pendingFixup[whichFixup] != NULL) { + createFixup(pendingFixup[whichFixup], location, + kindOfFixupsToPut, currentCodeMode, whichFixup); + } +} +/* + void +putReferencesHere(kindOfReferencesToPut, whichReference) + fixupKindType kindOfReferencesToPut; +{ + expressionReferenceListType *worthyReference; + int currentLocation; + int currentMode; + + if (!produceLinkableObject) + return; + + currentLocation = structNestingDepth==0 ? + currentLocationCounter.value : currentFieldOffset; + currentMode = structNestingDepth==0 ? (int)currentCodeMode : + STRUCT_BUFFER; + while (referencesToNote[whichReference] != NULL) { + if (isReferenceToRemember(referencesToNote[whichReference])) { + switch (kindOfReferencesToPut) { + case BYTE_FIXUP: + referencesToNote[whichReference]-> + relocation.referenceKind = REF_BYTE; + break; + case WORD_FIXUP: + referencesToNote[whichReference]-> + relocation.referenceKind = REF_WORD; + break; + case LONG_FIXUP: + referencesToNote[whichReference]-> + relocation.referenceKind = REF_LONG; + break; + case BYTE_RELATIVE_FIXUP: + referencesToNote[whichReference]-> + relocation.referenceKind = REF_BYTE; + referencesToNote[whichReference]-> + relocation.referenceRelative = TRUE; + break; + case WORD_RELATIVE_FIXUP: + referencesToNote[whichReference]-> + relocation.referenceKind = REF_WORD; + referencesToNote[whichReference]-> + relocation.referenceRelative = TRUE; + break; + case DBYTE_FIXUP: + referencesToNote[whichReference]-> + relocation.referenceKind = REF_DBYTE; + break; + default: + botch("bad fixup kind in put references %d\n", + kindOfReferencesToPut); + break; + } + numberOfReferencesInList[currentMode]++; + referencesToNote[whichReference]-> + relocation.referenceAddress = currentLocation; + referencesToNote[whichReference]-> + relocation.referenceMode = currentMode; + worthyReference = referencesToNote[whichReference]; + referencesToNote[whichReference] = + referencesToNote[whichReference]-> + nextReference; + worthyReference->nextReference = + expressionReferenceList[currentMode]; + expressionReferenceList[currentMode]= worthyReference; + } else { + worthyReference = referencesToNote[whichReference]; + referencesToNote[whichReference] = + referencesToNote[whichReference]-> + nextReference; + qsfree(worthyReference); + } + } +} +*/ + +/* + These routines handle contexts and dynamic symbol creation. + */ + + void +addNewLocalVariable(symbol) + symbolTableEntryType *symbol; +{ + identifierListType *newLocalVariable; + + newLocalVariable = typeAlloc(identifierListType); + newLocalVariable->theSymbol = symbol; + newLocalVariable->nextIdentifier = currentLocalVariableList; + currentLocalVariableList = newLocalVariable; +} + + symbolTableEntryType * +effectiveSymbol(symbol, assignmentTargetContext) + symbolTableEntryType *symbol; + symbolInContextType **assignmentTargetContext; +{ + symbolInContextType *context; + operandType *operand; + expressionType *expression; + environmentType *saveEnvironment; + + symbolInContextType *getWorkingContext(); + + context = getWorkingContext(symbol); + saveEnvironment = currentEnvironment; + while (context != NULL && context->usage == ARGUMENT_SYMBOL && + context->value->kindOfValue == OPERAND_VALUE) { + operand = (operandType *)context->value->value; + if (operand->kindOfOperand == EXPRESSION_OPND) { + expression = operand->theOperand.expressionUnion; + if (expression->kindOfTerm == IDENTIFIER_EXPR) { + currentEnvironment = currentEnvironment-> + previousEnvironment; + context =getWorkingContext(symbol=expression-> + expressionTerm.identifierUnion); + } else { + break; + } + } else { + break; + } + } + currentEnvironment = saveEnvironment; + if (assignmentTargetContext != NULL) + *assignmentTargetContext = context; + return(symbol); +} + + symbolTableEntryType * +generateLocalLabel(symbol) + symbolTableEntryType *symbol; +{ + stringType *localLabelString(); + symbolTableEntryType *lookupOrEnterSymbol(); + + return(lookupOrEnterSymbol(localLabelString(symbol), LABEL_SYMBOL)); +} + + symbolInContextType * +getBaseContext(identifier) + symbolTableEntryType *identifier; +{ + symbolInContextType *result; + + result = identifier->context; + while (result != NULL && result->environmentNumber != + GLOBAL_ENVIRONMENT_NUMBER) + result = result->pushedContexts; + return(result); +} + + symbolInContextType * +getWorkingContext(identifier) + symbolTableEntryType *identifier; +{ + symbolInContextType *result; + + result = identifier->context; + while (result != NULL && result->environmentNumber != + GLOBAL_ENVIRONMENT_NUMBER && result-> + environmentNumber != currentEnvironment-> + environmentNumber) + result = result->pushedContexts; + return(result); +} + + stringType * +localLabelString(symbol) + symbolTableEntryType *symbol; +{ +#define TEMP_SYMBOL_SIZE_LIMIT 200 + char nameUnderConstruction[TEMP_SYMBOL_SIZE_LIMIT]; + + stringType *saveString(); + + sprintf(nameUnderConstruction, "_%d_", localLabelTagValue(symbol)); + strncat(nameUnderConstruction, &(symbName(symbol)[1]), + TEMP_SYMBOL_SIZE_LIMIT); + return(saveString(nameUnderConstruction)); +} + + int +localLabelTagValue(symbol) + symbolTableEntryType *symbol; +{ + symbolInContextType *context; + + symbolInContextType *getWorkingContext(); + void addNewLocalVariable(); + + context = getWorkingContext(symbol); + if (context == NULL) + botch("local label doesn't have symbol context\n"); + if(context->environmentNumber!=currentEnvironment->environmentNumber){ + pushBinding(symbol, newValue(ABSOLUTE_VALUE, + currentLabelTagNumber, EXPRESSION_OPND), + LABEL_SYMBOL); + addNewLocalVariable(symbol); + return(currentLabelTagNumber); + } + return(context->value->value); +} + + void +addBreak(kind, data) + codeBreakKindType kind; + int data; +{ + codeBreakType *newBreak; + codeBreakType *buildCodeBreak(); + + newBreak = buildCodeBreak(kind, currentLocationCounter.value, data); + if (codeBreakList == NULL) { + codeBreakList = lastCodeBreak = newBreak; + } else { + lastCodeBreak->nextBreak = newBreak; + lastCodeBreak = newBreak; + } +} + + void +reserveAbsolute(startAddress, blockSize) + addressType startAddress; + int blockSize; +{ + reservationListType *buildReservation(); + + if (reservationList != NULL && reservationList->startAddress + + reservationList->blockSize == startAddress) + reservationList->blockSize += blockSize; + else + reservationList = buildReservation(startAddress, blockSize, + reservationList); +} + + bool +listableStatement(kind) + statementKindType kind; +{ + return( kind == ALIGN_STATEMENT || kind == BLOCK_STATEMENT || + kind == BYTE_STATEMENT || kind == CONSTRAIN_STATEMENT || + kind == DBYTE_STATEMENT || kind == DO_UNTIL_STATEMENT || + kind == DO_WHILE_STATEMENT || kind == IF_STATEMENT || + /*kind == INSTRUCTION_STATEMENT ||*/ kind == ORG_STATEMENT || + kind == REL_STATEMENT || kind == START_STATEMENT || + kind == STRUCT_STATEMENT || kind == LONG_STATEMENT || + kind == STRING_STATEMENT || kind == WHILE_STATEMENT || + kind == WORD_STATEMENT || kind == DEFINE_STATEMENT || + kind == EXTERN_STATEMENT || kind == INCLUDE_STATEMENT || + kind == UNDEFINE_STATEMENT || kind == VARIABLE_STATEMENT || + kind == TARGET_STATEMENT); +} diff --git a/semanticMisc.o b/semanticMisc.o new file mode 100644 index 0000000..00bb997 Binary files /dev/null and b/semanticMisc.o differ diff --git a/slinky/.mark b/slinky/.mark new file mode 100644 index 0000000..e259cf5 --- /dev/null +++ b/slinky/.mark @@ -0,0 +1 @@ +Fri Jun 6 14:51:43 PDT 1986 diff --git a/slinky/DOC b/slinky/DOC new file mode 100644 index 0000000..72b16fe --- /dev/null +++ b/slinky/DOC @@ -0,0 +1,8 @@ +/u0/chip/macross/slinky: + This directory contains the source to Slinky. Here's what's here: + +DOC - This file +Makefile - Makefile to compile it +*.c, *.h - source files +opt/ - directory for optimized version, as mentioned in + documentation above for /u0/chip/macross/opt diff --git a/slinky/Makefile b/slinky/Makefile new file mode 100644 index 0000000..5e01400 --- /dev/null +++ b/slinky/Makefile @@ -0,0 +1,77 @@ +.SUFFIXES: .o .c .h .run + +OBJECTS = builtins.o debugPrint.o errorStuff.o expr.o initialize.o\ +instantiate.o link.o main.o map.o poke.o read.o relocate.o slinkyTables.o\ +write.o + +SOURCES = builtins.c debugPrint.c errorStuff.c expr.c initialize.c\ +instantiate.c link.c main.c map.c poke.c read.c relocate.c slinkyTables.c\ +write.c slinkyExpressions.h slinkyGlobals.h slinkyTypes.h y.tab.h + +.c.o: + cc -c -g $*.c + +.c.run: + cc -o $* $*.c + +slinky: $(OBJECTS) + cc -g -o slinky $(OBJECTS) + +update: .mark + kessel "(cd /u0/chip/macross/slinky; make slinky >&errorfyle)" & + +move: .mark + +.mark: $(SOURCES) +# cp $? /net/kessel/u0/chip/macross/slinky + cp $? /net/kessel/u0/chip/macross/slinky +# cp $? /net/kessel/u0/chip/macross/slinky/prof + cp $? /net/kessel/u0/chip/macross/slinky/prof + cp $? opt + date >.mark +# date >/net/kessel/u0/chip/macross/slinky/.mark + date >/net/kessel/u0/chip/macross/slinky/.mark +# date >/net/kessel/u0/chip/macross/slinky/prof/.mark + date >/net/kessel/u0/chip/macross/slinky/prof/.mark + date >opt/.mark + +install: slinky + cp slinky /u1/gg/bin/slinky_tmp + strip /u1/gg/bin/slinky_tmp + mv /u1/gg/bin/slinky /u1/gg/bin/sliny.old + mv /u1/gg/bin/slinky_tmp /u1/gg/bin/slinky + +builtins.o: builtins.c slinkyGlobals.h slinkyTypes.h slinkyExpressions.h + +debugPrint.o: debugPrint.c slinkyGlobals.h slinkyTypes.h + +errorStuff.o: errorStuff.c slinkyGlobals.h slinkyTypes.h + +expr.o: expr.c slinkyExpressions.h slinkyGlobals.h slinkyTypes.h y.tab.h + +initialize.o: initialize.c slinkyGlobals.h slinkyTypes.h + +instantiate.o: instantiate.c slinkyGlobals.h slinkyTypes.h slinkyExpressions.h + +link.o: link.c slinkyGlobals.h slinkyTypes.h + +main.o: main.c slinkyGlobals.h slinkyTypes.h + +map.o: map.c slinkyGlobals.h slinkyTypes.h + +poke.o: poke.c slinkyGlobals.h slinkyTypes.h + +read.o: read.c slinkyGlobals.h slinkyTypes.h + +relocate.o: relocate.c slinkyGlobals.h slinkyTypes.h + +slinkyTables.o: slinkyTables.c slinkyTypes.h + +write.o: write.c slinkyGlobals.h slinkyTypes.h + +cleanup: + /bin/rm -f *.o slinky + +love: + @echo "Not war?" + diff --git a/slinky/builtins.c b/slinky/builtins.c new file mode 100644 index 0000000..055c530 --- /dev/null +++ b/slinky/builtins.c @@ -0,0 +1,431 @@ +/* + builtins.c -- Built-in functions for the Slinky linker + + Chip Morningstar -- Lucasfilm Ltd. + + 14-November-1985 +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" +#include "slinkyExpressions.h" +#include + +#define getSymbol() ((symbolType *)getNumber()) + + void +tooFewArgs(argCount, name) + int argCount; + stringType *name; +{ + error(TOO_FEW_ARGUMENTS_TO_BIF_ERROR, name); + while (argCount-- > 0) + skipExpression(); +} + + void +tooManyArgs(argCount, name) + int argCount; + stringType *name; +{ + error(TOO_MANY_ARGUMENTS_TO_BIF_ERROR, name); + while (argCount-- > 0) + skipExpression(); +} + +/* + The built-in-functions themselves: pointers to these are loaded into the + builtInFunctionTable at linker compile time. These are all known within + the Macross assembler: each symbol of the form "xxx" is assigned a pointer + to "xxxBIF" (BIF == Built-In-Function). + */ + +/* The two ATASCII related BIF's refer to this table -- This really only + makes sense for the 6502 version, but is harmless in other versions. */ +static char atasciiTable[] = { /* 0xFFs will become 0x00s on output */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0xFF, +}; + +/* Convert a string to ATASCII */ + stringType * +atasciiBIF(argCount) + int argCount; +{ + stringType *string; + stringType *newString; + int i; + + if (argCount == 0) { + return(""); + } else if (argCount > 1) { + tooManyArgs(argCount, "atascii"); + return(""); + } else { + string = (stringType *)evaluateExpression(); + newString = (stringType *)malloc(strlen(string)+1); + for (i=0; string[i]!='\0'; i++) + newString[i] = atasciiTable[string[i]]; + newString[i] = '\0'; + return(newString); + } +} + +/* Convert a string to ATASCII while setting high-order color bits */ + stringType * +atasciiColorBIF(argCount) + int argCount; +{ + stringType *string; + stringType *newString; + int color; + int i; + byte testChar; + + if (argCount == 0) { + return(""); + } else if (argCount == 1) { + return(atasciiBIF(argCount)); + } else if (argCount > 2) { + tooManyArgs(argCount, "atasciiColor"); + return(""); + } else { + string = (stringType *)evaluateExpression(); + color = (evaluateExpression() & 0x03) << 6; + newString = (stringType *)malloc(strlen(string)+1); + for (i=0; string[i]!='\0'; i++) { + testChar = atasciiTable[string[i]]; + if (testChar == 0xFF) + testChar = 0; + testChar = (testChar & 0x3F) | color; + if (testChar == 0) + testChar = 0xFF; + newString[i] = testChar; + } + newString[i] = '\0'; + return(newString); + } +} + +/* Check if an operand is absolute (as opposed to relocatable) */ + bool +isAbsoluteValueBIF(argCount) + int argCount; +{ + if (argCount > 1) + tooManyArgs(argCount, "isAbsoluteValue"); + return(TRUE); +} + +/* Check if operand is a condition code */ + bool +isConditionCodeBIF(argCount) + int argCount; +{ + bool result; + + if (argCount == 0) + return(FALSE); + else if (argCount > 1) { + tooManyArgs(argCount, "isConditionCode"); + return(FALSE); + } + result = (*pc == CONDITION_CODE_TAG); + skipExpression(); + return(result); +} + +/* Check if a symbol is defined */ + bool +isDefinedBIF(argCount) + int argCount; +{ + symbolType *symbol; + + if (argCount == 0) + return(FALSE); + else if (argCount > 1) { + tooManyArgs(argCount, "isDefined"); + return(FALSE); + } + if (*pc != IDENTIFIER_TAG) { + skipExpression(); + return(TRUE); + } + pc++; /* skip tag */ + symbol = getSymbol(); + return((symbol->symbolClass & ~SYMBOL_EXTERNAL) != 0); +} + +/* Check if a symbol is externally visible */ + bool +isExternalBIF(argCount) + int argCount; +{ + symbolType *symbol; + + if (argCount == 0) + return(FALSE); + else if (argCount > 1) { + tooManyArgs(argCount, "isExternal"); + return(FALSE); + } + if (*pc != IDENTIFIER_TAG) { + skipExpression(); + return(TRUE); + } + pc++; /* skip tag */ + symbol = getSymbol(); + return((symbol->symbolClass & SYMBOL_EXTERNAL) != 0); +} + +/* Return the Nth character of a string (as an integer) */ + int +nthCharBIF(argCount) + int argCount; +{ + stringType *string; + int position; + + if (argCount > 2) { + tooManyArgs(argCount, "nthChar"); + return(0); + } else if (argCount != 2) { + tooFewArgs(argCount, "nthChar"); + return(0); + } + string = (stringType *)evaluateExpression(); + position = evaluateExpression(); + if (position >= strlen(string)) { + error(BAD_POSITION_ARGUMENT_TO_NTH_CHAR_ERROR); + return(0); + } + return(string[position]); +} + +/* Pass stuff through to stdio's 'printf' function */ + int +printfBIF(argCount) + int argCount; +{ + stringType *formatString; + int argument[20]; + int i; + + if (argCount < 1) { + tooFewArgs(argCount, "printf"); + return(0); + } else if (argCount > 21) { + tooManyArgs(argCount, "printf"); + return(0); + } + formatString = (stringType *)evaluateExpression(); + argCount--; + for (i=0; i 2) { + tooManyArgs(argCount, "strcat"); + return(""); + } + string1 = (stringType *)evaluateExpression(); + string2 = (stringType *)evaluateExpression(); + newString = (stringType *)malloc(strlen(string1)+strlen(string2)+1); + strcpy(newString, string1); + strcat(newString, string2); + return(newString); +} + +/* Compare two strings */ + int +strcmpBIF(argCount) + int argCount; +{ + stringType *string1; + stringType *string2; + + if (argCount < 2) { + tooFewArgs(argCount, "strcmp"); + return(0); + } else if (argCount > 2) { + tooManyArgs(argCount, "strcmp"); + return(0); + } + string1 = (stringType *)evaluateExpression(); + string2 = (stringType *)evaluateExpression(); + return(strcmp(string1, string2)); +} + +/* Compare two strings in a case-independent fashion */ + int +strcmplcBIF(argCount) + int argCount; + +{ + stringType *string1; + stringType *string2; + + if (argCount < 2) { + tooFewArgs(argCount, "strcmplc"); + return(0); + } else if (argCount > 2) { + tooManyArgs(argCount, "strcmplc"); + return(0); + } + string1 = (stringType *)evaluateExpression(); + string2 = (stringType *)evaluateExpression(); + return(strcmplc(string1, string2)); +} + +/* Return the length of a string */ + int +strlenBIF(argCount) + int argCount; +{ + if (argCount < 1) + return(0); + else if (argCount > 1) { + tooManyArgs(argCount, "strlen"); + return(0); + } + return(strlen(evaluateExpression())); +} + +/* Return a substring of a string */ + char * +substrBIF(argCount) + int argCount; +{ + stringType *string; + int start; + int length; + stringType *newString; + int originalLength; + bool backwards; + + if (argCount < 1) + return(""); + else if (argCount == 1) + return((stringType *)evaluateExpression()); + else if (argCount > 3) { + tooManyArgs(argCount, "substr"); + return(""); + } + string = (stringType *)evaluateExpression(); + originalLength = strlen(string); + start = evaluateExpression(); + if (start < 0) { + start = -start - 1; + backwards = TRUE; + } else + backwards = FALSE; + if (argCount == 2) { + length = originalLength - start; + if (backwards) + length = -length; + } else { + length = evaluateExpression(); + } + if (length < 0) { + length = -length; + if (backwards) + start = start + length - 1; + else + start = start - length + 1; + } + if (backwards) + start = originalLength - start - 1; + if (originalLength <= start || originalLength < length + start || + start < 0 ){ + error(BAD_SUBSTRING_INDICES_ERROR); + return(""); + } + newString = (stringType *)malloc(length+1); + strncpy(newString, string+start, length); + newString[length] = '\0'; + return(newString); +} + +/* Turn a string into a symbol and return its value */ + addressType +symbolLookupBIF(argCount) + int argCount; +{ + symbolType *symbol; + stringType *symbolName; + symbolType *lookupGlobalSymbol(); + + if (argCount < 1) { + tooFewArgs(argCount, "symbolLookup"); + return(0); + } else if (argCount > 1) { + tooManyArgs(argCount, "symbolLookup"); + return(0); + } + symbol = lookupGlobalSymbol(symbolName = (stringType *) + evaluateExpression()); + if (symbol == NULL) { + error(SYMBOL_NOT_FOUND_IN_SYMBOL_LOOKUP_ERROR, symbolName); + return(0); + } else + return(symbol->symbolValue); +} + +/* Turn a symbol into a string */ + stringType * +symbolNameBIF(argCount) + int argCount; +{ + symbolType *symbol; + + if (argCount < 1) { + tooFewArgs(argCount, "symbolName"); + return(NULL); + } else if (argCount > 1) { + tooManyArgs(argCount, "symbolName"); + return(NULL); + } + if (*pc != IDENTIFIER_TAG) { + error(SYMBOL_NAME_ARG_IS_NOT_SYMBOL_ERROR); + skipExpression(); + return(""); + } + pc++; + symbol = getSymbol(); + return(symbol->symbolName); +} diff --git a/slinky/builtins.o b/slinky/builtins.o new file mode 100644 index 0000000..83ddc1f Binary files /dev/null and b/slinky/builtins.o differ diff --git a/slinky/debugPrint.c b/slinky/debugPrint.c new file mode 100644 index 0000000..2521861 --- /dev/null +++ b/slinky/debugPrint.c @@ -0,0 +1,124 @@ +/* + debugPrint.c -- Routines to dump stuff out in readable form for + debugging the Slinky linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 18-March-1985 + +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" + + +static char *modeStrings[2] = { + "abs", + "rel", + }; + +static char *kindStrings[3] = { + "byte", + "word", + "dbyt", + }; + +static char *pcrelStrings[2] = { + " ", + "pcrel", + }; + +static char *externalStrings[2] = { + " ", + "extern", + }; + +static char *symbolStrings[6] = { + "und ", /* 0x00 */ + "und ext", /* 0x01 */ + "abs ", /* 0x02 */ + "abs ext", /* 0x03 */ + "rel ", /* 0x04 */ + "rel ext", /* 0x05 */ + }; + + void +printCode(startAddress, endAddress, mode) + int startAddress; + int endAddress; + int mode; +{ + printf(" Code: 0x%04x:0x%04x %s\n", startAddress, endAddress, + modeStrings[mode]); +} + + void +printReference(reference) + expressionReferenceType *reference; +{ + printf(" Ref : 0x%04x (%s %s %s %s) expression #%d\n", reference-> + referenceAddress, modeStrings[reference->referenceMode], + pcrelStrings[reference->referenceRelative], externalStrings[ + reference->referenceExternal], kindStrings[reference-> + referenceKind], reference->referenceExpression.inFile); +} + + void +printReferenceFixup(reference) + expressionReferenceType *reference; +{ + printf(" Ref : 0x%04x (%s %s %s %s) expression=0x%x\n", + reference->referenceAddress, modeStrings[reference-> + referenceMode],pcrelStrings[reference->referenceRelative], + externalStrings[reference->referenceExternal], kindStrings[ + reference->referenceKind], reference->referenceExpression. + inCore); +} + + void +printSymbol(symbolTag, symbol) + int symbolTag; + symbolType *symbol; +{ + printf(" Symb: %3d %s 0x%04x \"%s\"\n", symbolTag, symbolStrings[ + symbol->symbolClass], symbol->symbolValue, + symbol->symbolName); +} + + void +printLoadMapSymbol(symbol) + symbolType *symbol; +{ + fprintf(mapFileOutput, "%-20s 0x%04x %s ", symbol->symbolName, + symbol->symbolValue, symbolStrings[symbol->symbolClass]); +} + + void +printGlobalSymbols() +{ + int symbolCount; + + printf("Globals:\n"); + printf(" %d global symbols\n", globalSymbolCount); + for (symbolCount=0; symbolCountsymbolName); + } +} + + void +printExpression(expression, length) + expressionPCType expression; + int length; +{ + int line; + int i; + + printf("expression length = %d:\n", length); + for (line=0; linesymbolValue = right; + return(right); + + case LOGICAL_OR: + return(left || right); + + case LOGICAL_XOR: + return((left && !right) || (!left && right)); + + case LOGICAL_AND: + return(left && right); + + case BITWISE_OR: + return(left | right); + + case BITWISE_XOR: + return(left ^ right); + + case BITWISE_AND: + return(left & right); + + case EQUAL_TO: + return(left == right); + + case NOT_EQUAL_TO: + return(left != right); + + case LESS_THAN: + return(left < right); + + case LESS_THAN_OR_EQUAL_TO: + return(left <= right); + + case GREATER_THAN: + return(left > right); + + case GREATER_THAN_OR_EQUAL_TO: + return(left >= right); + + case LEFT_SHIFT: + return(left << right); + + case RIGHT_SHIFT: + return(left >> right); + + case ADD: + return(left + right); + + case SUB: + return(left - right); + + case MUL: + return(left * right); + + case DIV: + return(left / right); + + case MOD: + return(left % right); + } +} + + addressType +evaluateBlock() +{ + while (*pc != END_TAG) { + evaluateExpression(); + if (hitFreturn) + while (*pc != END_TAG) + skipExpression(); + } + overByte(); + return(0); +} + + addressType +evaluateConditionCode() +{ + overByte(); + error(CONDITION_CODE_EXPRESSION_ENCOUNTERED_ERROR); + return(0); +} + + void +pushSymbol(symbol, value) + symbolType *symbol; + addressType value; +{ + bindingListType *newBinding; + + newBinding = typeAlloc(bindingListType); + newBinding->boundSymbol = symbol; + newBinding->previousClass = symbol->symbolClass; + symbol->symbolClass = SYMBOL_LOCAL; + newBinding->previousValue = symbol->symbolValue; + symbol->symbolValue = value; + newBinding->nextBinding = localBindings; + localBindings = newBinding; +} + + void +bindFunctionArguments(theFunction, argCount) + functionType *theFunction; + int argCount; +{ + argumentListType *argList; + + argList = theFunction->functionArguments; + while (argCount > 0) { + if (argList == NULL) { + error(TOO_MANY_FUNCTION_ARGUMENTS_ERROR); + while (argCount-- > 0) + skipExpression(); + } else { + pushSymbol(argList->argumentSymbol, + evaluateExpression()); + argList = argList->nextArgument; + argCount--; + } + } + while (argList != NULL) { + pushSymbol(argList->argumentSymbol, 0); + argList = argList->nextArgument; + } +} + + void +undoBindings() +{ + bindingListType *deadBinding; + + while (localBindings != NULL) { + localBindings->boundSymbol->symbolClass = localBindings-> + previousClass; + localBindings->boundSymbol->symbolValue = localBindings-> + previousValue; + deadBinding = localBindings; + localBindings = localBindings->nextBinding; + free(deadBinding); + } +} + + addressType +evaluateFreturn() +{ + hitFreturn = TRUE; + functionResult = evaluateExpression(); + return(0); +} + + addressType +evaluateBuiltinFunctionCall() +{ + int theFunction; + int argCount; + + theFunction = getNumber(); + nextByte(argCount); + if (theFunction<0 || MAX_FUNCTIONS<=theFunction) { + printf("illegal built-in function #%d\n", theFunction); + chokePukeAndDie(); + } + return((*builtInFunctionTable[theFunction].functionEntry)(argCount)); +} + + addressType +evaluateFunctionCall() +{ + expressionPCType savePoint; + functionType *theFunction; + int argCount; + bindingListType *saveBindings; + + theFunction = getFunction(); + nextByte(argCount); + saveBindings = localBindings; + localBindings = NULL; + bindFunctionArguments(theFunction, argCount); + savePoint = pc; + pc = theFunction->functionBody; + evaluateExpression(); + undoBindings(); + localBindings = saveBindings; + pc = savePoint; + if (hitFreturn) { + hitFreturn = FALSE; + return(functionResult); + } else + return(0); +} + + addressType +evaluateHere() +{ + return(here); +} + + addressType +evaluateMdefine() +{ + symbolType *symbol; + + symbol = getSymbol(); + pushSymbol(symbol, evaluateExpression); +} + + addressType +evaluateMdoUntil() +{ + expressionPCType testPoint; + expressionPCType endPoint; + + testPoint = pc; + skipExpression(); + do { + evaluateExpression; + endPoint = pc; + pc = testPoint; + } while (!evaluateExpression()); + pc = endPoint; + return(0); +} + + addressType +evaluateMdoWhile() +{ + expressionPCType testPoint; + expressionPCType endPoint; + + testPoint = pc; + skipExpression(); + do { + evaluateExpression; + endPoint = pc; + pc = testPoint; + } while (evaluateExpression()); + pc = endPoint; + return(0); +} + + addressType +evaluateMfor() +{ + expressionPCType testPoint; + expressionPCType incrPoint; + expressionPCType endPoint; + expressionPCType bodyPoint; + + evaluateExpression(); + testPoint = pc; + if (evaluateExpression()) { + incrPoint = pc; + skipExpression(); + bodyPoint = pc; + do { + pc = bodyPoint; + evaluateExpression(); + endPoint = pc; + pc = incrPoint; + evaluateExpression(); + pc = testPoint; + } while (evaluateExpression()); + pc = endPoint; + } else { + skipExpression(); + skipExpression(); + } + return(0); +} + + addressType +evaluateMif() +{ + if (evaluateExpression()) { + evaluateExpression(); + skipExpression(); + } else { + skipExpression(); + evaluateExpression(); + } + return(0); +} + + bool +evaluateClause(pattern) + addressType pattern; +{ + bool match; + + match = FALSE; + while (*pc != BLOCK_TAG) + if (match) + skipExpression(); + else + match = (evaluateExpression() == pattern); + if (match) + evaluateExpression(); + else + skipExpression(); + return(match); +} + + addressType +evaluateMswitch() +{ + addressType pattern; + + pattern = evaluateExpression(); + while (*pc != END_TAG) + if (evaluateClause(pattern)) + break; + while (*pc != END_TAG) + skipClause(); + overByte(); + return(0); +} + + addressType +evaluateMwhile() +{ + expressionPCType testPoint; + expressionPCType endPoint; + + testPoint = pc; + if (evaluateExpression()) { + do { + evaluateExpression(); + endPoint = pc; + pc = testPoint; + } while (evaluateExpression()); + pc = endPoint; + } else { + skipExpression(); + } +} + + addressType +evaluateMvariable() +{ + symbolType *symbol; + + symbol = getSymbol(); + pushSymbol(symbol, evaluateExpression); +} + + addressType +evaluateNumber() +{ + addressType result; + int i; + int shift; + + result = 0; + for (i=0, shift=0; isymbolValue++); + + case DECREMENT: + return(target->symbolValue--); + } +} + + addressType +evaluatePreop() +{ + int op; + symbolType *target; + + nextByte(op); + target = getSymbol(); + switch (intOp(op)) { + case INCREMENT: + return(++target->symbolValue); + + case DECREMENT: + return(--target->symbolValue); + } +} + + addressType +evaluateString() +{ + addressType result; + + result = (addressType) pc; + while (*pc++ != '\0') + ; + return(result); +} + + addressType +evaluateSymbol() +{ + symbolType *target; + + target = getSymbol(); + return(target->symbolValue); +} + + addressType +evaluateUnop() +{ + int op; + addressType arg; + + nextByte(op); + arg = evaluateExpression(); + switch(intOp(op)) { + case UNARY_MINUS: + return(-arg); + + case LOGICAL_NOT: + return(!arg); + + case BITWISE_NOT: + return(~arg); + + case HI_BYTE: + return((arg & 0xFF00) >> 8); + + case LO_BYTE: + return(arg & 0xFF); + } +} + + addressType +evaluateExpression() +{ + if (pc == NULL) + return(0); + switch (*pc++) { + case IDENTIFIER_TAG: + return(evaluateSymbol()); + + case FUNCTION_CALL_TAG: + return(evaluateFunctionCall()); + + case BUILTIN_FUNCTION_CALL_TAG: + return(evaluateBuiltinFunctionCall()); + + case NUMBER_TAG: + return(evaluateNumber()); + + case RELOCATABLE_TAG: + return(evaluateRelocatableNumber()); + + case CONDITION_CODE_TAG: + return(evaluateConditionCode()); + + case SUBEXPRESSION_TAG: + return(evaluateExpression()); + + case UNOP_TAG: + return(evaluateUnop()); + + case BINOP_TAG: + return(evaluateBinop()); + + case PREOP_TAG: + return(evaluatePreop()); + + case POSTOP_TAG: + return(evaluatePostop()); + + case HERE_TAG: + return(evaluateHere()); + + case STRING_TAG: + return(evaluateString()); + + case ARRAY_TAG: + return(evaluateArray()); + + case VALUE_TAG: + return(evaluateNumber()); + + case NULL_TAG: + return(0); + + case BLOCK_TAG: + return(evaluateBlock()); + + case MDEFINE_TAG: + return(evaluateMdefine()); + + case MVARIABLE_TAG: + return(evaluateMvariable()); + + case MIF_TAG: + return(evaluateMif()); + + case MFOR_TAG: + return(evaluateMfor()); + + case MWHILE_TAG: + return(evaluateMwhile()); + + case MDOWHILE_TAG: + return(evaluateMdoWhile()); + + case MDOUNTIL_TAG: + return(evaluateMdoUntil()); + + case PERFORM_TAG: + return(evaluatePerform()); + + case GROUP_TAG: + return(evaluateBlock()); + + case ASSERT_TAG: + return(evaluateAssert()); + + case MSWITCH_TAG: + return(evaluateMswitch()); + + case CLAUSE_TAG: + error(CLAUSE_AT_TOP_LEVEL_ERROR); + chokePukeAndDie(); + + case FRETURN_TAG: + return(evaluateFreturn()); + + case END_TAG: + return(0); + } +} + + void +skipArray() +{ + overSymbol(); + skipExpression(); +} + + void +skipAssert() +{ + skipExpression(); + skipString(); +} + + void +skipBinop() +{ + overByte(); + skipExpression(); + skipExpression(); +} + + void +skipBlock() +{ + while (*pc != END_TAG) + skipExpression(); + overByte(); +} + + void +skipFunctionCall() +{ + int argCount; + + overFunction(); + nextByte(argCount); + while (argCount-- > 0) + skipExpression(); +} + + void +skipMdefine() +{ + overSymbol(); + skipExpression(); +} + + void +skipMdoUntil() +{ + skipExpression(); + skipExpression(); +} + + void +skipMdoWhile() +{ + skipExpression(); + skipExpression(); +} + + void +skipMfor() +{ + skipExpression(); + skipExpression(); + skipExpression(); + skipExpression(); +} + + void +skipMif() +{ + skipExpression(); + skipExpression(); + skipExpression(); +} + + void +skipClause() +{ + while (*pc != BLOCK_TAG) + skipExpression; + skipBlock(); +} + + void +skipMswitch() +{ + skipExpression(); + while (*pc != END_TAG) + skipClause(); + overByte(); +} + + void +skipMvariable() +{ + overSymbol(); + skipExpression(); +} + + void +skipMwhile() +{ + skipExpression(); + skipExpression(); +} + + void +skipPostop() +{ + overByte(); + skipExpression(); +} + + void +skipPreop() +{ + overByte(); + skipExpression(); +} + + void +skipString() +{ + while (*pc++ != '\0') + ; +} + + void +skipUnop() +{ + overByte(); + skipExpression(); +} + + void +skipExpression() +{ + if (pc == NULL) + return; + switch (*pc++) { + case IDENTIFIER_TAG: + overSymbol(); + break; + + case FUNCTION_CALL_TAG: + skipFunctionCall(); + break; + + case NUMBER_TAG: + case RELOCATABLE_TAG: + overNumber(); + break; + + case CONDITION_CODE_TAG: + overByte(); + break; + + case SUBEXPRESSION_TAG: + skipExpression(); + break; + + case UNOP_TAG: + skipUnop(); + break; + + case BINOP_TAG: + skipBinop(); + break; + + case PREOP_TAG: + skipPreop(); + break; + + case POSTOP_TAG: + skipPostop(); + break; + + case HERE_TAG: + break; + + case STRING_TAG: + skipString(); + break; + + case ARRAY_TAG: + skipArray(); + break; + + case VALUE_TAG: + overNumber(); + break; + + case NULL_TAG: + break; + + case BLOCK_TAG: + skipBlock(); + break; + + case MDEFINE_TAG: + skipMdefine(); + break; + + case MVARIABLE_TAG: + skipMvariable(); + break; + + case MIF_TAG: + skipMif(); + break; + + case MFOR_TAG: + skipMfor(); + break; + + case MWHILE_TAG: + skipMwhile(); + break; + + case MDOWHILE_TAG: + skipMdoWhile(); + break; + + case MDOUNTIL_TAG: + skipMdoUntil(); + break; + + case PERFORM_TAG: + skipExpression(); + break; + + case GROUP_TAG: + skipBlock(); + break; + + case ASSERT_TAG: + skipAssert(); + break; + + case MSWITCH_TAG: + skipMswitch(); + break; + + case CLAUSE_TAG: + skipClause(); + break; + + case END_TAG: + break; + } +} diff --git a/slinky/expr.o b/slinky/expr.o new file mode 100644 index 0000000..9beb066 Binary files /dev/null and b/slinky/expr.o differ diff --git a/slinky/initialize.c b/slinky/initialize.c new file mode 100644 index 0000000..c8c9825 --- /dev/null +++ b/slinky/initialize.c @@ -0,0 +1,198 @@ +/* + initialize.c -- Program initialization for the Slinky linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 9-March-1985 +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" + +static char *outputFileName; + + void +chokePukeAndDie() +{ + unlink(outputFileName); + exit(1); +} + + void +initializeStuff(argc, argv) + int argc; + char *argv[]; +{ + int i; + int j; + char **args; + char *arg; + int outputFilesFound; + int mapFilesFound; + char *mapFileName; + + void queueInputFile(); + void queueLoadAddress(); + + currentFileName = ""; + errorFlag = FALSE; + packFlag = FALSE; + debug = FALSE; + verbose = FALSE; + objectFileList = endOfObjectFileList = NULL; + reservationList = NULL; + haveEntryPoint = FALSE; + readExpressionEntryPoint = FALSE; + haveExpressionEntryPoint = FALSE; + globalSymbolCount = 0; + produceLoadMap = FALSE; + leaveOffLoadFiles = FALSE; + + for (i=0; isegmentStartAddress = FIRST_AVAILABLE_LOCATION; + freeSegmentList->segmentEndAddress = LAST_AVAILABLE_LOCATION; + freeSegmentList->nextFreeSegment = NULL; + + outputFilesFound = 0; + outputFileName = DEFAULT_LOAD_FILE_NAME; + mapFilesFound = 0; + mapFileName = NULL; + + args = argv + 1; + for (i=1; i= argc) { + error(NO_LOAD_ADDRESS_ERROR); + chokePukeAndDie(); + } else { + queueLoadAddress(*args++); + } + continue; + + case 'm': + if (++i >= argc) { + error(NO_MAP_FILE_NAME_ERROR); + chokePukeAndDie(); + } else { + mapFileName = *args++; + mapFilesFound++; + } + produceLoadMap = TRUE; + continue; + + case 'n': + leaveOffLoadFiles = TRUE; + continue; + + case 'o': + if (++i >= argc) { + error(NO_DASH_O_FILE_NAME_ERROR); + chokePukeAndDie(); + } else { + outputFileName = *args++; + outputFilesFound++; + } + continue; + + case 'p': + packFlag = TRUE; + continue; + + case 'v': + printVersion(); + continue; + + default: + error(BAD_COMMAND_LINE_FLAG_ERROR, arg[j]); + continue; + } + } + + if (outputFilesFound > 1) { + error(MORE_THAN_ONE_OUTPUT_FILE_ERROR); + chokePukeAndDie(); + } else if ((loadFileOutput = fopen(outputFileName, "w"))==NULL) { + error(CANT_OPEN_LOAD_FILE_ERROR, outputFileName); + perror("Unix says"); + chokePukeAndDie(); + } + + if (mapFilesFound > 1) { + error(MORE_THAN_ONE_MAP_FILE_ERROR); + chokePukeAndDie(); + } else if (mapFilesFound == 1) { + if (strcmp(mapFileName, "-") == 0) { + mapFileOutput = stdout; + } else if ((mapFileOutput = fopen(mapFileName, "w")) == NULL){ + error(CANT_OPEN_MAP_FILE_ERROR, mapFileName); + perror("Unix says"); + chokePukeAndDie(); + } + } + currentFileName = outputFileName; +} + + + void +queueInputFile(name) + char *name; +{ + objectFileListType *newObjectFile; + + newObjectFile = typeAlloc(objectFileListType); + newObjectFile->name = name; + newObjectFile->symbolTable = NULL; + newObjectFile->codeSegments = NULL; + newObjectFile->lastCodeSegment = NULL; + newObjectFile->nextObjectFile = NULL; + if (objectFileList == NULL) { + objectFileList = endOfObjectFileList = newObjectFile; + } else { + endOfObjectFileList->nextObjectFile = newObjectFile; + endOfObjectFileList = newObjectFile; + } +} + + void +queueLoadAddress(addressString) + char *addressString; +{ + int loadAddress; + objectFileListType *newObjectFile; + + if (sscanf(addressString, "0x%x", &loadAddress) != 1) { + if (sscanf(addressString, "0X%x", &loadAddress) != 1) { + if (sscanf(addressString, "%x", &loadAddress) != 1) { + error(BAD_LOAD_ADDRESS_ERROR, addressString); + chokePukeAndDie(); + }}} + newObjectFile = typeAlloc(objectFileListType); + newObjectFile->name = NULL;/* NULL name encodes load address change */ + newObjectFile->symbolCount = loadAddress; /* then address goes here */ + newObjectFile->nextObjectFile = NULL; + if (objectFileList == NULL) { + objectFileList = endOfObjectFileList = newObjectFile; + } else { + endOfObjectFileList->nextObjectFile = newObjectFile; + endOfObjectFileList = newObjectFile; + } +} diff --git a/slinky/initialize.o b/slinky/initialize.o new file mode 100644 index 0000000..e3cd73e Binary files /dev/null and b/slinky/initialize.o differ diff --git a/slinky/instantiate.c b/slinky/instantiate.c new file mode 100644 index 0000000..eb41b49 --- /dev/null +++ b/slinky/instantiate.c @@ -0,0 +1,317 @@ +/* + instantiate.c -- Slinky linker routines to walk expression tree and + replace symbol ordinals with symbol pointers. + + Chip Morningstar -- Lucasfilm Ltd. + + 11-November-1985 +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" +#include "slinkyExpressions.h" +#include "y.tab.h" + +#define overFunction() (pc+=sizeof(functionType *)) +#define overNumber() (pc+=sizeof(addressType)) +#define overByte() pc++ +#define nextByte(byt) (byt = *pc++) + +void putSymbolPointersIntoArray(); +void putSymbolPointersIntoClause(); +void putSymbolPointersIntoExpression(); + + void +putNumber(number) + int number; +{ + int i; + for (i=0; i>= 8; + } +} + + void +instantiateSymbol() +{ + int index; + + index = evaluateNumber(); + pc -= sizeof(symbolType *); + putNumber(currentSymbolTable[index]); +} + + void +instantiateFunction() +{ + int index; + + index = evaluateNumber(); + pc -= sizeof(functionType *); + putNumber(&(currentFunctionTable[index])); +} + + void +putSymbolPointersIntoArray() +{ + instantiateSymbol(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoAssert() +{ + putSymbolPointersIntoExpression(); + skipString(); +} + + void +putSymbolPointersIntoBinop() +{ + overByte(); + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoBlock() +{ + while (*pc != END_TAG) + putSymbolPointersIntoExpression(); + overByte(); +} + + void +putSymbolPointersIntoBuiltinFunctionCall() +{ + int argCount; + + overNumber(); + nextByte(argCount); + while (argCount-- > 0) + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoFunctionCall() +{ + int argCount; + + instantiateFunction(); + nextByte(argCount); + while (argCount-- > 0) + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoMdefine() +{ + instantiateSymbol(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoMdoUntil() +{ + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoMdoWhile() +{ + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoMfor() +{ + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoMif() +{ + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoClause() +{ + while (*pc != BLOCK_TAG) + putSymbolPointersIntoExpression(); + putSymbolPointersIntoBlock(); +} + + void +putSymbolPointersIntoMswitch() +{ + putSymbolPointersIntoExpression(); + while (*pc != END_TAG) + putSymbolPointersIntoClause(); + overByte(); +} + + void +putSymbolPointersIntoMvariable() +{ + instantiateSymbol(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoMwhile() +{ + putSymbolPointersIntoExpression(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoPostop() +{ + overByte(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoPreop() +{ + overByte(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoUnop() +{ + overByte(); + putSymbolPointersIntoExpression(); +} + + void +putSymbolPointersIntoExpression() +{ + if (pc == NULL) + return; + switch (*pc++) { + case IDENTIFIER_TAG: + instantiateSymbol(); + break; + + case FUNCTION_CALL_TAG: + putSymbolPointersIntoFunctionCall(); + break; + + case BUILTIN_FUNCTION_CALL_TAG: + putSymbolPointersIntoBuiltinFunctionCall(); + break; + + case NUMBER_TAG: + case RELOCATABLE_TAG: + overNumber(); + break; + + case CONDITION_CODE_TAG: + overByte(); + break; + + case SUBEXPRESSION_TAG: + putSymbolPointersIntoExpression(); + break; + + case UNOP_TAG: + putSymbolPointersIntoUnop(); + break; + + case BINOP_TAG: + putSymbolPointersIntoBinop(); + break; + + case PREOP_TAG: + putSymbolPointersIntoPreop(); + break; + + case POSTOP_TAG: + putSymbolPointersIntoPostop(); + break; + + case HERE_TAG: + break; + + case STRING_TAG: + skipString(); + break; + + case ARRAY_TAG: + putSymbolPointersIntoArray(); + break; + + case VALUE_TAG: + overNumber(); + break; + + case NULL_TAG: + break; + + case BLOCK_TAG: + putSymbolPointersIntoBlock(); + break; + + case MDEFINE_TAG: + putSymbolPointersIntoMdefine(); + break; + + case MVARIABLE_TAG: + putSymbolPointersIntoMvariable(); + break; + + case MIF_TAG: + putSymbolPointersIntoMif(); + break; + + case MFOR_TAG: + putSymbolPointersIntoMfor(); + break; + + case MWHILE_TAG: + putSymbolPointersIntoMwhile(); + break; + + case MDOWHILE_TAG: + putSymbolPointersIntoMdoWhile(); + break; + + case MDOUNTIL_TAG: + putSymbolPointersIntoMdoUntil(); + break; + + case PERFORM_TAG: + putSymbolPointersIntoExpression(); + break; + + case GROUP_TAG: + putSymbolPointersIntoBlock(); + break; + + case ASSERT_TAG: + putSymbolPointersIntoAssert(); + break; + + case MSWITCH_TAG: + putSymbolPointersIntoMswitch(); + break; + + case CLAUSE_TAG: + putSymbolPointersIntoClause(); + break; + + case END_TAG: + break; + } +} diff --git a/slinky/instantiate.o b/slinky/instantiate.o new file mode 100644 index 0000000..b4ff97b Binary files /dev/null and b/slinky/instantiate.o differ diff --git a/slinky/link.c b/slinky/link.c new file mode 100644 index 0000000..acad612 --- /dev/null +++ b/slinky/link.c @@ -0,0 +1,442 @@ +/* + link.c -- Primary routines for the Slinky linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 9-March-1985 +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" +/*#define readWord(f,fn) ((getc(f) & 0xFF) | ((getc(f) & 0xFF)<<8))*/ + +/* + 'internalizeOneObjectFile' does just that: it reads an object file into + the master data structure. The object file format is: + + 0xFFFF -- A "magic number" to signal the + start of an object file. + ABSOLUTE code segments -- In the form of a 2-byte start + address, followed by a 2-byte end + address, followed by the requisite + number of code bytes. + 0xFFFF -- A partition. + RELOCATABLE code segments -- In the same format as the ABSOLUTE + code segments. + 0xFFFF -- Another partition. + space reservation blocks -- each in the form of a 2-byte start + address followed by a 2-byte + length. + 0xFFFF -- Yet another partition. + number of reference items -- A 4-byte count. + that many reference items -- Each a 'referenceType' in binary + form. + number of symbol entries -- A 4-byte count. + number of bytes of strings -- A 4-byte count of the sum total of + string space used by all of the + following symbol entries. + that many symbol entries -- Each a 'symbolType' in binary form + followed by a string with the + symbol name. +**new** + number of expression entries -- A 4-byte count. + that many expression entries -- Each a 4-byte length indicator + followed by the indicated number of + bytes representing a compacted + parse tree of an expression. + number of function entries -- A 4-byte count. + that many function entries -- Each a 1 byte argument count, + followed by that many symbol + numbers, followed by a compacted + parse tree of the function body + itself represented in the same + manner as expressions (i.e., + length + bytes). +**end of new stuff** + end-of-file + + Potential gotchas: + + 1) A length 1 code segment signals the program entry point and is not + really code (i.e., start address==end address==entry point). + + 2) A length 0 code segment encodes a constraint instruction. The 2-byte + word following gives the multiple to constrain by. + + 3) A length -1 code segment encodes an aligment instruction. The 2-byte + word following gives the multiple to align to. + + 4) It is assumed that Macross will output all code segments of a given mode + in strictly ascending order of start address. + + + */ + + bool +internalizeOneObjectFile(objectFile) + objectFileListType *objectFile; +{ + FILE *objectFildes; + int magic; + int mode; + addressType startAddress; + addressType endAddress; + bool compareSymbolValues(); + + currentFileName = objectFile->name; + if ((objectFildes = fopen(objectFile->name, "r")) == NULL) { + error(CANT_OPEN_OBJECT_FILE_ERROR, objectFile->name); + perror("Unix says"); + return(FALSE); + } + if (verbose) + printf("internalizing %s:\n", objectFile->name); + if ((magic = readWord(objectFildes, objectFile->name)) != 0xFFFF) { + error(BAD_OBJECT_FILE_ERROR, objectFile->name); + return(FALSE); + } + mode = MODE_ABSOLUTE; + for (;;) { + startAddress = readWord(objectFildes, objectFile->name); + if (startAddress == 0xFFFF) { + if (mode == MODE_ABSOLUTE) { + mode = MODE_RELOCATABLE; + continue; + } else { + break; + } + } + endAddress = readWord(objectFildes, objectFile->name); + readCode(startAddress, endAddress, mode, objectFile, + objectFildes); + } + readReservations(objectFile, objectFildes); + readReferences(objectFile, objectFildes); + readSymbols(objectFile, objectFildes); + readExpressions(objectFile, objectFildes); + readFunctions(objectFile, objectFildes); + instantiateExpressionAndSymbolPointers(objectFile); + if (readExpressionEntryPoint) { + pc = entryPointExpression; + putSymbolPointersIntoExpression(); + readExpressionEntryPoint = FALSE; + haveExpressionEntryPoint = TRUE; + } + qsort(objectFile->symbolTable, objectFile->symbolCount, + sizeof(symbolType *), compareSymbolValues); + fclose(objectFildes); + return(TRUE); +} + +#define toLowerCase(c) (('A'<=(c)&&(c)<='Z')?((c)-'A'+'a'):(c)); + + bool +strcmplc(s1, s2) + char *s1; + char *s2; +{ + register char c1; + register char c2; + int result; + + do { + c1 = *s1++; + c1 = toLowerCase(c1); + c2 = *s2++; + c2 = toLowerCase(c2); + + /* if result != 0, they differ */ + if (result = c1 - c2) { + return(result); /* c1c2==pos */ + } else if (!c1) { /* if they're null, we're done */ + return(0); + } + } while (TRUE); +} + + bool +compareSymbols(symbol1, symbol2) + symbolType **symbol1; + symbolType **symbol2; +{ + bool result; + + result = strcmplc((*symbol1)->symbolName, (*symbol2)->symbolName); + if (result == 0 && (((*symbol1)->symbolClass & ~SYMBOL_EXTERNAL) && + ((*symbol2)->symbolClass & ~SYMBOL_EXTERNAL))) { + error(MULTIPLY_DEFINED_SYMBOL_ERROR, (*symbol1)->symbolName); + (*symbol2)->symbolClass &= ~SYMBOL_ABSOLUTE; + (*symbol2)->symbolClass &= ~SYMBOL_RELOCATABLE; + } + return(result); +} + + void +buildGlobalSymbolTable(inputFileList) + objectFileListType *inputFileList; +{ + int symbolCount; + symbolType **symbol; + symbolType **globalSymbolPtr; + + globalSymbolTable = typeAllocBlock(symbolType *, globalSymbolCount); + globalSymbolPtr = globalSymbolTable; + for (; inputFileList != NULL; inputFileList = inputFileList-> + nextObjectFile) { + if (inputFileList->name != NULL) { + for (symbol = inputFileList->symbolTable, + symbolCount = inputFileList-> + symbolCount; symbolCount>0; symbol++, + symbolCount--) { + if (((*symbol)->symbolClass & + SYMBOL_EXTERNAL) && + ((*symbol)->symbolClass & + ~SYMBOL_EXTERNAL)) { + *globalSymbolPtr++ = (*symbol); + } + } + } + } + qsort(globalSymbolTable, globalSymbolCount, sizeof(symbolType *), + compareSymbols); + if (debug) { + printGlobalSymbols(); + } +} + + bool +readem() +{ + objectFileListType *inputFileList; + + if (objectFileList == NULL) { + error(NO_INPUT_FILES_ERROR); + return(FALSE); + } + inputFileList = objectFileList; + while (inputFileList != NULL) { + if (inputFileList->name != NULL) + if (!internalizeOneObjectFile(inputFileList)) + return(FALSE); + inputFileList = inputFileList->nextObjectFile; + } + buildGlobalSymbolTable(objectFileList); + return(TRUE); +} + + codeSegmentHeaderType * +locateConflictingSegment(codeSegment) + codeSegmentHeaderType *codeSegment; +{ + segmentListType *segmentPtr; + int segmentListOffset; + int segmentListOffsetStart; + int segmentListOffsetEnd; + addressType start; + addressType end; + + start = codeSegment->segmentStartAddress; + end = codeSegment->segmentEndAddress; +/* segmentListOffsetStart = (start / CODE_REGION_SIZE) - 1; + segmentListOffsetEnd = segmentListOffsetStart + 2; + if (segmentListOffsetStart < 0)*/ + segmentListOffsetStart = 0; +/* if (segmentListOffsetEnd >= CODE_REGIONS_IN_ADDRESS_SPACE)*/ + segmentListOffsetEnd = CODE_REGIONS_IN_ADDRESS_SPACE - 1; + for (segmentListOffset = segmentListOffsetStart; + segmentListOffset <= segmentListOffsetEnd; + segmentListOffset++) { + segmentPtr = generatedLoadImage[segmentListOffset]; + while (segmentPtr != NULL) { + if ((segmentPtr->thisSegment->segmentStartAddress<=start && + start<=segmentPtr->thisSegment->segmentEndAddress) || + (segmentPtr->thisSegment->segmentStartAddress<=end && + end<=segmentPtr->thisSegment->segmentEndAddress)) + return(segmentPtr->thisSegment); + else + segmentPtr = segmentPtr->nextSegment; + } + } + printf("Hey! segment list overrun in locateConflictingSegment\n"); + return(NULL); +} + + void +reserveSegment(start, end) + addressType start; + addressType end; +{ + freeSegmentEntryType *freeSegmentPtr; + freeSegmentEntryType *previousSegmentPtr; + freeSegmentEntryType *newSegmentPtr; + + previousSegmentPtr = NULL; + freeSegmentPtr = freeSegmentList; + while (freeSegmentPtr != NULL && start > freeSegmentPtr-> + segmentEndAddress) { + previousSegmentPtr = freeSegmentPtr; + freeSegmentPtr = freeSegmentPtr->nextFreeSegment; + } + if (end < freeSegmentPtr->segmentStartAddress) { + /* return; */ + } else if (start <= freeSegmentPtr->segmentStartAddress && end < + freeSegmentPtr->segmentEndAddress) { + freeSegmentPtr->segmentStartAddress = end + 1; + } else if (end >= freeSegmentPtr->segmentEndAddress) { + if (start > freeSegmentPtr->segmentStartAddress) + freeSegmentPtr->segmentEndAddress = start - 1; + if (previousSegmentPtr == NULL) { + while (end >= freeSegmentPtr->segmentEndAddress) { + freeSegmentList = freeSegmentPtr-> + nextFreeSegment; + free(freeSegmentPtr); + freeSegmentPtr = freeSegmentList; + } + } else { + while (end >= freeSegmentPtr->segmentEndAddress) { + previousSegmentPtr->nextFreeSegment = + freeSegmentPtr->nextFreeSegment; + free(freeSegmentPtr); + freeSegmentPtr = previousSegmentPtr-> + nextFreeSegment; + } + } + if (end >= freeSegmentPtr->segmentStartAddress) { + freeSegmentPtr->segmentStartAddress = end + 1; + } + } else { + newSegmentPtr = typeAlloc(freeSegmentEntryType); + newSegmentPtr->nextFreeSegment = freeSegmentPtr-> + nextFreeSegment; + freeSegmentPtr->nextFreeSegment = newSegmentPtr; + newSegmentPtr->segmentEndAddress = freeSegmentPtr-> + segmentEndAddress; + freeSegmentPtr->segmentEndAddress = start - 1; + newSegmentPtr->segmentStartAddress = end + 1; + } +} + + codeSegmentHeaderType * +allocateAbsolute(codeSegment) + codeSegmentHeaderType *codeSegment; +{ + freeSegmentEntryType *freeSegmentPtr; + freeSegmentEntryType *previousSegmentPtr; + freeSegmentEntryType *newSegmentPtr; + addressType start; + addressType end; + + previousSegmentPtr = NULL; + freeSegmentPtr = freeSegmentList; + start = codeSegment->segmentStartAddress; + end = codeSegment->segmentEndAddress; + while (freeSegmentPtr != NULL && start > freeSegmentPtr-> + segmentEndAddress) { + previousSegmentPtr = freeSegmentPtr; + freeSegmentPtr = freeSegmentPtr->nextFreeSegment; + } + if (freeSegmentPtr->segmentEndAddress < end || start + segmentStartAddress) + return(locateConflictingSegment(codeSegment)); + if (freeSegmentPtr->segmentStartAddress == start || freeSegmentPtr-> + segmentEndAddress == end) { + if (freeSegmentPtr->segmentStartAddress == start) + freeSegmentPtr->segmentStartAddress = end + 1; + if (freeSegmentPtr->segmentEndAddress == end) + freeSegmentPtr->segmentEndAddress = start - 1; + if (freeSegmentPtr->segmentEndAddress < freeSegmentPtr-> + segmentStartAddress) { + if (previousSegmentPtr == NULL) + freeSegmentList = freeSegmentPtr-> + nextFreeSegment; + else + previousSegmentPtr->nextFreeSegment = + freeSegmentPtr->nextFreeSegment; + free(freeSegmentPtr); + } + } else { + newSegmentPtr = typeAlloc(freeSegmentEntryType); + newSegmentPtr->nextFreeSegment = freeSegmentPtr-> + nextFreeSegment; + freeSegmentPtr->nextFreeSegment = newSegmentPtr; + newSegmentPtr->segmentEndAddress = freeSegmentPtr-> + segmentEndAddress; + freeSegmentPtr->segmentEndAddress = start - 1; + newSegmentPtr->segmentStartAddress = end + 1; + } + return(NULL); +} + + void +reserveReservations() +{ + while (reservationList != NULL) { + reserveSegment(reservationList->startAddress, + reservationList->startAddress + reservationList-> + blockSize - 1); + reservationList = reservationList->nextReservation; + } +} + + void +installSegment(codeSegment) + codeSegmentHeaderType *codeSegment; +{ + segmentListType *previousSegment; + segmentListType *installSegmentList; + segmentListType *newSegmentListEntry; + int regionNumber; + int endRegion; + + regionNumber = regionOf(codeSegment->segmentStartAddress); + previousSegment = NULL; + installSegmentList = generatedLoadImage[regionNumber]; + while (installSegmentList != NULL && installSegmentList->thisSegment-> + segmentStartAddress < codeSegment->segmentStartAddress) { + previousSegment = installSegmentList; + installSegmentList = installSegmentList->nextSegment; + } + newSegmentListEntry = typeAlloc(segmentListType); + newSegmentListEntry->thisSegment = codeSegment; + newSegmentListEntry->nextSegment = installSegmentList; + if (previousSegment == NULL) { + generatedLoadImage[regionNumber] = newSegmentListEntry; + } else { + previousSegment->nextSegment = newSegmentListEntry; + } + if (regionNumber < (endRegion=regionOf(codeSegment->segmentEndAddress))) { + for (regionNumber++; regionNumber <= endRegion; regionNumber++) { + newSegmentListEntry = typeAlloc(segmentListType); + newSegmentListEntry->thisSegment = codeSegment; + newSegmentListEntry->nextSegment=generatedLoadImage[regionNumber]; + generatedLoadImage[regionNumber] = newSegmentListEntry; + } + } +} + + void +installAbsoluteCodeSegment(codeSegment) + codeSegmentHeaderType *codeSegment; +{ + codeSegmentHeaderType *conflictingSegment; + + if ((conflictingSegment = allocateAbsolute(codeSegment)) != NULL) { + error(OVERLAPPING_ABSOLUTE_CODE_SEGMENTS_ERROR, conflictingSegment-> + fileName, conflictingSegment->segmentStartAddress, + conflictingSegment->segmentEndAddress, codeSegment->fileName, + codeSegment->segmentStartAddress, codeSegment->segmentEndAddress); + } else { + installSegment(codeSegment); + } +} + + void +linkem() +{ + if (!readem()) + return; + relocatem(); + valuem(); + pokem(); + writem(); +} diff --git a/slinky/link.o b/slinky/link.o new file mode 100644 index 0000000..7c8a07e Binary files /dev/null and b/slinky/link.o differ diff --git a/slinky/main.c b/slinky/main.c new file mode 100644 index 0000000..479be17 --- /dev/null +++ b/slinky/main.c @@ -0,0 +1,28 @@ +/* + main.c -- Top level of the Slinky linker + + Chip Morningstar -- Lucasfilm Ltd. + + 9-March-1985 +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" + +main(argc, argv) + int argc; + char *argv[]; +{ + initializeStuff(argc, argv); + linkem(); + if (errorFlag) + chokePukeAndDie(); + else + exit(0); +} + + void +printVersion() +{ + printf("Slinky version 1.16.\n"); +} diff --git a/slinky/main.o b/slinky/main.o new file mode 100644 index 0000000..4302096 Binary files /dev/null and b/slinky/main.o differ diff --git a/slinky/map.c b/slinky/map.c new file mode 100644 index 0000000..8a0baa7 --- /dev/null +++ b/slinky/map.c @@ -0,0 +1,82 @@ +/* + map.c -- Routines to print out load map for the Slinky linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 26-March-1985 + +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" + +typedef struct { + symbolType *symbol; + stringType *fileName; + } loadMapTableEntryType; + + int +compareLoadMapEntries(entry1, entry2) + loadMapTableEntryType *entry1; + loadMapTableEntryType *entry2; +{ + int result; + + if ((result = strcmplc(entry1->symbol->symbolName, entry2-> + symbol->symbolName)) != 0) + return(result); + else if (entry1->symbol->symbolValue < entry2->symbol->symbolValue) + return(-1); + else if (entry1->symbol->symbolValue > entry2->symbol->symbolValue) + return(1); + else + return(strcmplc(entry1->fileName, entry2->fileName)); +} + + void +outputLoadMap() +{ + loadMapTableEntryType *loadMapTable; + loadMapTableEntryType *loadMapPtr; + objectFileListType *inputFileList; + int symbolCount; + int i; + + loadMapPtr = loadMapTable = typeAllocBlock(loadMapTableEntryType, + totalSymbolCount); + for (inputFileList = objectFileList; inputFileList != NULL; + inputFileList = inputFileList->nextObjectFile) { + if (inputFileList->name != NULL) { + for (symbolCount=0; symbolCount < inputFileList->symbolCount; + symbolCount++) { + loadMapPtr->symbol = inputFileList->symbolTable[ + symbolCount]; + loadMapPtr->fileName = inputFileList->name; + loadMapPtr++; + } + } + } + qsort(loadMapTable, totalSymbolCount, sizeof(loadMapTableEntryType), + compareLoadMapEntries); + loadMapPtr = loadMapTable; + for (i=0; isymbol->symbolName, + (loadMapPtr-1)->symbol->symbolName)==0 && + loadMapPtr->symbol->symbolValue==(loadMapPtr- + 1)->symbol->symbolValue && loadMapPtr-> + symbol->symbolClass==(loadMapPtr-1)->symbol-> + symbolClass) { + if (!leaveOffLoadFiles) + fprintf(mapFileOutput, ", %s", loadMapPtr-> + fileName); + } else { + fprintf(mapFileOutput, "\n"); + printLoadMapSymbol(loadMapPtr->symbol); + if (!leaveOffLoadFiles) + fprintf(mapFileOutput, " %s", loadMapPtr-> + fileName); + } + loadMapPtr++; + } + fprintf(mapFileOutput, "\n"); +} diff --git a/slinky/map.o b/slinky/map.o new file mode 100644 index 0000000..57eea56 Binary files /dev/null and b/slinky/map.o differ diff --git a/slinky/opt/.mark b/slinky/opt/.mark new file mode 100644 index 0000000..3ee320f --- /dev/null +++ b/slinky/opt/.mark @@ -0,0 +1 @@ +Fri Jun 6 14:51:46 PDT 1986 diff --git a/slinky/opt/Makefile b/slinky/opt/Makefile new file mode 100644 index 0000000..3ec6fb7 --- /dev/null +++ b/slinky/opt/Makefile @@ -0,0 +1,77 @@ +.SUFFIXES: .o .c .h .run + +OBJECTS = builtins.o debugPrint.o errorStuff.o expr.o initialize.o\ +instantiate.o link.o main.o map.o poke.o read.o relocate.o slinkyTables.o\ +write.o + +SOURCES = builtins.c debugPrint.c errorStuff.c expr.c initialize.c\ +instantiate.c link.c main.c map.c poke.c read.c relocate.c slinkyTables.c\ +write.c slinkyExpressions.h slinkyGlobals.h slinkyTypes.h y.tab.h + +.c.o: + cc -c -O $*.c + +.c.run: + cc -o $* $*.c + +slinky: $(OBJECTS) + cc -O -o slinky $(OBJECTS) + +update: .mark + kessel "(cd /u0/chip/macross/slinky; make slinky >&errorfyle)" & + +move: .mark + +.mark: $(SOURCES) + cp $? /net/kessel/u0/chip/macross/slinky + cp $? /net/kessel/u0/chip/macross/slinky/prof + cp $? .. + date >.mark + date >/net/kessel/u0/chip/macross/slinky/.mark + date >/net/kessel/u0/chip/macross/slinky/prof/.mark + date >../.mark + +install: slinky + cp slinky slinky_tmp + strip slinky_tmp + cp /u1/gg/bin/slinky /u1/gg/bin/slinky.old + cp slinky_tmp /u1/gg/bin/slinky + /bin/rm slinky_tmp + cp /u1/gg/bin/slinky /net/mycroft/u1/gg/bin + cp /u1/gg/bin/slinky /net/shem/u1/gg/bin + cp /u1/gg/bin/slinky /net/weyr/u1/gg/bin + +builtins.o: builtins.c slinkyGlobals.h slinkyTypes.h slinkyExpressions.h + +debugPrint.o: debugPrint.c slinkyGlobals.h slinkyTypes.h + +errorStuff.o: errorStuff.c slinkyGlobals.h slinkyTypes.h + +expr.o: expr.c slinkyExpressions.h slinkyGlobals.h slinkyTypes.h y.tab.h + +initialize.o: initialize.c slinkyGlobals.h slinkyTypes.h + +instantiate.o: instantiate.c slinkyGlobals.h slinkyTypes.h slinkyExpressions.h + +link.o: link.c slinkyGlobals.h slinkyTypes.h + +main.o: main.c slinkyGlobals.h slinkyTypes.h + +map.o: map.c slinkyGlobals.h slinkyTypes.h + +poke.o: poke.c slinkyGlobals.h slinkyTypes.h + +read.o: read.c slinkyGlobals.h slinkyTypes.h + +relocate.o: relocate.c slinkyGlobals.h slinkyTypes.h + +slinkyTables.o: slinkyTables.c slinkyTypes.h + +write.o: write.c slinkyGlobals.h slinkyTypes.h + +cleanup: + /bin/rm -f *.o slinky + +love: + @echo "Not war?" + diff --git a/slinky/poke.c b/slinky/poke.c new file mode 100644 index 0000000..328bac1 --- /dev/null +++ b/slinky/poke.c @@ -0,0 +1,193 @@ +/* + poke.c -- Routines to poke the values of symbolic references into the + generated code for the Slinky linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 18-March-1985 + +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" + + bool +isWordSized(value) + int value; +{ + return (-32768<=value && value<=65535); +} + + bool +isByteSized(value) + int value; +{ + return (-128<=value && value<=255); +} + + bool +isByteOffset(value) + int value; +{ + return (-128<=value && value<=127); +} + + int +computeRelativeValue(valueToPoke, codeSegment, offset) + int valueToPoke; + codeSegmentHeaderType *codeSegment; + int offset; +{ + int fromLocation; + int result; + + fromLocation = codeSegment->segmentStartAddress + offset; + result = valueToPoke - fromLocation; +/* if (result > 0)*/ if (result != 0) + result = result - 1; + else if (result < 0) + result = result + 1; + if (!isByteOffset(result)) { + error(RELATIVE_OFFSET_TOO_LARGE_ERROR, result, offset, + fromLocation); + result = 0; + } + return(result); +} + + int +getBaseValue(codeBuffer, offset, referenceKind) + byte codeBuffer[]; + int offset; + int referenceKind; +{ + int result; + + switch (referenceKind) { + case REF_BYTE: + result = codeBuffer[offset]; + break; + + case REF_DBYTE: + result = (codeBuffer[offset] << 8) | codeBuffer[offset+1]; + break; + + case REF_WORD: + result = codeBuffer[offset] | (codeBuffer[offset+1] << 8); + break; + } + return(result); +} + + void +pokeValue(value, codeBuffer, offset, referenceKind, trueAddress) + int value; + byte codeBuffer[]; + int offset; + int referenceKind; + int trueAddress; +{ + switch (referenceKind) { + case REF_BYTE: + if (!isByteSized(value)) { + error(BYTE_VALUE_TOO_LARGE_ERROR, value, offset, + trueAddress); + } else { + codeBuffer[offset] = value; + } + if (debug) + printf(" Byte: 0x%02x at (0x%04x) 0x%04x\n\n", + value&0xFF, offset, trueAddress); + break; + + case REF_WORD: + if (!isWordSized(value)) { + error(WORD_VALUE_TOO_LARGE_ERROR, value, offset, + trueAddress); + } else { + codeBuffer[offset] = value & 0xFF; + codeBuffer[offset+1] = (value >> 8) & 0xFF; + } + if (debug) + printf(" Word: 0x%04x at (0x%04x) 0x%04x\n\n", + value, offset, trueAddress); + break; + + case REF_DBYTE: + if (!isWordSized(value)) { + error(WORD_VALUE_TOO_LARGE_ERROR, value, offset, + trueAddress); + } else { + codeBuffer[offset] = (value >> 8) & 0xFF; + codeBuffer[offset+1] = 0xFF; + } + if (debug) + printf(" Dbyt: 0x%04x at (0x%04x) 0x%04x\n\n", + value, offset, trueAddress); + break; + } +} + + void +fixupReference(reference, codeSegment) + expressionReferenceType *reference; + codeSegmentHeaderType *codeSegment; +{ + int offset; + addressType baseValue; + int valueToPoke; + + /* at this point, we assume we are already pointing at the + correct codeSegment! */ + if (debug) + printReferenceFixup(reference); + offset = reference->referenceAddress - codeSegment-> + segmentStartAddress + codeSegment->relocationOffset; + relocationOffset = codeSegment->relocationOffset; + baseValue = getBaseValue(codeSegment->segmentCodeBuffer, offset, + reference->referenceKind); + + pc = reference->referenceExpression.inCore; + valueToPoke = evaluateExpression(); + if (reference->referenceRelative) + valueToPoke = computeRelativeValue(valueToPoke, codeSegment, + offset); + else + valueToPoke = (short)baseValue + (short)valueToPoke; + pokeValue(valueToPoke, codeSegment->segmentCodeBuffer, offset, + reference->referenceKind, codeSegment->segmentStartAddress + + offset); + +} + + void +pokem() +{ + objectFileListType *inputFileList; + codeSegmentHeaderType *codeSegment; + expressionReferenceType *reference; + int referenceCount; + + if (debug) + printf("\nFixups:\n"); + + if (haveExpressionEntryPoint) { + pc = entryPointExpression; + entryPointAddress = evaluateExpression(); + } + + for (inputFileList = objectFileList; inputFileList != NULL; + inputFileList = inputFileList->nextObjectFile) { + if (inputFileList->name != NULL) { + currentFileName = inputFileList->name; + for (codeSegment = inputFileList->codeSegments; codeSegment!= + NULL; codeSegment = codeSegment->nextSegment) { + for (reference=codeSegment->segmentReferences, + referenceCount=codeSegment->referenceCount; + referenceCount >0; reference++, referenceCount--){ + fixupReference(reference, codeSegment); + } + } + } + } +} diff --git a/slinky/poke.o b/slinky/poke.o new file mode 100644 index 0000000..2b19063 Binary files /dev/null and b/slinky/poke.o differ diff --git a/slinky/read.c b/slinky/read.c new file mode 100644 index 0000000..e5a6523 --- /dev/null +++ b/slinky/read.c @@ -0,0 +1,529 @@ +/* + read.c -- Routines to read stuff in from object files for the Slinky + linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 10-March-1985 + +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" + +#define isAbsolute(symbol) (((symbol)->symbolClass & SYMBOL_ABSOLUTE) != 0) +#define isRelocatable(symbol) (((symbol)->symbolClass &SYMBOL_RELOCATABLE)!=0) + + void +fileCheck(fildes, fileName) + FILE *fildes; + char *fileName; +{ + if (feof(fildes)) { + error(PREMATURE_EOF_ERROR, fileName); + chokePukeAndDie(); + } else if (ferror(fildes)) { + error(ERROR_READING_OBJECT_FILE, fileName); + perror("Unix says"); + chokePukeAndDie(); + } +} + + wordType +readWord(file, fileName) + FILE *file; + char *fileName; +{ + wordType result; + register char loByte; + register char hiByte; + + loByte = getc(file); + hiByte = getc(file); + fileCheck(file, fileName); + result = ((hiByte & 0xFF) << 8) | (loByte & 0xFF); + return(result); +} + + byte +readByte(file, fileName) + FILE *file; + char *fileName; +{ + int result; + + if ((result = getc(file)) == EOF) { + fileCheck(file, fileName); + } + return(result); +} + + bigWord +readBigword(file, fileName) + FILE *file; + char *fileName; +{ + register bigWord result; + + result = getc(file) & 0xFF; + result |= (getc(file) & 0xFF) << 8; + result |= (getc(file) & 0xFF) << 16; + result |= (getc(file) & 0xFF) << 24; + fileCheck(file, fileName); + return(result); +} + + bigWord +read3ByteWord(file, fileName) + FILE *file; + char *fileName; +{ + register bigWord result; + + result = getc(file) & 0xFF; + result |= (getc(file) & 0xFF) << 8; + result |= (getc(file) & 0xFF) << 16; + fileCheck(file, fileName); + return(result); +} + + int +readString(buffer, fildes, fileName) + char *buffer; + FILE *fildes; + char *fileName; +{ + register char c; + register char *scratchBuffer; + + scratchBuffer = buffer; + while ((c = getc(fildes)) != EOF && c != '\0') + *scratchBuffer++ = c; + fileCheck(fildes, fileName); + *scratchBuffer++ = '\0'; + return(scratchBuffer - buffer); +} + + void +readChunk(buffer, numberOfBytes, fildes, fileName) + byte *buffer; + int numberOfBytes; + FILE *fildes; + char *fileName; +{ + do { + *buffer++ = getc(fildes); + } while (--numberOfBytes > 0); + fileCheck(fildes, fileName); +} + + void +readCode(startAddress, endAddress, mode, objectFile, objectFildes) + addressType startAddress; + addressType endAddress; + int mode; + objectFileListType *objectFile; + FILE *objectFildes; +{ + int size; + byte *codeBuffer; + codeSegmentHeaderType *newCodeSegment; + static int currentConstraint = 0; + static int currentAlignment = 0; + + size = (short)endAddress - (short)startAddress + 1; + if (size == -2) { + entryPointAddress = startAddress; + entryPointMode = mode; + haveEntryPoint = TRUE; + readByte(objectFildes, objectFile->name); + return; + } else if (size == 0) { + currentConstraint = readWord(objectFildes, objectFile->name); + return; + } else if (size == -1) { + currentAlignment = readWord(objectFildes, objectFile->name); + return; + } + size = (wordType)endAddress - (wordType)startAddress + 1; + codeBuffer = typeAllocBlock(byte, size); + readChunk(codeBuffer, size, objectFildes, objectFile->name); + newCodeSegment = typeAlloc(codeSegmentHeaderType); + newCodeSegment->fileName = objectFile->name; + newCodeSegment->segmentStartAddress = startAddress; + newCodeSegment->segmentEndAddress = endAddress; + newCodeSegment->segmentMode = mode; + newCodeSegment->segmentCodeBuffer = codeBuffer; + newCodeSegment->relocationOffset = 0; + newCodeSegment->constraint = currentConstraint; + newCodeSegment->alignment = currentAlignment; + currentConstraint = currentAlignment = 0; + if (objectFile->lastCodeSegment == NULL) { + objectFile->codeSegments = newCodeSegment; + } else { + objectFile->lastCodeSegment->nextSegment = newCodeSegment; + } + objectFile->lastCodeSegment = newCodeSegment; + newCodeSegment->nextSegment = NULL; + if (mode == MODE_ABSOLUTE) + installAbsoluteCodeSegment(newCodeSegment); + if (debug) + printCode(startAddress, endAddress, mode); +} + + bool +compareReferences(reference1, reference2) + expressionReferenceType *reference1; + expressionReferenceType *reference2; +{ + if (reference1->referenceMode == MODE_ABSOLUTE && reference2-> + referenceMode == MODE_RELOCATABLE) + return(-1); + else + return(reference1->referenceAddress - reference2-> + referenceAddress); +/* else if (reference1->referenceAddress < reference2->referenceAddress) + return(-1); + else if (reference1->referenceAddress > reference2->referenceAddress) + return(1); + else + return(0);*/ +} + + void +sortReferences(theReferences, numberOfReferences) + expressionReferenceType *theReferences; + int numberOfReferences; +{ + qsort(theReferences, numberOfReferences, + sizeof(expressionReferenceType), compareReferences); +} + + void +readReference(reference, fildes, fileName) + expressionReferenceType *reference; + FILE *fildes; + char *fileName; +{ + register byte funnyByte; + + reference->referenceAddress = read3ByteWord(fildes, fileName); + funnyByte = readByte(fildes, fileName); + reference->referenceMode = funnyByte & 1; + reference->referenceRelative = (funnyByte >> 1) & 1; + reference->referenceExternal = (funnyByte >> 2) & 1; + reference->referenceKind = (funnyByte >> 3) & 7; + reference->referenceExpression.inFile = readBigword(fildes, fileName); + if (debug) { + printReference(reference); + } +} + + void +readReferences(objectFile, objectFildes) + objectFileListType *objectFile; + FILE *objectFildes; +{ + int count; + int readCount; + expressionReferenceType *theReferences; + expressionReferenceType *readPtr; + expressionReferenceType *subPtr; + codeSegmentHeaderType *codeSegment; + + readCount = count = readBigword(objectFildes, objectFile->name); + if (readCount == 0) + readPtr = theReferences = NULL; + else + readPtr = theReferences = + typeAllocBlock(expressionReferenceType, count); + if (debug) + printf(" %d references\n", count); + while (readCount-- > 0) + readReference(readPtr++, objectFildes, objectFile->name); + sortReferences(theReferences, count); + if (debug) { + printf(" sorted references\n"); + for (readCount=0; readCountcodeSegments; codeSegment != NULL; + codeSegment = codeSegment->nextSegment) { + codeSegment->segmentReferences = readPtr; + while (codeSegment->nextSegment != NULL && readPtr != NULL && + readPtr->referenceAddress <= codeSegment-> + segmentEndAddress && readPtr-> + referenceMode == codeSegment->segmentMode && + readCount-- > 0) { + readPtr++; + } + if (codeSegment->nextSegment != NULL) { + codeSegment->referenceCount = readPtr - subPtr; + subPtr = readPtr; + } else { + codeSegment->referenceCount = count - (readPtr - + theReferences); + } + } +} + + bool +compareSymbolValues(symbol1, symbol2) + symbolType **symbol1; + symbolType **symbol2; +{ + if ((isAbsolute(*symbol1) && !isAbsolute(*symbol2)) || + (isRelocatable(*symbol1) && !isRelocatable(*symbol2) + && !isAbsolute(*symbol2))) + return(-1); + else if ((isAbsolute(*symbol2) && !isAbsolute(*symbol1)) || + (isRelocatable(*symbol2) && !isRelocatable(*symbol1) + && !isAbsolute(*symbol1))) + return(1); + else + return((*symbol1)->symbolValue - (*symbol2)->symbolValue); +/* else if ((*symbol1)->symbolValue < (*symbol2)->symbolValue) + return(-1); + else if ((*symbol1)->symbolValue == (*symbol2)->symbolValue) + return(0); + else + return(1);*/ +} + + void +readSymbols(objectFile, objectFildes) + objectFileListType *objectFile; + FILE *objectFildes; +{ + symbolType *symbolTable; + symbolType **symbolTableIndir; + int symbolCount; + int stringSize; + char *stringBuffer; + char *fileName; + int symbolTag; + + fileName = objectFile->name; + symbolCount = readBigword(objectFildes, fileName); + objectFile->symbolCount = symbolCount; + stringSize = readBigword(objectFildes, fileName); + if (debug) { + printf(" %d symbols with %d bytes of strings\n", + symbolCount, stringSize); + } + symbolTable = typeAllocBlock(symbolType, symbolCount); + symbolTableIndir = typeAllocBlock(symbolType *, symbolCount); + stringBuffer = typeAllocBlock(char, stringSize); + objectFile->symbolTable = symbolTableIndir; + symbolTag = 0; + while (symbolCount-- > 0) { + *symbolTableIndir++ = symbolTable; + symbolTable->symbolClass = readByte(objectFildes, fileName); + symbolTable->symbolValue = readBigword(objectFildes,fileName); + symbolTable->symbolName = stringBuffer; + stringBuffer += readString(stringBuffer, objectFildes, + fileName); + if (debug) { + printSymbol(symbolTag, symbolTable); + symbolTag++; + } + if ((symbolTable->symbolClass & SYMBOL_EXTERNAL) && + (symbolTable->symbolClass & ~SYMBOL_EXTERNAL)) + globalSymbolCount++; + symbolTable++; + } +} + + expressionPCType +readOneExpression(objectFile, objectFildes) + objectFileListType *objectFile; + FILE *objectFildes; +{ + char *fileName; + int expressionSize; + byte *expressionBuffer; + expressionPCType result; + int saveExpressionSize; + + fileName = objectFile->name; + expressionSize = readBigword(objectFildes, fileName); + if (expressionSize == 0) + return(NULL); + expressionBuffer = typeAllocBlock(byte, expressionSize); + result = expressionBuffer; + saveExpressionSize = expressionSize; + do { + *expressionBuffer++ = readByte(objectFildes, fileName); + } while (--expressionSize > 0); + if (debug) { + printExpression(result, saveExpressionSize); + } + return(result); +} + + void +readExpressions(objectFile, objectFildes) + objectFileListType *objectFile; + FILE *objectFildes; +{ + expressionPCType *expressions; + int expressionCount; + int expressionSize; + int saveExpressionSize; + char *fileName; + byte *expressionBuffer; + + fileName = objectFile->name; + expressionCount = readBigword(objectFildes, fileName); + objectFile->expressionCount = expressionCount; + if (debug) + printf(" %d expressions\n", expressionCount); + expressions = typeAllocBlock(expressionPCType, expressionCount); + objectFile->expressions = expressions; + while (expressionCount-- > 0) { + *expressions = readOneExpression(objectFile, objectFildes); + expressions++; + } + if (haveEntryPoint && entryPointAddress==0xFFFE && entryPointMode== + MODE_RELOCATABLE && !haveExpressionEntryPoint) { + if (debug) + printf("Start address expression:\n"); + entryPointAddress = 0; + entryPointExpression = readOneExpression(objectFile, + objectFildes); + readExpressionEntryPoint = TRUE; + } +} + + argumentListType * +readArgumentList(objectFile, objectFildes) + objectFileListType *objectFile; + FILE *objectFildes; +{ + int argumentCount; + char *fileName; + argumentListType *result; + int i; + int symbolNumber; + + fileName = objectFile->name; + argumentCount = readByte(objectFildes, fileName); + if (argumentCount == 0) + return(NULL); + result = typeAllocBlock(argumentListType, argumentCount); + for (i=0; i + symbolTable[symbolNumber]; + } + return(result); +} + + void +readFunctions(objectFile, objectFildes) + objectFileListType *objectFile; + FILE *objectFildes; +{ + functionType *functions; + int functionCount; + int functionSize; + int argumentCount; + int useFunctionSize; + char *fileName; + byte *functionBuffer; + + fileName = objectFile->name; + functionCount = readBigword(objectFildes, fileName); + objectFile->functionCount = functionCount; + if (debug) + printf(" %d functions\n", functionCount); + functions = typeAllocBlock(functionType, functionCount); + objectFile->functions = functions; + while (functionCount-- > 0) { + functions->functionArguments = readArgumentList(objectFile, + objectFildes); + functionSize = readBigword(objectFildes, fileName); + functionBuffer = typeAllocBlock(byte, functionSize); + functions->functionBody = functionBuffer; + useFunctionSize = functionSize; + while (useFunctionSize-- > 0) + *functionBuffer++ = readByte(objectFildes,fileName); + if (debug) { + printExpression(functions->functionBody,functionSize); + } + functions++; + } +} + + void +instantiateExpressionAndSymbolPointers(objectFile) + objectFileListType *objectFile; +{ + symbolType **symbolTable; + expressionPCType *expressions; + functionType *functions; + int i; + codeSegmentHeaderType *codeSegment; + expressionReferenceType *reference; + int referenceCount; + + currentSymbolTable = objectFile->symbolTable; + currentFunctionTable = objectFile->functions; + expressions = objectFile->expressions; + for (codeSegment = objectFile->codeSegments; codeSegment != NULL; + codeSegment = codeSegment->nextSegment) { + for (reference = codeSegment->segmentReferences, referenceCount = + codeSegment->referenceCount; referenceCount > 0; + reference++, referenceCount--) { + pc = reference->referenceExpression.inCore = expressions[ + reference->referenceExpression.inFile]; + putSymbolPointersIntoExpression(); + } + } + functions = objectFile->functions; + for (i=0; ifunctionCount; ++i) { + pc = functions[i].functionBody; + putSymbolPointersIntoExpression(); + } +} + + void +readReservations(objectFile, objectFildes) + objectFileListType *objectFile; + FILE *objectFildes; +{ + addressType startAddress; + reservationListType *buildReservation(); + + if (debug) + printf(" reservations\n"); + while ((startAddress = readWord(objectFildes, objectFile->name)) != + 0xFFFF) + reservationList = buildReservation(startAddress, + readWord(objectFildes, objectFile->name), + reservationList); +} + + reservationListType * +buildReservation(startAddress, blockSize, nextReservation) + addressType startAddress; + int blockSize; + reservationListType *nextReservation; +{ + reservationListType *result; + + result = typeAlloc(reservationListType); + result->startAddress = startAddress; + result->blockSize = blockSize; + result->nextReservation = nextReservation; + if (debug) + printf(" Res: 0x%x 0x%x @0x%x -> 0x%x\n", startAddress, + blockSize, result, nextReservation); + return(result); +} diff --git a/slinky/read.o b/slinky/read.o new file mode 100644 index 0000000..e7bd774 Binary files /dev/null and b/slinky/read.o differ diff --git a/slinky/relocate.c b/slinky/relocate.c new file mode 100644 index 0000000..c4ba9df --- /dev/null +++ b/slinky/relocate.c @@ -0,0 +1,348 @@ +/* + relocate.c -- Routines to relocate relocatable code for the Slinky + linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 15-March-1985 +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" + +#define isUndefined(symbol) (((symbol)->symbolClass & ~SYMBOL_EXTERNAL) == 0) + + void +removeZeroPageFromFreeList() +{ + while (freeSegmentList->segmentEndAddress <= 0x100) + freeSegmentList = freeSegmentList->nextFreeSegment; + if (freeSegmentList->segmentStartAddress < 0x100) + freeSegmentList->segmentStartAddress = 0x100; +} + + addressType +align(address, alignment) + addressType address; + int alignment; +{ + if (alignment == 0) + return(address); + else + return(((address + alignment - 1) / alignment) * alignment); +} + + addressType +constrain(address, size, constraint) + addressType address; + int size; + addressType constraint; +{ + if (constraint == 0) + return(address); + else if (address/constraint != (address + size - 1)/constraint) + return(align(address, constraint)); + else + return(address); +} + void +moveRelocationBase(newBase) + addressType newBase; +{ + freeSegmentEntryType *freePtr; + freeSegmentEntryType *newFreePtr; + + freePtr = freeSegmentList; + while (freePtr != NULL && newBase > freePtr->segmentEndAddress) + freePtr = freePtr->nextFreeSegment; + if (freePtr == NULL || freePtr->segmentStartAddress == newBase) { + effectiveFreeSegmentList = freePtr; + } else { + newFreePtr = typeAlloc(freeSegmentEntryType); + newFreePtr->segmentEndAddress = freePtr->segmentEndAddress; + freePtr->segmentEndAddress = newBase - 1; + newFreePtr->segmentStartAddress = newBase; + newFreePtr->nextFreeSegment = freePtr->nextFreeSegment; + freePtr->nextFreeSegment = newFreePtr; + effectiveFreeSegmentList = newFreePtr; + } +} + + addressType +allocateRelocatable(codeSegment) + codeSegmentHeaderType *codeSegment; +{ + freeSegmentEntryType *freePtr; + freeSegmentEntryType *previousPtr; + freeSegmentEntryType *newFreePtr; + int size; + addressType effectiveStartAddress; + + freePtr = effectiveFreeSegmentList; + previousPtr = NULL; + size = codeSegment->segmentEndAddress - codeSegment-> + segmentStartAddress + 1; + while (freePtr != NULL) { + effectiveStartAddress = align(freePtr->segmentStartAddress, + codeSegment->alignment); + effectiveStartAddress = constrain(effectiveStartAddress, size, + codeSegment->constraint); + if (freePtr->segmentEndAddress - effectiveStartAddress + 1 < + size) { + previousPtr = freePtr; + freePtr = freePtr->nextFreeSegment; + continue; + } + /* if we made it to here, we got a winner! */ + if (effectiveStartAddress == freePtr->segmentStartAddress) { + if (effectiveStartAddress + size - 1 == freePtr-> + segmentEndAddress) { + if (previousPtr == NULL) + freeSegmentList = freePtr->nextFreeSegment; + else + previousPtr->nextFreeSegment = freePtr-> + nextFreeSegment; + } else { + freePtr->segmentStartAddress += size; + } + } else { + if (effectiveStartAddress + size - 1 == freePtr-> + segmentEndAddress) { + freePtr->segmentEndAddress -= size; + } else { + newFreePtr = typeAlloc(freeSegmentEntryType); + newFreePtr->nextFreeSegment = freePtr->nextFreeSegment; + freePtr->nextFreeSegment = newFreePtr; + newFreePtr->segmentEndAddress =freePtr->segmentEndAddress; + freePtr->segmentEndAddress = effectiveStartAddress - 1; + newFreePtr->segmentStartAddress = effectiveStartAddress + + size; + } + } + return(effectiveStartAddress); + } + return((addressType) -1); +} + + void +relocateOneCodeSegment(codeSegment, targetLocation) + codeSegmentHeaderType *codeSegment; + addressType targetLocation; +{ + int relocationOffset; + + relocationOffset = targetLocation - codeSegment->segmentStartAddress; + if (verbose) + printf(" 0x%04x:0x%04x --> 0x%04x", codeSegment-> + segmentStartAddress, codeSegment->segmentEndAddress, + targetLocation); + codeSegment->relocationOffset = relocationOffset; + codeSegment->segmentStartAddress += relocationOffset; + codeSegment->segmentEndAddress += relocationOffset; + if (!packFlag) { + moveRelocationBase(codeSegment->segmentEndAddress+1); + } + if (verbose) + printf(" (0x%04x:0x%04x)\n", codeSegment->segmentStartAddress, + codeSegment->segmentEndAddress); + installSegment(codeSegment); +} + + void +relocatem() +{ + objectFileListType *inputFileList; + addressType targetLocation; + codeSegmentHeaderType *codeSegment; + + reserveReservations(); + removeZeroPageFromFreeList(); + for (inputFileList = objectFileList; inputFileList != NULL; + inputFileList = inputFileList->nextObjectFile) { + if (inputFileList->name != NULL) { + currentFileName = inputFileList->name; + if (verbose) + printf("%s:\n", inputFileList->name); + for (codeSegment = inputFileList->codeSegments; codeSegment != + NULL; codeSegment = codeSegment->nextSegment) { + if (codeSegment->segmentMode == MODE_RELOCATABLE) { + if ((targetLocation=allocateRelocatable(codeSegment)) + == (addressType) -1) { + error(NO_PLACE_TO_PUT_CODE_SEGMENT_ERROR, + codeSegment->segmentStartAddress, + inputFileList->name); + } else { + relocateOneCodeSegment(codeSegment, + targetLocation); + } + } + } + } else { /* null name encodes new relocation base */ + moveRelocationBase(inputFileList->symbolCount); + } + } +} + + codeSegmentHeaderType * +matchModes(symbol, codeSegment) + symbolType *symbol; + codeSegmentHeaderType *codeSegment; +{ + while (codeSegment!=NULL && ((codeSegment->segmentMode==MODE_ABSOLUTE + && !(symbol->symbolClass & SYMBOL_ABSOLUTE)) || + (codeSegment->segmentMode==MODE_RELOCATABLE && + !(symbol->symbolClass & SYMBOL_RELOCATABLE) && + !(symbol->symbolClass & SYMBOL_ABSOLUTE)))) + codeSegment = codeSegment->nextSegment; + return(codeSegment); +} + + bool +matchedModes(symbol, codeSegment) + symbolType *symbol; + codeSegmentHeaderType *codeSegment; +{ + return(((symbol->symbolClass & SYMBOL_ABSOLUTE) && codeSegment-> + segmentMode == MODE_ABSOLUTE) || ((symbol->symbolClass & + SYMBOL_RELOCATABLE) && codeSegment->segmentMode == + MODE_RELOCATABLE)); +} + + codeSegmentHeaderType * +synchronizeCodeSegment(symbol, codeSegment) + symbolType *symbol; + codeSegmentHeaderType *codeSegment; +{ + codeSegment = matchModes(symbol, codeSegment); + while (codeSegment != NULL && codeSegment->nextSegment != NULL && + codeSegment->segmentEndAddress - codeSegment-> + relocationOffset < symbol->symbolValue && + matchedModes(symbol, codeSegment)) { + codeSegment = codeSegment->nextSegment; + } + return(codeSegment); +} + + void +handleGlobalSymbol(symbol) + symbolType *symbol; +{ +} + + void +valueSymbol(symbol, codeSegment) + symbolType *symbol; + codeSegmentHeaderType *codeSegment; +{ + if (symbol->symbolClass & SYMBOL_ABSOLUTE) { + return; + } else if (symbol->symbolClass & SYMBOL_RELOCATABLE) { + symbol->symbolValue += codeSegment->relocationOffset; + } else { + printf("Super botcho! Undefined symbol in ValueSymbol.\n"); + } +} + + symbolType * +lookupGlobalSymbol(symbolName) + char *symbolName; +{ + int guess; + int top; + int bottom; + int compare; + int oldTop; + int oldBottom; + + top = oldBottom = globalSymbolCount; + bottom = oldTop = 0; + while (top != bottom && top != oldTop && bottom != oldBottom) { + guess = (top + bottom) >> 1; + compare = strcmplc(globalSymbolTable[guess]->symbolName, + symbolName); + if (compare == 0) + return(globalSymbolTable[guess]); + else if (compare < 0) { + oldBottom = bottom; + bottom = guess; + } else { + oldTop = top; + top = guess; + } + } + return(NULL); +} + + void +valueUndefinedSymbol(symbol) + symbolType *symbol; +{ + symbolType *globalSymbol; + + if ((globalSymbol = lookupGlobalSymbol(symbol->symbolName)) == NULL) { + error(UNDEFINED_SYMBOL_ERROR, symbol->symbolName); + } else { + symbol->symbolClass = globalSymbol->symbolClass; + symbol->symbolValue = globalSymbol->symbolValue; + } +} + + void +valuem() +{ + objectFileListType *inputFileList; + codeSegmentHeaderType *codeSegmentPtr; + symbolType *symbolPtr; + int symbolCount; + + totalSymbolCount = 0; + for (inputFileList = objectFileList; inputFileList != NULL; + inputFileList = inputFileList->nextObjectFile) { + if (inputFileList->name != NULL) { + currentFileName = inputFileList->name; + if (debug) + printf("\nSymbols with values (%s):\n", inputFileList-> + name); + codeSegmentPtr = inputFileList->codeSegments; + for (symbolCount = 0; symbolCountsymbolCount; + symbolCount++) { + symbolPtr = inputFileList->symbolTable[symbolCount]; + if (isUndefined(symbolPtr)) { +/* inputFileList->undefinedSymbols = symbolPtr;*/ + inputFileList->undefinedSymbols = &(inputFileList->symbolTable[symbolCount]); + break; + } + codeSegmentPtr = synchronizeCodeSegment(symbolPtr, + codeSegmentPtr); + valueSymbol(symbolPtr, codeSegmentPtr); + if (debug) + printSymbol(symbolCount, symbolPtr); + } + inputFileList->baseSymbolCount = symbolCount; + inputFileList->symbolCount -= symbolCount; + } + } + + for (inputFileList = objectFileList; inputFileList != NULL; + inputFileList = inputFileList->nextObjectFile) { + if (inputFileList->name != NULL) { + currentFileName = inputFileList->name; + if (debug) + printf("\nGlobal symbols with values (%s):\n", + inputFileList->name); + for (symbolCount = 0; symbolCount symbolCount; + symbolCount++) { + symbolPtr = inputFileList->undefinedSymbols[symbolCount]; + valueUndefinedSymbol(symbolPtr); + if (debug) + printSymbol(symbolCount, symbolPtr); + } + inputFileList->symbolCount = inputFileList->baseSymbolCount; + totalSymbolCount += inputFileList->baseSymbolCount; + } + } + if (debug) + printf("\nTotal symbol count = %d\n", totalSymbolCount); + if (produceLoadMap) + outputLoadMap(); +} diff --git a/slinky/relocate.o b/slinky/relocate.o new file mode 100644 index 0000000..f6d86e5 Binary files /dev/null and b/slinky/relocate.o differ diff --git a/slinky/slinky b/slinky/slinky new file mode 100755 index 0000000..f5da58b Binary files /dev/null and b/slinky/slinky differ diff --git a/slinky/slinkyExpressions.h b/slinky/slinkyExpressions.h new file mode 100644 index 0000000..04ddca7 --- /dev/null +++ b/slinky/slinkyExpressions.h @@ -0,0 +1,147 @@ +/* + slinkyExpressions.h -- Expression definitions for the Slinky linker + + Chip Morningstar -- Lucasfilm Ltd. + + 6-November-1985 +*/ + +/* + Expressions are stored in the object file in a compact parse-tree + representation. We just read this directly and interpret it on-the-fly + without much sophistication. Function definitions include whole + statements, but the principle is the same. + + The basic form of a syntactic entity is: + +---------+-------------+ + | tagByte | bodyOfThing | + +---------+-------------+ + where 'tabByte' encodes how 'bodyOfThing' is to be interpreted. + + These are the possible 'thing's, as encoded by the 'tagByte's + +------+ + identifier: | sym# | 'sym#' is an index into the symbol entries + +------+ of the object file when the expression is + in the object file too, and then 'sym#' is converted + to a pointer to symbol structure when the symbol + itself is read in. + +-------+-------+------+------+-----+ + functionCall: | func# | argCt | expr | expr | ... | 'argCt' is a + +-------+-------+------+------+-----+ single byte + argument count (which means that a function may have + no more than 255 arguments if it is to be used + externally) and this is how many 'expr's there are. + +-----+ + number: | num | 'num' is just a 4-byte number. + +-----+ + +----+ + conditionCode: | cc | 'cc' is a single byte condition code. + +----+ + +------+ + subexpression: | expr | + +------+ + +----+------+ + unop: | op | expr | 'op' is a 1-byte operation number. + +----+------+ + +----+------+------+ + binop: | op | expr | expr | + +----+------+------+ + +----+------+ + preop: | op | expr | + +----+------+ + +----+------+ + postop: | op | expr | + +----+------+ + + here: empty body. + + +---+---+---+---+-----+----+ + string: | a | b | c | d | ... | \0 | Typical 'C' string. + +---+---+---+---+-----+----+ + +------+------+ + array: | sym# | expr | + +------+------+ + +-----+ + value: | num | + +-----+ + + null: empty body. Encodes null expression *or* statement. + + +-------+-------+-----+-----+ + block: | thing | thing | ... | end | 'end' acts as a + +-------+-------+-----+-----+ termination symbol. + +------+------+ + mdefine: | sym# | expr | 'expr' can be null. + +------+------+ + +------+------+ + mvar: | sym# | expr | 'expr' can be null. + +------+------+ + +------+-------+-------+ + mif: | expr | block | block | either 'block' can be null. + +------+-------+-------+ + +------+------+------+-------+ + mfor: | expr | expr | expr | block | + +------+------+------+-------+ + +------+-------+ + mwhile: | expr | block | + +------+-------+ + +------+-------+ + mdoWhile: | expr | block | + +------+-------+ + +------+-------+ + mdoUntil: | expr | block | + +------+-------+ + +------+ + freturn: | expr | + +------+ + +------+ + perform: | expr | + +------+ + +-------+ + group: | block | + +-------+ + +------+--------+ + assert: | expr | string | + +------+--------+ + +------+--------+--------+-----+-----+ + mswitch: | expr | clause | clause | ... | end | + +------+--------+--------+-----+-----+ + +------+------+-----+-------+ + clause: | expr | expr | ... | block | + +------+------+-----+-------+ + + end: empty body. + +*/ + +#define IDENTIFIER_TAG 0x00 +#define FUNCTION_CALL_TAG 0x01 +#define NUMBER_TAG 0x02 +#define CONDITION_CODE_TAG 0x03 +#define SUBEXPRESSION_TAG 0x04 +#define UNOP_TAG 0x05 +#define BINOP_TAG 0x06 +#define PREOP_TAG 0x07 +#define POSTOP_TAG 0x08 +#define HERE_TAG 0x09 +#define STRING_TAG 0x0A +#define ARRAY_TAG 0x0B +#define VALUE_TAG 0x0C +#define NULL_TAG 0x0D +#define BLOCK_TAG 0x0E +#define MDEFINE_TAG 0x0F +#define MVARIABLE_TAG 0x10 +#define MIF_TAG 0x11 +#define MFOR_TAG 0x12 +#define MWHILE_TAG 0x13 +#define MDOWHILE_TAG 0x14 +#define MDOUNTIL_TAG 0x15 +#define PERFORM_TAG 0x16 +#define GROUP_TAG 0x17 +#define ASSERT_TAG 0x18 +#define MSWITCH_TAG 0x19 +#define CLAUSE_TAG 0x1A +#define END_TAG 0x1B +#define FRETURN_TAG 0x1C +#define BUILTIN_FUNCTION_CALL_TAG 0x1D +#define RELOCATABLE_TAG 0x1E diff --git a/slinky/slinkyGlobals.h b/slinky/slinkyGlobals.h new file mode 100644 index 0000000..e62d610 --- /dev/null +++ b/slinky/slinkyGlobals.h @@ -0,0 +1,49 @@ +/* + slinkyGlobals.h -- Global variables for the Slinky linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 9-March-1985 +*/ + +bool debug; /* TRUE iff we should print debug diagnostics */ +bool errorFlag; /* TRUE iff an error occured during linking */ +bool verbose; +bool packFlag; +#define DEFAULT_LOAD_FILE_NAME "s.out" +FILE *loadFileOutput; /* where to put the results */ +FILE *mapFileOutput; +objectFileListType *objectFileList; +objectFileListType *endOfObjectFileList; +char *currentFileName; +freeSegmentEntryType *freeSegmentList; +freeSegmentEntryType *effectiveFreeSegmentList; +addressType relocationOffset; +addressType entryPointAddress; +int entryPointMode; +expressionPCType entryPointExpression; +bool produceLoadMap; +bool leaveOffLoadFiles; +bool haveEntryPoint; +bool haveExpressionEntryPoint; +bool readExpressionEntryPoint; +symbolType **globalSymbolTable; +int globalSymbolCount; +symbolType **currentSymbolTable; +functionType *currentFunctionTable; +reservationListType *reservationList; +int totalSymbolCount; +expressionPCType pc; +addressType here; +bindingListType *localBindings; + +#define CODE_REGIONS_IN_ADDRESS_SPACE 256 +#define CODE_REGION_SIZE 0x100 +segmentListType *generatedLoadImage[CODE_REGIONS_IN_ADDRESS_SPACE]; +#define regionOf(addr) (addr / CODE_REGION_SIZE) + +struct { + stringType *functionName; + addressType (*functionEntry)(); + } builtInFunctionTable[]; +#define MAX_FUNCTIONS 15 diff --git a/slinky/slinkyTables.c b/slinky/slinkyTables.c new file mode 100644 index 0000000..7cefba9 --- /dev/null +++ b/slinky/slinkyTables.c @@ -0,0 +1,49 @@ +/* + slinkyTables.c -- Global tables for the Slinky linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 14-November-1985 +*/ + +#include "slinkyTypes.h" + +addressType atasciiBIF(); +addressType atasciiColorBIF(); +addressType isAbsoluteValueBIF(); +addressType isConditionCodeBIF(); +addressType isDefinedBIF(); +addressType isExternalBIF(); +addressType nthCharBIF(); +addressType printfBIF(); +addressType strcatBIF(); +addressType strcmpBIF(); +addressType strcmplcBIF(); +addressType strlenBIF(); +addressType substrBIF(); +addressType symbolDefineBIF(); +addressType symbolLookupBIF(); +addressType symbolNameBIF(); + +/* Used to initialize symbols representing built-in functions */ +struct { + stringType *functionName; + addressType (*functionEntry)(); + } builtInFunctionTable[] = { + "atascii", atasciiBIF, /* 0 */ + "atasciiColor", atasciiColorBIF, /* 1 */ + "isAbsoluteValue", isAbsoluteValueBIF, /* 2 */ + "isConditionCode", isConditionCodeBIF, /* 3 */ + "isDefined", isDefinedBIF, /* 4 */ + "isExternal", isExternalBIF, /* 5 */ + "nthChar", nthCharBIF, /* 6 */ + "printf", printfBIF, /* 7 */ + "strcat", strcatBIF, /* 8 */ + "strcmp", strcmpBIF, /* 9 */ + "strcmplc", strcmplcBIF, /* 10 */ + "strlen", strlenBIF, /* 11 */ + "substr", substrBIF, /* 12 */ + "symbolLookup", symbolLookupBIF, /* 13 */ + "symbolName", symbolNameBIF, /* 14 */ + NULL, NULL, +}; diff --git a/slinky/slinkyTables.o b/slinky/slinkyTables.o new file mode 100644 index 0000000..98dc881 Binary files /dev/null and b/slinky/slinkyTables.o differ diff --git a/slinky/slinkyTypes.h b/slinky/slinkyTypes.h new file mode 100644 index 0000000..8573644 --- /dev/null +++ b/slinky/slinkyTypes.h @@ -0,0 +1,168 @@ +/* + slinkyTypes.h -- Type definitions for the Slinky relocating linker. + + Chip Morningstar -- Lucasfilm Ltd. + + 8-March-1985 +*/ + +#include + +typedef unsigned char byte; + +typedef unsigned short wordType; + +typedef unsigned int *ptr; + +typedef byte anyOldThing; + +#define TRUE 1 +#define FALSE 0 +typedef int bool; + +typedef unsigned long bigWord; + +typedef char stringType; /* a char is not a string but a + pointer to char is a pointer to a + string, and pointers are what we + care about when handling strings */ + +typedef bigWord addressType; /* target machine address */ + +/* symbolClass bits */ +#define SYMBOL_UNDEFINED 0x00 +#define SYMBOL_ABSOLUTE 0x02 +#define SYMBOL_RELOCATABLE 0x04 +#define SYMBOL_LOCAL 0x08 +#define SYMBOL_EXTERNAL 0x01 + +typedef struct { + byte symbolClass; /* see above */ + int symbolValue; + stringType *symbolName; + } symbolType; /* as managed in core */ + +typedef byte *expressionPCType; + +typedef struct bindingListStruct { + symbolType *boundSymbol; + byte previousClass; + int previousValue; + struct bindingListStruct *nextBinding; + } bindingListType; + +typedef struct argumentListStruct { + symbolType *argumentSymbol; + struct argumentListStruct *nextArgument; + } argumentListType; + +typedef struct { + expressionPCType functionBody; + argumentListType *functionArguments; + } functionType; + +#define MODE_ABSOLUTE 0 +#define MODE_RELOCATABLE 1 + +#define REF_BYTE 0 +#define REF_WORD 1 +#define REF_DBYTE 2 + +typedef struct { + bigWord referenceAddress : 24, /* target machine address */ + referenceMode : 1, /* see above MODE_xx defines*/ + referenceRelative : 1, /* TRUE==is relative */ + referenceKind : 3, /* see above REF_xx defines */ + referenceExternal : 1, /* TRUE==is ref to external */ + : 2; /* unused bits */ + union { + expressionPCType inCore; + int inFile; + } referenceExpression; + } expressionReferenceType; + +typedef struct codeSegmentHeaderStruct { + struct codeSegmentHeaderStruct *nextSegment; + int relocationOffset; + addressType constraint; + addressType alignment; + addressType segmentStartAddress; + addressType segmentEndAddress; + byte segmentMode; + byte *segmentCodeBuffer; + int referenceCount; + expressionReferenceType *segmentReferences; + char *fileName; + } codeSegmentHeaderType; + +typedef struct segmentListStruct { + codeSegmentHeaderType *thisSegment; + struct segmentListStruct *nextSegment; + } segmentListType; + +#define FIRST_AVAILABLE_LOCATION 0x0000 +#define LAST_AVAILABLE_LOCATION 0xFFFF +typedef struct freeSegmentEntryStruct { + addressType segmentStartAddress; + addressType segmentEndAddress; + struct freeSegmentEntryStruct *nextFreeSegment; + } freeSegmentEntryType; + +typedef struct objectFileListStruct { + char *name; + symbolType **symbolTable; + int symbolCount; + int baseSymbolCount; + symbolType **undefinedSymbols; + int expressionCount; + int functionCount; + expressionPCType *expressions; + functionType *functions; + codeSegmentHeaderType *codeSegments; + codeSegmentHeaderType *lastCodeSegment; + struct objectFileListStruct *nextObjectFile; + } objectFileListType; + +typedef struct reservationListStruct { + addressType startAddress; + int blockSize; + struct reservationListStruct *nextReservation; + } reservationListType; + +typedef enum { + NO_DASH_O_FILE_NAME_ERROR, + BAD_COMMAND_LINE_FLAG_ERROR, + MORE_THAN_ONE_OUTPUT_FILE_ERROR, + CANT_OPEN_LOAD_FILE_ERROR, + CANT_OPEN_OBJECT_FILE_ERROR, + NO_INPUT_FILES_ERROR, + BAD_OBJECT_FILE_ERROR, + PREMATURE_EOF_ERROR, + ERROR_READING_OBJECT_FILE, + OVERLAPPING_ABSOLUTE_CODE_SEGMENTS_ERROR, + NO_PLACE_TO_PUT_CODE_SEGMENT_ERROR, + MULTIPLY_DEFINED_SYMBOL_ERROR, + UNDEFINED_SYMBOL_ERROR, + RELATIVE_OFFSET_TOO_LARGE_ERROR, + BYTE_VALUE_TOO_LARGE_ERROR, + WORD_VALUE_TOO_LARGE_ERROR, + NO_MAP_FILE_NAME_ERROR, + MORE_THAN_ONE_MAP_FILE_ERROR, + CANT_OPEN_MAP_FILE_ERROR, + BAD_LOAD_ADDRESS_ERROR, + NO_LOAD_ADDRESS_ERROR, + ARRAY_TERM_IN_OBJECT_ERROR, + ASSERT_FAILED_ERROR, + CONDITION_CODE_EXPRESSION_ENCOUNTERED_ERROR, + CLAUSE_AT_TOP_LEVEL_ERROR, + TOO_MANY_FUNCTION_ARGUMENTS_ERROR, + TOO_FEW_ARGUMENTS_TO_BIF_ERROR, + TOO_MANY_ARGUMENTS_TO_BIF_ERROR, + BAD_POSITION_ARGUMENT_TO_NTH_CHAR_ERROR, + BAD_SUBSTRING_INDICES_ERROR, + SYMBOL_NAME_ARG_IS_NOT_SYMBOL_ERROR, + SYMBOL_NOT_FOUND_IN_SYMBOL_LOOKUP_ERROR, + } errorType; + +#define typeAlloc(type) (type *)malloc(sizeof(type)) +#define typeAllocBlock(type, size) (type *)malloc(sizeof(type) * (size)) diff --git a/slinky/write.c b/slinky/write.c new file mode 100644 index 0000000..9b2893d --- /dev/null +++ b/slinky/write.c @@ -0,0 +1,60 @@ +/* + write.c -- Routines to write out the eventual object module for the + Slinky linker + + Chip Morningstar -- Lucasfilm Ltd. + + 19-March-1985 +*/ + +#include "slinkyTypes.h" +#include "slinkyGlobals.h" + +#define writeWord(aWord) putc(aWord & 0xFF, loadFileOutput);\ + putc((aWord >> 8) & 0xFF, loadFileOutput) +#define writeByte(aByte) putc(aByte & 0xFF, loadFileOutput) + + void +writeEntryPoint() +{ + writeWord(entryPointAddress); + writeWord(entryPointAddress); + writeByte(0); +} + + void +writeCodeSegment(codeSegment) + codeSegmentHeaderType *codeSegment; +{ + int length; + int i; + + writeWord(codeSegment->segmentStartAddress); + writeWord(codeSegment->segmentEndAddress); + length = codeSegment->segmentEndAddress - codeSegment-> + segmentStartAddress + 1; + for (i=0; isegmentCodeBuffer[i]); +} + + void +writem() +{ + int regionNumber; + codeSegmentHeaderType *lastSegment; + segmentListType *segment; + + writeWord(0xFFFF); + if (haveEntryPoint) + writeEntryPoint(); + lastSegment = NULL; + for (regionNumber = 0; regionNumber < CODE_REGIONS_IN_ADDRESS_SPACE; + regionNumber++) { + for (segment = generatedLoadImage[regionNumber]; segment != + NULL; segment = segment->nextSegment) { + if (segment->thisSegment != lastSegment) + writeCodeSegment(lastSegment = segment-> + thisSegment); + } + } +} diff --git a/slinky/write.o b/slinky/write.o new file mode 100644 index 0000000..2204187 Binary files /dev/null and b/slinky/write.o differ diff --git a/slinky/y.tab.h b/slinky/y.tab.h new file mode 100644 index 0000000..00a12d8 --- /dev/null +++ b/slinky/y.tab.h @@ -0,0 +1,80 @@ +# define A 257 +# define ALIGN 258 +# define ASSERT 259 +# define BLOCK 260 +# define BYTE 261 +# define CONSTRAIN 262 +# define DBYTE 263 +# define DEFINE 264 +# define DO 265 +# define ELSE 266 +# define ELSEIF 267 +# define ENDFILE 268 +# define EOL 269 +# define EXTERN 270 +# define FRETURN 271 +# define FUNCTION 272 +# define HERE 273 +# define IF 274 +# define INCLUDE 275 +# define LONG 276 +# define MACRO 277 +# define MCASE 278 +# define MDEFAULT 279 +# define MDEFINE 280 +# define MDO 281 +# define MELSE 282 +# define MELSEIF 283 +# define MFOR 284 +# define MIF 285 +# define MSWITCH 286 +# define MUNTIL 287 +# define MVARIABLE 288 +# define MWHILE 289 +# define ORG 290 +# define REL 291 +# define START 292 +# define STRING 293 +# define STRUCT 294 +# define TARGET 295 +# define UNDEFINE 296 +# define UNTIL 297 +# define VARIABLE 298 +# define WHILE 299 +# define WORD 300 +# define X 301 +# define Y 302 +# define ConditionCode 303 +# define Identifier 304 +# define MacroName 305 +# define Number 306 +# define Opcode 307 +# define TextString 308 +# define ASSIGN 309 +# define LOGICAL_OR 310 +# define LOGICAL_XOR 311 +# define LOGICAL_AND 312 +# define BITWISE_OR 313 +# define BITWISE_XOR 314 +# define BITWISE_AND 315 +# define EQUAL_TO 316 +# define NOT_EQUAL_TO 317 +# define LESS_THAN 318 +# define LESS_THAN_OR_EQUAL_TO 319 +# define GREATER_THAN 320 +# define GREATER_THAN_OR_EQUAL_TO 321 +# define LEFT_SHIFT 322 +# define RIGHT_SHIFT 323 +# define ADD 324 +# define SUB 325 +# define MUL 326 +# define DIV 327 +# define MOD 328 +# define UNARY_MINUS 329 +# define LOGICAL_NOT 330 +# define BITWISE_NOT 331 +# define HI_BYTE 332 +# define LO_BYTE 333 +# define SELECT 334 +# define INCREMENT 335 +# define DECREMENT 336 diff --git a/slinkyExpressions.h b/slinkyExpressions.h new file mode 100644 index 0000000..04ddca7 --- /dev/null +++ b/slinkyExpressions.h @@ -0,0 +1,147 @@ +/* + slinkyExpressions.h -- Expression definitions for the Slinky linker + + Chip Morningstar -- Lucasfilm Ltd. + + 6-November-1985 +*/ + +/* + Expressions are stored in the object file in a compact parse-tree + representation. We just read this directly and interpret it on-the-fly + without much sophistication. Function definitions include whole + statements, but the principle is the same. + + The basic form of a syntactic entity is: + +---------+-------------+ + | tagByte | bodyOfThing | + +---------+-------------+ + where 'tabByte' encodes how 'bodyOfThing' is to be interpreted. + + These are the possible 'thing's, as encoded by the 'tagByte's + +------+ + identifier: | sym# | 'sym#' is an index into the symbol entries + +------+ of the object file when the expression is + in the object file too, and then 'sym#' is converted + to a pointer to symbol structure when the symbol + itself is read in. + +-------+-------+------+------+-----+ + functionCall: | func# | argCt | expr | expr | ... | 'argCt' is a + +-------+-------+------+------+-----+ single byte + argument count (which means that a function may have + no more than 255 arguments if it is to be used + externally) and this is how many 'expr's there are. + +-----+ + number: | num | 'num' is just a 4-byte number. + +-----+ + +----+ + conditionCode: | cc | 'cc' is a single byte condition code. + +----+ + +------+ + subexpression: | expr | + +------+ + +----+------+ + unop: | op | expr | 'op' is a 1-byte operation number. + +----+------+ + +----+------+------+ + binop: | op | expr | expr | + +----+------+------+ + +----+------+ + preop: | op | expr | + +----+------+ + +----+------+ + postop: | op | expr | + +----+------+ + + here: empty body. + + +---+---+---+---+-----+----+ + string: | a | b | c | d | ... | \0 | Typical 'C' string. + +---+---+---+---+-----+----+ + +------+------+ + array: | sym# | expr | + +------+------+ + +-----+ + value: | num | + +-----+ + + null: empty body. Encodes null expression *or* statement. + + +-------+-------+-----+-----+ + block: | thing | thing | ... | end | 'end' acts as a + +-------+-------+-----+-----+ termination symbol. + +------+------+ + mdefine: | sym# | expr | 'expr' can be null. + +------+------+ + +------+------+ + mvar: | sym# | expr | 'expr' can be null. + +------+------+ + +------+-------+-------+ + mif: | expr | block | block | either 'block' can be null. + +------+-------+-------+ + +------+------+------+-------+ + mfor: | expr | expr | expr | block | + +------+------+------+-------+ + +------+-------+ + mwhile: | expr | block | + +------+-------+ + +------+-------+ + mdoWhile: | expr | block | + +------+-------+ + +------+-------+ + mdoUntil: | expr | block | + +------+-------+ + +------+ + freturn: | expr | + +------+ + +------+ + perform: | expr | + +------+ + +-------+ + group: | block | + +-------+ + +------+--------+ + assert: | expr | string | + +------+--------+ + +------+--------+--------+-----+-----+ + mswitch: | expr | clause | clause | ... | end | + +------+--------+--------+-----+-----+ + +------+------+-----+-------+ + clause: | expr | expr | ... | block | + +------+------+-----+-------+ + + end: empty body. + +*/ + +#define IDENTIFIER_TAG 0x00 +#define FUNCTION_CALL_TAG 0x01 +#define NUMBER_TAG 0x02 +#define CONDITION_CODE_TAG 0x03 +#define SUBEXPRESSION_TAG 0x04 +#define UNOP_TAG 0x05 +#define BINOP_TAG 0x06 +#define PREOP_TAG 0x07 +#define POSTOP_TAG 0x08 +#define HERE_TAG 0x09 +#define STRING_TAG 0x0A +#define ARRAY_TAG 0x0B +#define VALUE_TAG 0x0C +#define NULL_TAG 0x0D +#define BLOCK_TAG 0x0E +#define MDEFINE_TAG 0x0F +#define MVARIABLE_TAG 0x10 +#define MIF_TAG 0x11 +#define MFOR_TAG 0x12 +#define MWHILE_TAG 0x13 +#define MDOWHILE_TAG 0x14 +#define MDOUNTIL_TAG 0x15 +#define PERFORM_TAG 0x16 +#define GROUP_TAG 0x17 +#define ASSERT_TAG 0x18 +#define MSWITCH_TAG 0x19 +#define CLAUSE_TAG 0x1A +#define END_TAG 0x1B +#define FRETURN_TAG 0x1C +#define BUILTIN_FUNCTION_CALL_TAG 0x1D +#define RELOCATABLE_TAG 0x1E diff --git a/statementSemantics.c b/statementSemantics.c new file mode 100644 index 0000000..ac4e287 --- /dev/null +++ b/statementSemantics.c @@ -0,0 +1,1532 @@ +/* + statementSemantics.c -- Routines to eat up a parse tree and spit out + code. + + Chip Morningstar -- Lucasfilm Ltd. + + 12-November-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +operandType *dbOperand; /* safe temps for dbx hacking */ +expressionType *dbExpression; +symbolTableEntryType *dbSymbol; + +bool newIncludeFile = FALSE; +static bool insideConstraintBlock = FALSE; +bool nullStatementFlag = FALSE; + +#define nullAssemble(thing) if (thing==NULL) return; +#define sideEffectBomb() if (beneathFunction) {\ + error(SIDE_EFFECT_ERROR, currentFunctionName);\ + break; } + +#define expansionOff() {saveExpansion=expandMacros; expandMacros=FALSE;} +#define expansionOn() expandMacros=saveExpansion; + + void +assembleBlock(block) + blockType *block; +{ + simpleFixupListType *assembleStatement(); + + nullAssemble(block); + assembleStatement(block, FALSE, NULL); +} + + simpleFixupListType * +assembleBlockInsideIf(block, ongoingFixupList) + blockType *block; + simpleFixupListType *ongoingFixupList; +{ + simpleFixupListType *assembleStatement(); + + nullAssemble(block); + return(assembleStatement(block, TRUE, ongoingFixupList)); +} + + bool +operandCheck(opcode, numberOfOperands, evaluatedOperands) + opcodeTableEntryType *opcode; + int numberOfOperands; + valueType *evaluatedOperands[]; +{ + int i; + + for (i=0; iaddressMode)] & opcode-> + permissibleOperandModes) == 0) { + error(ILLEGAL_OPERAND_TYPE_ERROR, opcode->mnemonic); + return(FALSE); + } + } + return(TRUE); +} + + void +assembleMachineInstruction(opcode, operands) + opcodeTableEntryType *opcode; + operandListType *operands; +{ + int i; + int op; + valueType *evaluatedOperands[MAX_NUMBER_OF_OPERANDS]; + valueType *value; + + valueType *evaluateOperand(); + addressType addressValue(); + + nullAssemble(opcode); + expand(moreText("%s\t", opcode->mnemonic)); + for (op=1; operands!=NULL && op<=opcode->maxNumberOfOperands; + op++, operands=operands->nextOperand) { + newFixupAddressMode = EXPRESSION_OPND; + evaluatedOperands[op-1] = value = evaluateOperand(operands); + fixupAddressMode[op-1] = newFixupAddressMode; + currentOperandNumber++; + expand(isUndefined(value) ? (finishOperand = TRUE) : + expandOperand(value->addressMode, + operandBuffer[op-1])); + if (value==NULL || value->kindOfValue == FAIL){ + error(BAD_INSTRUCTION_OPERAND_ERROR, opcode-> + mnemonic); + if (freeFlag) + for (i=1; imnemonic, + opcode->maxNumberOfOperands); + } else if (op < opcode->minNumberOfOperands) { + error(TOO_FEW_INSTRUCTION_OPERANDS_ERROR, opcode->mnemonic, + opcode->minNumberOfOperands); + } else if (operandCheck(opcode, op, evaluatedOperands)) { + (*instructionActionTable[(int)opcode->addressClass])(opcode, + op, evaluatedOperands); + } + expand((expandOperands(op), endLine())); + if (freeFlag) + for (i=0; ibody == NULL) { + error(UNDEFINED_MACRO_ERROR, macroInstruction->macroName); + return; + } + pushEnvironment(newEnvironment); + savedLocalVariableList = currentLocalVariableList; + currentLocalVariableList = NULL; + savedLabelTagNumber = currentLabelTagNumber; + currentLabelTagNumber = nextLabelTagNumber++; + savedErrorFlag = errorFlag; + errorFlag = FALSE; + saveListingOn = listingOn; + if ((numberBound = bindMacroArguments(macroInstruction->arguments, + operands, macroInstruction->macroName)) > 0) { + macroCallDepth++; + listingOn = amExpanding(); + assembleBlock(macroInstruction->body); + macroCallDepth--; + } else + numberBound = -numberBound; + if (numberBound > 1) + unbindArguments(macroInstruction->arguments, numberBound-1); + unbindLocalVariables(currentLocalVariableList); + if (errorFlag) + error(ERROR_INSIDE_MACRO_ERROR, macroInstruction->macroName); + else + errorFlag = savedErrorFlag; + currentLabelTagNumber = savedLabelTagNumber; + currentLocalVariableList = savedLocalVariableList; + listingOn = saveListingOn; + popEnvironment(); +} + + void +assembleAlignStatement(alignStatement) + alignStatementBodyType *alignStatement; +{ + int alignment; + bool saveExpansion; + + int intValue(); + valueType *evaluateExpression(); + + nullAssemble(alignStatement); + expansionOff(); + alignment = intValue(evaluateExpression(alignStatement, NO_FIXUP)); + expansionOn(); + expand((moreText("align\t0x%x", alignment), endLine())); + if (alignment > 0) + if (currentCodeMode == ABSOLUTE_BUFFER) { + if (structNestingDepth == 0) + currentLocationCounter.value = alignment * + ((currentLocationCounter.value + + alignment - 1) / alignment); + else + currentFieldOffset = alignment * + ((currentFieldOffset + alignment - + 1) / alignment); + } else { + if (insideConstraintBlock) + error(ALIGN_INSIDE_CONSTRAIN_ERROR); + else + addBreak(ALIGN_BREAK, alignment); + } + else + error(IMPROPER_ALIGNMENT_VALUE_ERROR); +} + + void +assembleAssertStatement(assertStatement) + assertStatementBodyType *assertStatement; +{ + valueType *test; + valueType *message; + bool saveExpansion; + + valueType *evaluateExpression(); + + expansionOff(); + test = evaluateExpression(assertStatement->condition, NO_FIXUP); + expansionOn(); + if (test == NULL || test->kindOfValue != ABSOLUTE_VALUE) { + error(INVALID_ASSERT_CONDITION_ERROR); + } else if (!test->value) { + if (assertStatement->message == NULL) + error(ASSERT_ERROR); + else { + expansionOff(); + message = evaluateExpression(assertStatement->message, + NO_FIXUP); + expansionOn(); + if (message == NULL || message->kindOfValue != + STRING_VALUE) + error(INVALID_ASSERT_MESSAGE_ERROR); + else + error(ASSERT_WITH_MESSAGE_ERROR, message-> + value); + } + } +} + + void +assembleBlockStatement(blockStatement) + blockStatementBodyType *blockStatement; +{ + valueType *blockIncrement; + int blockSize; + + valueType *evaluateExpression(); + int intValue(); + + blockSize = 0; + nullAssemble(blockStatement); + expand(moreText("block\t")); + while (blockStatement != NULL) { + blockIncrement = evaluateExpression(blockStatement-> + theExpression, NO_FIXUP); + blockSize += intValue(blockIncrement); + blockStatement = blockStatement->nextExpression; + expand((expandExpression(NULL), blockStatement!=NULL ? + moreText(", ") : 0)); + qfree(blockIncrement); + } + expand(endLine()); + if (blockSize >= 0) { + if (structNestingDepth != 0) { + while (blockSize-- > 0) + emitByte(0); + } else if (currentCodeMode == RELOCATABLE_BUFFER) { + while (blockSize-- > 0) + emitByte(0); + } else { + if (produceLinkableObject) + reserveAbsolute(currentLocationCounter.value, + blockSize); + currentLocationCounter.value += blockSize; + } + } else + error(NEGATIVE_BLOCK_SIZE_ERROR); +} + + void +assembleByteStatement(byteStatement) + byteStatementBodyType *byteStatement; +{ + valueType *byteValue; + + valueType *evaluateExpression(); + + nullAssemble(byteStatement); + expand(moreText("byte\t")); + while (byteStatement != NULL) { + byteValue = evaluateExpression(byteStatement->theExpression, + BYTE_FIXUP); + if (byteValue->kindOfValue == STRING_VALUE) { + emitString(byteValue->value); + } else { + putFixupsHere(BYTE_FIXUP, 0); + emitByteValue(byteValue); + } + qfree(byteValue); + byteStatement = byteStatement->nextExpression; + expand((expandExpression(NULL), byteStatement != NULL ? + moreText(", ") : 0)); + } + expand(endLine()); +} + + void +assembleConstrainStatement(constrainStatement) + constrainStatementBodyType *constrainStatement; +{ + valueType *constraintValue; + int constraint; + addressType startAddress; + addressType endAddress; + bool saveExpansion; + + valueType *evaluateExpression(); + + expansionOff(); + constraintValue = evaluateExpression(constrainStatement->constraint, + NO_FIXUP); + expansionOn(); + if (constraintValue == NULL || constraintValue->kindOfValue != + ABSOLUTE_VALUE) { + error(INVALID_CONSTRAINT_VALUE_ERROR); + return; + } + constraint = constraintValue->value; + expand((moreText("constrain (0x%x) {", constraint), endLine(), + tabCount++)); + if (currentCodeMode == ABSOLUTE_BUFFER) { + startAddress = currentLocationCounter.value; + assembleBlock(constrainStatement->constrainedBlock); + endAddress = currentLocationCounter.value; + if ((startAddress / constraint) != (endAddress / constraint)) + error(CONSTRAINT_ERROR, constraint); + } else { + if (insideConstraintBlock) { + error(CONSTRAIN_INSIDE_CONSTRAIN_ERROR); + assembleBlock(constrainStatement->constrainedBlock); + } else { + insideConstraintBlock = TRUE; + addBreak(CONSTRAIN_BREAK, constraint); + assembleBlock(constrainStatement->constrainedBlock); + addBreak(END_CONSTRAIN_BREAK, 0); + insideConstraintBlock = FALSE; + } + } + expand((tabCount--, startLineMarked(), tabIndent(), moreText("}"), + endLine())); +} + + void +assembleDbyteStatement(dbyteStatement) + dbyteStatementBodyType *dbyteStatement; +{ + valueType *wordValue; + + valueType *evaluateExpression(); + valueType *swabValue(); + + nullAssemble(dbyteStatement); + expand(moreText("dbyte\t")); + while (dbyteStatement != NULL) { + wordValue = swabValue(evaluateExpression(dbyteStatement-> + theExpression, DBYTE_FIXUP)); + dbyteStatement = dbyteStatement->nextExpression; + expand((expandExpression(NULL), dbyteStatement != NULL ? + moreText(", ") : 0)); + putFixupsHere(DBYTE_FIXUP, 0); + emitWordValue(wordValue); + qfree(wordValue); + } + expand(endLine()); +} + + void +assembleDefineStatement(defineStatement) + defineStatementBodyType *defineStatement; +{ + symbolTableEntryType *symbolToDefine; + symbolInContextType *contextToDefine; + bool saveExpansion; + + valueType *evaluateDefineExpression(); + valueType *newValue(); + symbolTableEntryType *effectiveSymbol(); + + nullAssemble(defineStatement); + symbolToDefine = effectiveSymbol(defineStatement->theSymbol, + &contextToDefine); + if (isDefinable(contextToDefine)) { + expand(moreText("define %s = ", symbName(symbolToDefine))); + if (contextToDefine->usage == DEAD_SYMBOL) { + reincarnateSymbol(contextToDefine, DEFINE_SYMBOL); + } else if (contextToDefine->usage == NESTED_UNKNOWN_SYMBOL) { + contextToDefine->usage = DEFINE_SYMBOL; + } + if (alreadyDefined(contextToDefine)) + error(REDEFINITION_OF_SYMBOL_ERROR, symbName( + symbolToDefine)); + else { + if (defineStatement->theValue != NULL) { + contextToDefine->value = + evaluateDefineExpression( + defineStatement->theValue); + contextToDefine->usage = DEFINE_SYMBOL; + expand(expandExpression(NULL)); + } else + contextToDefine->value = newValue(FAIL, 0, + EXPRESSION_OPND); + contextToDefine->environmentNumber = + GLOBAL_ENVIRONMENT_NUMBER; + contextToDefine->attributes |= DEFINED_VARIABLE_ATT; + } + expand(endLine()); + } else { + error(SYMBOL_ALREADY_THERE_ERROR, symbName(symbolToDefine)); + } +} + + void +assembleDoUntilStatement(doUntilStatement) + doUntilStatementBodyType *doUntilStatement; +{ + valueType topOfLoop; + + simpleFixupListType *emitJump(); + + nullAssemble(doUntilStatement); + topOfLoop = currentLocationCounter; + if (doUntilStatement->doUntilCondition == NEVER_COND) + topOfLoop.value -= targetOffset; + expand((moreText("do {"), endLine(), tabCount++)); + assembleBlock(doUntilStatement->doUntilLoop); + expand((tabCount--, startLineMarked(), tabIndent(), + moreText("} until %s", conditionString(doUntilStatement-> + doUntilCondition)), endLine())); + if (doUntilStatement->doUntilCondition == ALWAYS_COND) { + return; + } else if (doUntilStatement->doUntilCondition != NEVER_COND) { + emitRelativeBranch(invertConditionCode(doUntilStatement-> + doUntilCondition), &topOfLoop, NULL); + } else { + emitJump(&topOfLoop, NULL); + } +} + + void +assembleDoWhileStatement(doWhileStatement) + doWhileStatementBodyType *doWhileStatement; +{ + valueType topOfLoop; + + simpleFixupListType *emitJump(); + + nullAssemble(doWhileStatement); + topOfLoop = currentLocationCounter; + if (doWhileStatement->doWhileCondition == ALWAYS_COND) + topOfLoop.value -= targetOffset; + expand((moreText("do {"), endLine(), tabCount++)); + assembleBlock(doWhileStatement->doWhileLoop); + expand((tabCount--, startLineMarked(), tabIndent(), + moreText("} while %s", conditionString(doWhileStatement-> + doWhileCondition)), endLine())); + if (doWhileStatement->doWhileCondition == NEVER_COND) { + return; + } else if (doWhileStatement->doWhileCondition != ALWAYS_COND) { + emitRelativeBranch(doWhileStatement->doWhileCondition, + &topOfLoop, NULL); + } else { + emitJump(&topOfLoop, NULL); + } +} + + void +assembleExternStatement(externStatement) + externStatementBodyType *externStatement; +{ + symbolInContextType *context; + symbolTableEntryType *theSymbol; + + symbolInContextType *getBaseContext(); + symbolTableEntryType *effectiveSymbol(); + + expand(moreText("extern\t")); + while (externStatement != NULL) { + theSymbol = effectiveSymbol(externStatement->theSymbol, + &context); + expand(moreText("%s", symbName(theSymbol))); + if (context != NULL) { + if (context->usage == LABEL_SYMBOL || context->usage + == EXTERNAL_SYMBOL || context->usage + == UNKNOWN_SYMBOL || context->usage + == NESTED_UNKNOWN_SYMBOL) { + context->attributes |= GLOBAL_ATT; + } else { + error(BAD_KIND_OF_SYMBOL_TO_MAKE_EXTERNAL_ERROR, + usageString(context->usage)); + } + } + externStatement = externStatement->nextIdentifier; + expand(externStatement != NULL ? moreText(", ") : 0); + } + expand(endLine()); +} + + void +assembleFreturnStatement(freturnStatement) + freturnStatementBodyType *freturnStatement; +{ + freturnExit = TRUE; + resultOfLastFunctionCall = evaluateExpression(freturnStatement, + NO_FIXUP_OK); +} + + void +assembleFunctionStatement(functionStatement) + functionStatementBodyType *functionStatement; +{ + symbolTableEntryType *newFunctionSymbol; + functionDefinitionType *newFunction; + symbolInContextType *context; + + symbolTableEntryType *lookupOrEnterSymbol(); + valueType *newValue(); + symbolInContextType *getBaseContext(); + + nullAssemble(functionStatement); + if (currentEnvironment != &globalEnvironment) { + error(FUNCTION_DEFINITION_INSIDE_FUNCTION_ERROR); + return; + } + newFunctionSymbol = lookupOrEnterSymbol(functionStatement-> + functionName, FUNCTION_SYMBOL); + context = getBaseContext(newFunctionSymbol); + if (context->usage != FUNCTION_SYMBOL) { + if (context->usage == UNKNOWN_FUNCTION_SYMBOL) { + context->usage = FUNCTION_SYMBOL; + } else { + error(SYMBOL_ALREADY_THERE_ERROR, symbName( + newFunctionSymbol)); + return; + } + } else if (isDefined(context->value)) { + error(FUNCTION_ALREADY_EXISTS_ERROR, symbName( + newFunctionSymbol)); + return; + } + newFunction = typeAlloc(functionDefinitionType); + newFunction->functionName = newFunctionSymbol; + newFunction->arguments = functionStatement->theArguments; + newFunction->body = functionStatement->theBlock; + newFunction->ordinal = -1; + newFunction->nextExternalFunction = NULL; + context->value = newValue(FUNCTION_VALUE, newFunction, + EXPRESSION_OPND); + context->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; +} + + void +assembleGroupStatement(groupStatement) + blockType *groupStatement; +{ + expand((startLineMarked(), tabIndent(), moreText("{"), endLine(), + tabCount++)); + assembleBlock(groupStatement); + expand((tabCount--, startLineMarked(), tabIndent(), moreText("}"), + endLine())); +} + + simpleFixupListType * +assembleIfStatement(ifStatement, terminalIf, ongoingFixupList) + ifStatementBodyType *ifStatement; + bool terminalIf; + simpleFixupListType *ongoingFixupList; +{ + valueType fixupLocation1[COMPOUND_BRANCH_MAX]; + simpleFixupListType *fixupLocation2; + + simpleFixupListType *emitJump(); + void assembleIfStatementOldStyle(); + + if (backwardsCompatibleIfFlag) { + assembleIfStatementOldStyle(ifStatement); + return(NULL); + } + + nullAssemble(ifStatement); + fixupLocation2 = ongoingFixupList; + if (ifStatement->ifCondition != ALWAYS_COND && ifStatement-> + ifCondition != NEVER_COND) { + emitRelativeBranch(invertConditionCode(ifStatement-> + ifCondition), NULL, fixupLocation1); + expand((moreText("if %s {", conditionString(ifStatement-> + ifCondition)), endLine(), tabCount++)); + } else if (ifStatement->ifCondition == ALWAYS_COND) { + expand((moreText("{"), endLine(), tabCount++)); + } + if (ifStatement->consequence != NULL && ifStatement->ifCondition != + NEVER_COND) + fixupLocation2 = assembleBlockInsideIf(ifStatement-> + consequence, fixupLocation2); + expand((tabCount--, startLineMarked())); + if (ifStatement->continuation.continuationBodyUnion != NULL && + ifStatement->ifCondition != NEVER_COND && + ifStatement->ifCondition != ALWAYS_COND) + fixupLocation2 = emitJump(NULL, fixupLocation2); + if (ifStatement->ifCondition != ALWAYS_COND && ifStatement-> + ifCondition != NEVER_COND) + fixupBranch(fixupLocation1, currentLocationCounter); + if (ifStatement->continuation.continuationBodyUnion != NULL && + ifStatement->ifCondition != ALWAYS_COND) { + expand((tabIndent(), moreText("} else "))); + fixupLocation2 = assembleIfStatement(ifStatement-> + continuation, terminalIf, fixupLocation2); + } else { + expand((tabIndent(), moreText("}"), endLine())); + } + if (terminalIf) { + return(fixupLocation2); + } else { + fixupJump(fixupLocation2, currentLocationCounter); + return(NULL); + } +} + + void +assembleIfStatementOldStyle(ifStatement) + ifStatementBodyType *ifStatement; +{ + valueType fixupLocation1[COMPOUND_BRANCH_MAX]; + simpleFixupListType *fixupLocation2; + + simpleFixupListType *emitJump(); + + nullAssemble(ifStatement); + if (ifStatement->ifCondition != ALWAYS_COND) { + emitRelativeBranch(invertConditionCode(ifStatement-> + ifCondition), NULL, fixupLocation1); + expand((moreText("if %s {", conditionString(ifStatement-> + ifCondition)), endLine(), tabCount++)); + } else { + expand((moreText("{"), endLine(), tabCount++)); + } + if (ifStatement->consequence != NULL) + assembleBlock(ifStatement->consequence); + expand((tabCount--, startLineMarked())); + if (ifStatement->continuation.continuationBodyUnion != NULL) + fixupLocation2 = emitJump(NULL, NULL); + if (ifStatement->ifCondition != ALWAYS_COND) + fixupBranch(fixupLocation1, currentLocationCounter); + if (ifStatement->continuation.continuationBodyUnion != NULL) { + expand((tabIndent(), moreText("} else "))); + assembleIfStatementOldStyle(ifStatement->continuation); + } else { + expand((tabIndent(), moreText("}"), endLine())); + } + if (ifStatement->continuation.continuationBodyUnion != NULL) + fixupJump(fixupLocation2, currentLocationCounter); +} + + void +assembleIncludeStatement(includeStatement) + includeStatementBodyType *includeStatement; +{ + stringType *fileName; + valueType *possibleFileName; + bool saveExpansion; + valueType *evaluateExpression(); + stringType *saveString(); + + expansionOff(); + possibleFileName = evaluateExpression(includeStatement, NO_FIXUP); + expansionOn(); + if (possibleFileName->kindOfValue == STRING_VALUE) { + fileName = (stringType *)possibleFileName->value; + newIncludeFile = TRUE; + expand((moreText("include \"%s\"", fileName), endLine())); + pushInputFileStack(saveString(fileName)); + } else { + error(INCLUDE_FILE_NOT_A_STRING_VALUE_ERROR); + } +} + + void +assembleInstructionStatement(instructionStatement, cumulativeLineNumber) + instructionStatementBodyType *instructionStatement; + int cumulativeLineNumber; +{ + nullAssemble(instructionStatement); + switch(instructionStatement->kindOfInstruction) { + + case OPCODE_INSTRUCTION: + if (amListing()) + saveIndexForListing(INSTRUCTION_STATEMENT, + cumulativeLineNumber); + expand((startLine(), expandLabel(), tabIndent())); + assembleMachineInstruction(instructionStatement-> + theInstruction, instructionStatement->theOperands); + break; + + case MACRO_INSTRUCTION: + if (amListing() && !amExpanding()) + saveIndexForListing(INSTRUCTION_STATEMENT, + cumulativeLineNumber); + assembleMacro(instructionStatement->theInstruction, + instructionStatement->theOperands); + break; + + default: + botch("bad instruction type=%d\n", instructionStatement-> + kindOfInstruction); + break; + } +} + + void +assembleLongStatement(longStatement) + longStatementBodyType *longStatement; +{ + valueType *longValue; + + valueType *evaluateExpression(); + + nullAssemble(longStatement); + expand(moreText("long\t")); + while (longStatement != NULL) { + longValue = evaluateExpression(longStatement->theExpression, + LONG_FIXUP); + longStatement = longStatement->nextExpression; + expand((expandExpression(NULL), longStatement != NULL ? + moreText(", ") : 0)); + putFixupsHere(LONG_FIXUP, 0); + emitLongValue(longValue); + qfree(longValue); + } + expand(endLine()); +} + + void +assembleMacroStatement(macroStatement) + macroStatementBodyType *macroStatement; +{ + macroTableEntryType *newMacro; + + macroTableEntryType *installMacro(); + + nullAssemble(macroStatement); + if (currentEnvironment != &globalEnvironment) { + error(MACRO_DEFINITION_INSIDE_MACRO_ERROR); + return; + } + newMacro = macroStatement->theMacro; + if (newMacro == NULL) + return; + if (newMacro->body != NULL) { + error(MACRO_ALREADY_EXISTS_ERROR, macroStatement->theMacro-> + macroName); + return; + } + newMacro->arguments = macroStatement->theArguments; + newMacro->body = macroStatement->theBlock; +} + + void +assembleMdefineStatement(mdefineStatement) + defineStatementBodyType *mdefineStatement; +{ + bool saveExpansion; + valueType *evaluateDefineExpression(); + + nullAssemble(mdefineStatement); + expansionOff(); + pushBinding(mdefineStatement->theSymbol, evaluateDefineExpression( + mdefineStatement->theValue), MDEFINE_SYMBOL); + expansionOn(); + addNewLocalVariable(mdefineStatement->theSymbol); +} + + void +assembleMdoUntilStatement(mdoUntilStatement) + mdoUntilStatementBodyType *mdoUntilStatement; +{ + bool saveListingOn; + + nullAssemble(mdoUntilStatement); + saveListingOn = listingOn; + do { + assembleBlock(mdoUntilStatement->mdoUntilLoop); + listingOn = amExpanding(); + } while (!booleanTest(mdoUntilStatement->mdoUntilCondition)); + listingOn = saveListingOn; +} + + void +assembleMdoWhileStatement(mdoWhileStatement) + mdoWhileStatementBodyType *mdoWhileStatement; +{ + bool saveListingOn; + + nullAssemble(mdoWhileStatement); + saveListingOn = listingOn; + do { + assembleBlock(mdoWhileStatement->mdoWhileLoop); + listingOn = amExpanding(); + } while (booleanTest(mdoWhileStatement->mdoWhileCondition)); + listingOn = saveListingOn; +} + + void +assembleMforStatement(mforStatement) + mforStatementBodyType *mforStatement; +{ + bool saveListingOn; + bool saveExpansion; + + nullAssemble(mforStatement); + saveListingOn = listingOn; + expansionOff(); + for (evaluateExpression(mforStatement->initExpression, NO_FIXUP); + booleanTest(mforStatement->testExpression); + evaluateExpression(mforStatement->incrExpression, NO_FIXUP)) { + expansionOn(); + assembleBlock(mforStatement->forLoop); + listingOn = amExpanding(); + expansionOff(); + } + expansionOn(); + listingOn = saveListingOn; +} + + void +assembleMifStatement(mifStatement, cumulativeLineNumber) + mifStatementBodyType *mifStatement; + int cumulativeLineNumber; +{ + while (mifStatement != NULL) { + if (mifStatement->mifCondition == NULL) { + assembleBlock(mifStatement->mifConsequence); + break; + } else if (booleanTest(mifStatement->mifCondition)) { + assembleBlock(mifStatement->mifConsequence); + break; + } else { + mifStatement = mifStatement->mifContinuation. + mifContinuationBodyUnion; + } + } + if (amListing()) + saveEndMifForListing(cumulativeLineNumber); +} + + void +assembleMswitchStatement(mswitchStatement) + mswitchStatementBodyType *mswitchStatement; +{ + valueType *switchValue; + caseListType *caseList; + caseType *theCase; + bool matched; + expressionListType *tagExpressionList; + valueType *tagValue; + bool saveExpansion; + valueType *evaluateExpression(); + + expansionOff(); + switchValue = evaluateExpression(mswitchStatement->switchExpression, + NO_FIXUP); + expansionOn(); + if (switchValue->kindOfValue != ABSOLUTE_VALUE && switchValue->kindOfValue + != STRING_VALUE) { + error(INVALID_SWITCH_VALUE_KIND, valueKindString(switchValue-> + kindOfValue)); + return; + } + for (caseList=mswitchStatement->cases; caseList!=NULL; caseList=caseList-> + nextCase) { + theCase = caseList->theCase; + if (theCase->caseTags == NULL) { + assembleBlock(theCase->caseBody); + break; + } else { + matched = FALSE; + for (tagExpressionList=theCase->caseTags; tagExpressionList!=NULL; + tagExpressionList=tagExpressionList->nextExpression) { + expansionOff(); + tagValue = evaluateExpression(tagExpressionList-> + theExpression, NO_FIXUP); + expansionOn(); + if (tagValue->kindOfValue != ABSOLUTE_VALUE && tagValue-> + kindOfValue != STRING_VALUE) { + error(INVALID_CASE_VALUE_KIND, valueKindString(tagValue-> + kindOfValue)); + continue; + } + if (tagValue->kindOfValue != switchValue->kindOfValue) + continue; + if (tagValue->kindOfValue == ABSOLUTE_VALUE) { + if (tagValue->value != switchValue->value) + continue; + } else { + if (strcmplc(tagValue->value, switchValue->value) != 0) + continue; + } + matched = TRUE; + break; + } + if (matched) { + assembleBlock(theCase->caseBody); + break; + } + } + } +} + + void +assembleMvariableStatement(mvariableStatement) + mvariableStatementBodyType *mvariableStatement; +{ + identifierListType *newLocalVariable; + int initCount; + bool saveExpansion; + + valueType *createArray(); + int expressionListLength(); + + nullAssemble(mvariableStatement); + expansionOff(); + if (mvariableStatement->theDimension == NULL) { + if ((initCount = expressionListLength(mvariableStatement-> + theValue)) == 1) { + pushBinding(mvariableStatement->theSymbol, + evaluateExpression(mvariableStatement-> + theValue->theExpression, NO_FIXUP), + MVARIABLE_SYMBOL); + } else if (initCount > 1) { + error(TOO_MANY_VARIABLE_INITIALIZERS_ERROR); + } else { + pushBinding(mvariableStatement->theSymbol, NULL, + MVARIABLE_SYMBOL); + } + } else { + pushBinding(mvariableStatement->theSymbol, createArray( + mvariableStatement->theDimension, mvariableStatement-> + theValue), MVARIABLE_SYMBOL); + } + expansionOn(); + newLocalVariable = typeAlloc(identifierListType); + newLocalVariable->theSymbol = mvariableStatement->theSymbol; + newLocalVariable->nextIdentifier = currentLocalVariableList; + currentLocalVariableList = newLocalVariable; +} + + void +assembleMwhileStatement(mwhileStatement) + mwhileStatementBodyType *mwhileStatement; +{ + bool saveListingOn; + + nullAssemble(mwhileStatement); + saveListingOn = listingOn; + while (booleanTest(mwhileStatement->mwhileCondition)) { + assembleBlock(mwhileStatement->mwhileLoop); + listingOn = amExpanding(); + } + listingOn = saveListingOn; +} + + void +assembleOrgStatement(orgStatement) + orgStatementBodyType *orgStatement; +{ + valueType *orgAddress; + bool saveExpansion; + valueType *evaluateExpression(); + + nullAssemble(orgStatement); + targetOffset = 0; + expansionOff(); + orgAddress = evaluateExpression(orgStatement, NO_FIXUP); + expansionOn(); + if (absoluteValue(orgAddress) || relocatableValue(orgAddress)) { + if (relocatableValue(¤tLocationCounter) && + absoluteValue(orgAddress)) { + savedRelocatableCurrentLocationCounter = + currentLocationCounter; + currentCodeMode = ABSOLUTE_BUFFER; + } + currentLocationCounter.kindOfValue = orgAddress->kindOfValue; + currentLocationCounter.value = orgAddress->value; + expand((moreText("org\t0x%x", orgAddress->value), endLine())); + } else { + error(BAD_ORG_ADDRESS_ERROR, valueKindString(orgAddress-> + kindOfValue)); + } + qfree(orgAddress); +} + + void +assemblePerformStatement(performStatement) + performStatementBodyType *performStatement; +{ + void evaluateExpressionStandalone(); + + nullAssemble(performStatement); + sideEffectFlag = FALSE; + evaluateExpressionStandalone(performStatement); + if (!sideEffectFlag) + warning(PERFORM_WITHOUT_SIDE_EFFECT_ERROR); +} + + void +assembleRelStatement(relStatement) + relStatementBodyType *relStatement; +{ + targetOffset = 0; + if (!relocatableValue(¤tLocationCounter)) { + currentLocationCounter = + savedRelocatableCurrentLocationCounter; + currentCodeMode = RELOCATABLE_BUFFER; + } + expand((moreText("rel"), endLine())); + addBreak(BREAK_BREAK, 0); +} + + void +assembleStartStatement(startStatement) + startStatementBodyType *startStatement; +{ + valueType *evaluateExpression(); + addressType addressValue(); + expressionType *generateFixupExpression(); + + nullAssemble(startStatement); + expand(moreText("start\t")); + if (haveUserStartAddress) { + expand((moreText("*fail*"), endLine())); + error(START_ADDRESS_ALREADY_GIVEN_ERROR); + } else { + startAddress = evaluateExpression(startStatement,NO_FIXUP_OK); + if (startAddress->kindOfValue == UNDEFINED_VALUE) { + startAddress = (valueType *)generateFixupExpression( + startStatement); + haveUserStartAddress = TRUE; + fixupStartAddress = TRUE; + } else if (startAddress->kindOfValue != ABSOLUTE_VALUE && + startAddress->kindOfValue!=RELOCATABLE_VALUE){ + expand((moreText("*fail*"), endLine())); + error(BAD_START_ADDRESS_ERROR); + } else { + expand((expandExpression(NULL), endLine())); + haveUserStartAddress = TRUE; + fixupStartAddress = FALSE; + } + } +} + + void +assembleStringStatement(stringStatement) + stringStatementBodyType *stringStatement; +{ + valueType *byteValue; + + valueType *evaluateExpression(); + + nullAssemble(stringStatement); + expand(moreText("string\t")); + while (stringStatement != NULL) { + byteValue = evaluateExpression(stringStatement->theExpression, + BYTE_FIXUP); + if (byteValue->kindOfValue == STRING_VALUE) { + emitString(byteValue->value); + emitByte('\0'); + } else { + putFixupsHere(BYTE_FIXUP, 0); + emitByteValue(byteValue); + } + qfree(byteValue); + stringStatement = stringStatement->nextExpression; + expand((expandExpression(NULL), stringStatement != NULL ? + moreText(", ") : 0)); + } + expand(endLine()); +} + + void +assembleStructStatement(structStatement) + structStatementBodyType *structStatement; +{ + nullAssemble(structStatement); + if (structStatement->structBody == NULL) + instantiateStruct(structStatement); + else + assembleStructDefinition(structStatement); +} + + void +assembleTargetStatement(targetStatement) + targetStatementBodyType *targetStatement; +{ + valueType *targetAddress; + bool saveExpansion; + valueType *evaluateExpression(); + + nullAssemble(targetStatement); + targetOffset = 0; + expansionOff(); + targetAddress = evaluateExpression(targetStatement, NO_FIXUP); + expansionOn(); + if (absoluteValue(targetAddress)) { + expand((moreText("target\t0x%x", targetAddress-> + value), endLine())); + targetOffset = currentLocationCounter.value - + targetAddress->value; + } else { + error(BAD_TARGET_ADDRESS_ERROR, valueKindString( + targetAddress->kindOfValue)); + } + qfree(targetAddress); +} + + void +assembleUndefineStatement(undefineStatement) + undefineStatementBodyType *undefineStatement; +{ + symbolTableEntryType *effectiveSymbol(); + + expand(moreText("undefine\t")); + while (undefineStatement != NULL) { + expand(moreText("%s", symbName(undefineStatement->theSymbol))); + purgeSymbol(effectiveSymbol(undefineStatement->theSymbol, + NULL)); + undefineStatement = undefineStatement->nextIdentifier; + expand(undefineStatement != NULL ? moreText(", ") : 0); + } + expand(endLine()); +} + + void +assembleVariableStatement(variableStatement) + variableStatementBodyType *variableStatement; +{ + symbolTableEntryType *newVariable; + symbolInContextType *contextForVariable; + int initCount; + + symbolTableEntryType *effectiveSymbol(); + valueType *createArray(); + int expressionListLength(); + + nullAssemble(variableStatement); + newVariable = effectiveSymbol(variableStatement->theSymbol, + &contextForVariable); + if (isPotentialVariable(contextForVariable)) { + expand(moreText("variable %s = ", symbName(newVariable))); + if (contextForVariable->usage == DEAD_SYMBOL) { + reincarnateSymbol(contextForVariable, VARIABLE_SYMBOL); + } else if (contextForVariable->usage == NESTED_UNKNOWN_SYMBOL) { + contextForVariable->usage = VARIABLE_SYMBOL; + } + if (alreadyDefined(contextForVariable)) { + error(REDEFINITION_OF_SYMBOL_ERROR, symbName(newVariable)); + } else { + if (variableStatement->theDimension == NULL) { + if ((initCount = expressionListLength(variableStatement-> + theValue)) == 1) { + contextForVariable->value = evaluateExpression( + variableStatement->theValue->theExpression, NO_FIXUP); + expand(expandExpression(NULL)); + } else { + if (initCount > 1) + error(TOO_MANY_VARIABLE_INITIALIZERS_ERROR); + expand(moreText("*fail*")); + contextForVariable->value = newValue(FAIL, 0, + EXPRESSION_OPND); + } + } else { + contextForVariable->value = createArray(variableStatement-> + theDimension, variableStatement->theValue); + } + contextForVariable->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; + contextForVariable->attributes |= DEFINED_VARIABLE_ATT; + } + expand(endLine()); + } else { + error(SYMBOL_ALREADY_THERE_ERROR, symbName(newVariable)); + } +} + + void +assembleWhileStatement(whileStatement) + whileStatementBodyType *whileStatement; +{ + valueType topOfLoop; + valueType fixupLocation[COMPOUND_BRANCH_MAX]; + + nullAssemble(whileStatement); + if (whileStatement->whileCondition == NEVER_COND) { + return; + } else if (whileStatement->whileCondition != ALWAYS_COND) { + emitRelativeBranch(invertConditionCode(whileStatement-> + whileCondition), NULL, fixupLocation); + topOfLoop = currentLocationCounter; + } else { + topOfLoop = currentLocationCounter; + topOfLoop.value -= targetOffset; + } + expand((moreText("while %s {", conditionString(whileStatement-> + whileCondition)), endLine(), tabCount++)); + assembleBlock(whileStatement->whileLoop); + expand((tabCount--, startLineMarked(), tabIndent(), moreText("}"), + endLine())); + if (whileStatement->whileCondition != ALWAYS_COND) { + emitRelativeBranch(whileStatement->whileCondition, &topOfLoop, + NULL); + fixupBranch(fixupLocation, currentLocationCounter); + } else { + emitJump(&topOfLoop, NULL); + } +} + + void +assembleWordStatement(wordStatement) + wordStatementBodyType *wordStatement; +{ + valueType *word; + + valueType *evaluateExpression(); + + nullAssemble(wordStatement); + expand(moreText("word\t")); + while (wordStatement != NULL) { + word = evaluateExpression(wordStatement->theExpression, + WORD_FIXUP); + wordStatement = wordStatement->nextExpression; + expand((expandExpression(NULL), wordStatement != NULL ? + moreText(", ") : 0)); + putFixupsHere(WORD_FIXUP, 0); + emitWordValue(word); + qfree(word); + } + expand(endLine()); +} + + bool +assembleStatementBody(kind, body, cumulativeLineNumber, worryAboutIf, + ifFixupList) + statementKindType kind; + statementBodyType body; + int cumulativeLineNumber; + bool worryAboutIf; + simpleFixupListType **ifFixupList; +{ + bool result; + + result = TRUE; + if (amListing() && kind != INSTRUCTION_STATEMENT && !beneathFunction) + saveIndexForListing(kind, cumulativeLineNumber); + switch (kind) { + + case ALIGN_STATEMENT: + sideEffectBomb(); + assembleAlignStatement(body); + if (amListing()) + saveIndexForListing(ALIGN_STATEMENT, + cumulativeLineNumber); + break; + + case ASSERT_STATEMENT: + assembleAssertStatement(body); + break; + + case BLOCK_STATEMENT: + sideEffectBomb(); + assembleBlockStatement(body); + break; + + case BYTE_STATEMENT: + sideEffectBomb(); + assembleByteStatement(body); + break; + + case CONSTRAIN_STATEMENT: + sideEffectBomb(); + assembleConstrainStatement(body); + break; + + case DBYTE_STATEMENT: + sideEffectBomb(); + assembleDbyteStatement(body); + break; + + case DEFINE_STATEMENT: + sideEffectBomb(); + assembleDefineStatement(body); + break; + + case DO_UNTIL_STATEMENT: + sideEffectBomb(); + assembleDoUntilStatement(body); + break; + + case DO_WHILE_STATEMENT: + sideEffectBomb(); + assembleDoWhileStatement(body); + break; + + case EXTERN_STATEMENT: + sideEffectBomb(); + assembleExternStatement(body); + break; + + case FRETURN_STATEMENT: + assembleFreturnStatement(body); +/* result = FALSE;*/ + break; + + case FUNCTION_STATEMENT: + assembleFunctionStatement(body); + break; + + case GROUP_STATEMENT: + assembleGroupStatement(body); + break; + + case IF_STATEMENT: + sideEffectBomb(); + if (worryAboutIf) { + *ifFixupList = assembleIfStatement(body, worryAboutIf, + *ifFixupList); + } else { + assembleIfStatement(body, worryAboutIf, NULL); + } + break; + + case INCLUDE_STATEMENT: + sideEffectBomb(); + assembleIncludeStatement(body); + break; + + case INSTRUCTION_STATEMENT: + sideEffectBomb(); + assembleInstructionStatement(body, cumulativeLineNumber); + break; + + case LONG_STATEMENT: + sideEffectBomb(); + assembleLongStatement(body); + break; + + case MACRO_STATEMENT: + assembleMacroStatement(body); + break; + + case MDEFINE_STATEMENT: + assembleMdefineStatement(body); + break; + + case MDO_UNTIL_STATEMENT: + assembleMdoUntilStatement(body); + break; + + case MDO_WHILE_STATEMENT: + assembleMdoWhileStatement(body); + break; + + case MFOR_STATEMENT: + assembleMforStatement(body); + break; + + case MIF_STATEMENT: + assembleMifStatement(body, cumulativeLineNumber); + break; + + case MSWITCH_STATEMENT: + assembleMswitchStatement(body); + break; + + case MVARIABLE_STATEMENT: + assembleMvariableStatement(body); + break; + + case MWHILE_STATEMENT: + assembleMwhileStatement(body); + break; + + case NULL_STATEMENT: + nullStatementFlag = TRUE; + expand(labeledLine() ? (startLineMarked(), expandLabel(), + endLine()) : 0); + break; + + case ORG_STATEMENT: + sideEffectBomb(); + assembleOrgStatement(body); + if (amListing()) + saveIndexForListing(ORG_STATEMENT, + cumulativeLineNumber); + break; + + case PERFORM_STATEMENT: + assemblePerformStatement(body); + break; + + case REL_STATEMENT: + sideEffectBomb(); + assembleRelStatement(body); + if (amListing()) + saveIndexForListing(REL_STATEMENT, + cumulativeLineNumber); + break; + + case START_STATEMENT: + assembleStartStatement(body); + break; + + case STRING_STATEMENT: + sideEffectBomb(); + assembleStringStatement(body); + break; + + case STRUCT_STATEMENT: + sideEffectBomb(); + assembleStructStatement(body); + break; + + case TARGET_STATEMENT: + sideEffectBomb(); + assembleTargetStatement(body); + break; + + case UNDEFINE_STATEMENT: + sideEffectBomb(); + assembleUndefineStatement(body); + break; + + case VARIABLE_STATEMENT: + sideEffectBomb(); + assembleVariableStatement(body); + break; + + case WHILE_STATEMENT: + sideEffectBomb(); + assembleWhileStatement(body); + break; + + case WORD_STATEMENT: + sideEffectBomb(); + assembleWordStatement(body); + break; + + default: + botch("assembleStatementBody doesn't know kind %d\n", kind); + break; + } +/* return(result);*/ + return(!freturnExit); +} + + void +assembleLabelList(labelList) + labelListType *labelList; +{ + valueType *newValue(); + + while (labelList != NULL) { + if (structNestingDepth == 0) + valueLabel(labelList->theLabel, + newValue(currentLocationCounter.kindOfValue, + currentLocationCounter.value, + EXPRESSION_OPND)); + else + valueField(labelList->theLabel, newValue(FIELD_VALUE, + currentFieldOffset, EXPRESSION_OPND)); + labelList = labelList->nextLabel; + } +} + + simpleFixupListType * +assembleStatement(statement, insideIf, ongoingFixupList) + statementType *statement; + bool insideIf; + simpleFixupListType *ongoingFixupList; +{ + char *saveFileName; + int saveLineNumber; + int saveCumulativeLineNumber; + simpleFixupListType *result; + + statementEvaluationDepth++; + expand(flushExpressionString()); + saveFileName = currentFileName; + saveLineNumber = currentLineNumber; + result = ongoingFixupList; + while (statement != NULL) { + currentFileName = statement->fileName; + currentLineNumber = statement->lineNumber; + expand(listableStatement(statement->kindOfStatement) ? + startLine() : 0); + assembleLabelList(statement->labels); + expand(listableStatement(statement->kindOfStatement) ? + (expandLabel(), tabIndent()) : 0); + if (assembleStatementBody(statement->kindOfStatement, + statement->statementBody, statement-> + cumulativeLineNumber, insideIf && + isLastStatementInBlock(statement), &result)) { + if (freeFlag && statementEvaluationDepth == 1) + freeStatement(statement); + statement = statement->nextStatement; + } else { + if (freeFlag && statementEvaluationDepth == 1) + freeStatement(statement); + freturnExit = TRUE; + break; + } + } + if (!newIncludeFile) { + currentFileName = saveFileName; + currentLineNumber = saveLineNumber; + } else { + newIncludeFile = FALSE; + } + statementEvaluationDepth--; + return(result); +} + + void +eatStatement(statement) + statementType *statement; +{ + if (debug) { + printf("assembling:\n"); + printStatement(statement); + } + assembleStatement(statement, FALSE, NULL); +} diff --git a/statementSemantics.o b/statementSemantics.o new file mode 100644 index 0000000..f3a3bd3 Binary files /dev/null and b/statementSemantics.o differ diff --git a/structSemantics.c b/structSemantics.c new file mode 100644 index 0000000..efc5d67 --- /dev/null +++ b/structSemantics.c @@ -0,0 +1,156 @@ +/* + structSemantics.c -- Routines to handle struct's for Macross assembler + + Chip Morningstar -- Lucasfilm Ltd. + + 7-December-1984 +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + + void +putStructFixups(base, fixups) + int base; + fixupListType *fixups; +{ + fixupListType *newFixup; + + while (fixups != NULL) { + newFixup = typeAlloc(fixupListType); + newFixup->locationToFixup = base + fixups->locationToFixup; + newFixup->kindOfFixup = fixups->kindOfFixup; + newFixup->theFixupExpression = fixups->theFixupExpression; + if (structNestingDepth == 0) { + newFixup->nextFixup = fixupList; + fixupList = newFixup; + } else { + newFixup->nextFixup = newStruct->structFixups; + newStruct->structFixups = newFixup; + } + fixups = fixups->nextFixup; + } +} + + void +putStructReferences(base, references) + int base; + expressionReferenceListType *references; +{ + expressionReferenceListType *newReference; + int currentMode; + + if (!produceLinkableObject) + return; + + currentMode = structNestingDepth==0 ? (int)currentCodeMode : + STRUCT_BUFFER; + while (references != NULL) { + newReference = typeAlloc(expressionReferenceListType); + newReference->relocation = references->relocation; + newReference->relocation.referenceAddress += base; + newReference->expressionReferenced = references-> + expressionReferenced; + newReference->nextReference = expressionReferenceList[ + currentMode]; + expressionReferenceList[currentMode] = newReference; + references = references->nextReference; + } +} + + void +instantiateStruct(structStatement) + structStatementBodyType *structStatement; +{ + int i; + int base; + symbolInContextType *context; + + symbolInContextType *getWorkingContext(); + +#define structInstance ((structInstanceType *) context->value->value) + + context = getWorkingContext(structStatement->structName); + if (context == NULL) + botch("struct doesn't have working context\n"); + if (context->usage != STRUCT_NAME_SYMBOL) { + error(NOT_A_STRUCT_NAME_ERROR, structStatement->structName-> + symbolName); + } else if (context->value->kindOfValue != STRUCT_VALUE) { + botch("struct name doesn't have struct value\n"); + } else { + expand((moreText("struct\t%s", structStatement->structName-> + symbolName), endLine())); + base = structNestingDepth==0 ? currentLocationCounter.value : + currentFieldOffset; + for (i=0; istructSize; i++) + emitByte(structInstance->structMap[i]); + putStructFixups(base, structInstance->structFixups); + putStructReferences(base, structInstance->structReferences); + } +} + + structInstanceType * +assembleStructDefinitionBody(structBody) + structBodyType *structBody; +{ + int i; + simpleFixupListType *dummy; + + newStruct = typeAlloc(structInstanceType); + newStruct->structFixups = NULL; + currentFieldOffset = 0; + while (structBody != NULL) { + expand(listableStatement(structBody->kindOfStatement) ? + startLine() : 0); + assembleLabelList(structBody->labels); + expand(listableStatement(structBody->kindOfStatement) ? + (expandLabel(), tabIndent()) : 0); + assembleStatementBody(structBody->kindOfStatement, + structBody->statementBody, FALSE, &dummy); + if (currentFieldOffset > MAXIMUM_ALLOWED_STRUCT_SIZE) { + error(STRUCT_TOO_BIG_ERROR); + return(NULL); + } + structBody = (blockType *)structBody->nextStatement; + } + newStruct->structSize = currentFieldOffset; + newStruct->structMap = (byte *)malloc(currentFieldOffset); + newStruct->structReferences = expressionReferenceList[STRUCT_BUFFER]; + for (i=0; istructMap[i] = structScratchBuffer[i]; + return(newStruct); +} + + void +assembleStructDefinition(structStatement) + structStatementBodyType *structStatement; +{ + symbolTableEntryType *name; + symbolInContextType *context; + + symbolTableEntryType *effectiveSymbol(); + + name = effectiveSymbol(structStatement->structName, &context); + if (context == NULL) + botch("struct definition doesn't have working context\n"); + if (context->usage != STRUCT_NAME_SYMBOL) + error(NOT_A_STRUCT_NAME_ERROR, structStatement->structName-> + symbolName); + else if (structNestingDepth > 0) + error(STRUCT_DEFINITION_INSIDE_STRUCT_DEFINITION_ERROR); + else { + structNestingDepth++; + expressionReferenceList[STRUCT_BUFFER] = NULL; + numberOfReferencesInList[STRUCT_BUFFER] = 0; + context->value->kindOfValue = STRUCT_VALUE; + expand((moreText("struct {"), endLine(), tabCount++)); + context->value->value = (int) + assembleStructDefinitionBody(structStatement->structBody); + expand((tabCount--, startLineMarked(), tabIndent(), + moreText("} %s", symbName(structStatement-> + structName)), endLine())); + context->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; + structNestingDepth--; + } +} diff --git a/structSemantics.o b/structSemantics.o new file mode 100644 index 0000000..843e0d4 Binary files /dev/null and b/structSemantics.o differ diff --git a/tokenStrings.o b/tokenStrings.o new file mode 100644 index 0000000..cbc2441 Binary files /dev/null and b/tokenStrings.o differ diff --git a/tokenStrings_6502.c b/tokenStrings_6502.c new file mode 100644 index 0000000..30e1728 --- /dev/null +++ b/tokenStrings_6502.c @@ -0,0 +1,138 @@ +/* + tokenStrings_6502.c -- Target processor dependent string generators + for the Macross assembler (6502 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 23-April-1985 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* conditionString similarly deals with condition codes */ + char * +conditionString(condition) + conditionType condition; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'conditionType' */ + + static char *conditionStringTable[] = { + "(carry)", + "(zero)", + "(minus)", + "(overflow)", + "(lt)", + "(leq)", + "(slt)", + "(sleq)", + "(always)", + "(!carry)", + "(!zero)", + "(plus)", + "(!overflow)", + "(geq)", + "(gt)", + "(sgeq)", + "(sgt)", + "(never)", + }; + return(conditionStringTable[(int)condition]); +} + + +/* tokenString similarly deals with parser tokens */ + + char * +tokenString(token) + int token; +{ +/* This table MUST be maintained congruently with the token definitions in + the file 'y.tab.h' as output by yacc. */ + + static char *tokenTable[] = { + "A", + "ALIGN", + "ASSERT", + "BLOCK", + "BYTE", + "CONSTRAIN", + "DBYTE", + "DEFINE", + "DO", + "ELSE", + "ELSEIF", + "ENDFILE", + "EOL", + "EXTERN", + "FRETURN", + "FUNCTION", + "HERE", + "IF", + "INCLUDE", + "LONG", + "MACRO", + "MCASE", + "MDEFAULT", + "MDEFINE", + "MDO", + "MELSE", + "MELSEIF", + "MFOR", + "MIF", + "MSWITCH", + "MUNTIL", + "MVARIABLE", + "MWHILE", + "ORG", + "REL", + "START", + "STRING", + "STRUCT", + "TARGET", + "UNDEFINE", + "UNTIL", + "VARIABLE", + "WHILE", + "WORD", + "X", + "Y", + "ConditionCode", + "Identifier", + "MacroName", + "Number", + "Opcode", + "TextString", + "Assignment", + "||", + "^^", + "&&", + "|", + "^", + "&", + "==", + "!=", + "<", + "<=", + ">", + ">=", + "<<", + ">>", + "+", + "-", + "*", + "/", + "%", + "-", + "!", + "~", + "?", + "/", + ".", + "++", + "--", + }; + return(tokenTable[token-257]); +} diff --git a/tokenStrings_68000.c b/tokenStrings_68000.c new file mode 100644 index 0000000..6ac0be1 --- /dev/null +++ b/tokenStrings_68000.c @@ -0,0 +1,160 @@ +/* + tokenStrings_68000.c -- Target processor dependent string generators + for the Macross assembler (68000 version). + + Chip Morningstar -- Lucasfilm Ltd. + + 26-April-1985 + +*/ + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +/* conditionString similarly deals with condition codes */ + char * +conditionString(condition) + conditionType condition; +{ +/* This table MUST be maintained congruently with the definition of the + enumerated type 'conditionType' */ + + static char *conditionStringTable[] = { + "(carry)", + "(equal)", + "(overflow)", + "(minus)", + "(lt)", + "(leq)", + "(ls)", + "(always)", + "(!carry)", + "(!equal)", + "(!overflow)", + "(plus)", + "(geq)", + "(gt)", + "(high)", + "(never)", + }; + return(conditionStringTable[(int)condition]); +} + + +/* tokenString similarly deals with parser tokens */ + + char * +tokenString(token) + int token; +{ +/* This table MUST be maintained congruently with the token definitions in + the file 'y.tab.h' as output by yacc. */ + + static char *tokenTable[] = { + "A0", + "A1", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "ALIGN", + "ASSERT", + "BLOCK", + "BYTE", + "CCR", + "CONSTRAIN", + "D0", + "D1", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "DBYTE", + "DEFINE", + "DFC", + "DO", + "ELSE", + "ELSEIF", + "ENDFILE", + "EOL", + "EXTERN", + "FRETURN", + "FUNCTION", + "HERE", + "IF", + "INCLUDE", + "L", + "LONG", + "MACRO", + "MCASE", + "MDEFAULT", + "MDEFINE", + "MDO", + "MELSE", + "MELSEIF", + "MFOR", + "MIF", + "MSWITCH", + "MUNTIL", + "MVARIABLE", + "MWHILE", + "ORG", + "PC", + "REL", + "SFC", + "SR", + "START", + "STRING", + "STRUCT", + "TARGET", + "UNDEFINE", + "UNTIL", + "USP", + "VARIABLE", + "VBR", + "W", + "WHILE", + "WORD", + "X", + "Y", + "ConditionCode", + "Identifier", + "MacroName", + "Number", + "Opcode", + "TextString", + "Assignment", + "||", + "^^", + "&&", + "|", + "^", + "&", + "==", + "!=", + "<", + "<=", + ">", + ">=", + "<<", + ">>", + "+", + "-", + "*", + "/", + "%", + "-", + "!", + "~", + "?", + "/", + ".", + "++", + "--", + }; + return(tokenTable[token-257]); +} diff --git a/y.tab.c b/y.tab.c new file mode 100644 index 0000000..4bc54f3 --- /dev/null +++ b/y.tab.c @@ -0,0 +1,1698 @@ + +# line 10 "macross_6502.y" + +#include "macrossTypes.h" +#include "macrossGlobals.h" + +# define A 257 +# define ALIGN 258 +# define ASSERT 259 +# define BLOCK 260 +# define BYTE 261 +# define CONSTRAIN 262 +# define DBYTE 263 +# define DEFINE 264 +# define DO 265 +# define ELSE 266 +# define ELSEIF 267 +# define ENDFILE 268 +# define EOL 269 +# define EXTERN 270 +# define FRETURN 271 +# define FUNCTION 272 +# define HERE 273 +# define IF 274 +# define INCLUDE 275 +# define LONG 276 +# define MACRO 277 +# define MCASE 278 +# define MDEFAULT 279 +# define MDEFINE 280 +# define MDO 281 +# define MELSE 282 +# define MELSEIF 283 +# define MFOR 284 +# define MIF 285 +# define MSWITCH 286 +# define MUNTIL 287 +# define MVARIABLE 288 +# define MWHILE 289 +# define ORG 290 +# define REL 291 +# define START 292 +# define STRING 293 +# define STRUCT 294 +# define TARGET 295 +# define UNDEFINE 296 +# define UNTIL 297 +# define VARIABLE 298 +# define WHILE 299 +# define WORD 300 +# define X 301 +# define Y 302 +# define ConditionCode 303 +# define Identifier 304 +# define MacroName 305 +# define Number 306 +# define Opcode 307 +# define TextString 308 +# define ASSIGN 309 +# define LOGICAL_OR 310 +# define LOGICAL_XOR 311 +# define LOGICAL_AND 312 +# define BITWISE_OR 313 +# define BITWISE_XOR 314 +# define BITWISE_AND 315 +# define EQUAL_TO 316 +# define NOT_EQUAL_TO 317 +# define LESS_THAN 318 +# define LESS_THAN_OR_EQUAL_TO 319 +# define GREATER_THAN 320 +# define GREATER_THAN_OR_EQUAL_TO 321 +# define LEFT_SHIFT 322 +# define RIGHT_SHIFT 323 +# define ADD 324 +# define SUB 325 +# define MUL 326 +# define DIV 327 +# define MOD 328 +# define UNARY_MINUS 329 +# define LOGICAL_NOT 330 +# define BITWISE_NOT 331 +# define HI_BYTE 332 +# define LO_BYTE 333 +# define SELECT 334 +# define INCREMENT 335 +# define DECREMENT 336 +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 +extern int yychar; +extern short yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +#ifndef YYSTYPE +#define YYSTYPE int +#endif +YYSTYPE yylval, yyval; +# define YYERRCODE 256 +short yyexca[] ={ +-1, 1, + 0, -1, + -2, 0, +-1, 48, + 40, 242, + -2, 200, +-1, 158, + 40, 242, + -2, 200, +-1, 323, + 318, 0, + 319, 0, + 320, 0, + 321, 0, + -2, 222, +-1, 324, + 318, 0, + 319, 0, + 320, 0, + 321, 0, + -2, 223, +-1, 325, + 318, 0, + 319, 0, + 320, 0, + 321, 0, + -2, 224, +-1, 326, + 318, 0, + 319, 0, + 320, 0, + 321, 0, + -2, 225, +-1, 327, + 316, 0, + 317, 0, + -2, 226, +-1, 328, + 316, 0, + 317, 0, + -2, 227, + }; +# define YYNPROD 266 +# define YYLAST 1367 +short yyact[]={ + + 108, 207, 418, 526, 417, 357, 262, 415, 381, 293, + 292, 261, 356, 46, 41, 21, 201, 33, 12, 413, + 20, 183, 303, 19, 18, 343, 142, 245, 202, 17, + 398, 247, 16, 15, 143, 244, 9, 138, 5, 123, + 122, 119, 120, 121, 351, 556, 384, 184, 185, 138, + 555, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 467, 160, 161, 162, 163, 138, 464, 347, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 346, 179, 180, 181, 182, 349, 352, 353, 304, + 216, 419, 186, 187, 188, 189, 190, 191, 192, 193, + 124, 125, 123, 122, 119, 120, 121, 513, 476, 457, + 402, 215, 138, 354, 335, 286, 209, 210, 211, 212, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 205, 110, 199, 126, 128, 127, 129, 124, 125, 123, + 122, 119, 120, 121, 242, 243, 260, 256, 254, 138, + 11, 252, 250, 99, 99, 257, 258, 237, 240, 433, + 106, 431, 213, 358, 359, 239, 419, 264, 388, 432, + 387, 430, 110, 276, 278, 248, 412, 391, 372, 559, + 139, 204, 525, 409, 103, 104, 289, 290, 291, 300, + 294, 295, 259, 296, 297, 3, 298, 299, 99, 85, + 437, 554, 553, 542, 538, 301, 132, 130, 131, 126, + 128, 127, 129, 124, 125, 123, 122, 119, 120, 121, + 314, 311, 313, 241, 536, 138, 502, 312, 501, 336, + 310, 309, 337, 492, 491, 342, 308, 344, 345, 307, + 306, 159, 4, 305, 471, 196, 195, 107, 200, 164, + 300, 470, 350, 360, 361, 362, 363, 364, 365, 366, + 355, 215, 573, 246, 246, 367, 368, 552, 246, 544, + 370, 130, 131, 126, 128, 127, 129, 124, 125, 123, + 122, 119, 120, 121, 532, 378, 379, 531, 530, 138, + 522, 389, 517, 496, 348, 493, 441, 144, 562, 382, + 61, 263, 99, 203, 475, 49, 275, 61, 274, 314, + 311, 313, 268, 266, 197, 70, 312, 165, 151, 310, + 309, 392, 371, 150, 149, 308, 383, 148, 307, 306, + 147, 558, 528, 529, 401, 528, 529, 405, 406, 407, + 408, 410, 411, 414, 421, 422, 423, 146, 208, 424, + 425, 58, 110, 394, 396, 145, 10, 399, 58, 110, + 419, 395, 397, 420, 442, 443, 105, 444, 270, 376, + 102, 86, 448, 101, 100, 450, 194, 141, 451, 452, + 140, 434, 449, 91, 166, 393, 447, 446, 429, 455, + 527, 456, 285, 287, 458, 459, 314, 311, 313, 462, + 199, 61, 465, 312, 468, 454, 310, 309, 152, 152, + 206, 472, 308, 524, 110, 307, 306, 167, 480, 305, + 436, 481, 482, 483, 484, 485, 267, 479, 487, 488, + 489, 490, 478, 255, 253, 416, 474, 288, 91, 251, + 249, 302, 214, 386, 47, 45, 44, 495, 494, 497, + 43, 42, 58, 40, 504, 505, 106, 506, 507, 39, + 38, 509, 510, 37, 390, 512, 36, 35, 34, 265, + 498, 499, 377, 514, 32, 516, 31, 523, 518, 519, + 520, 521, 515, 30, 29, 28, 27, 26, 533, 152, + 25, 534, 61, 24, 535, 23, 22, 537, 14, 539, + 13, 7, 541, 6, 540, 154, 109, 2, 1, 0, + 91, 375, 0, 545, 0, 547, 0, 0, 548, 549, + 0, 0, 550, 269, 0, 271, 272, 273, 0, 0, + 0, 277, 0, 0, 153, 279, 280, 281, 282, 283, + 284, 560, 0, 58, 0, 0, 564, 565, 0, 566, + 0, 0, 0, 567, 0, 0, 568, 569, 0, 571, + 0, 0, 572, 0, 0, 0, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, + 330, 331, 332, 333, 334, 0, 0, 0, 0, 0, + 0, 338, 341, 99, 380, 0, 385, 136, 137, 135, + 133, 134, 132, 130, 131, 126, 128, 127, 129, 124, + 125, 123, 122, 119, 120, 121, 89, 78, 0, 55, + 54, 138, 53, 0, 0, 0, 0, 369, 0, 0, + 0, 0, 0, 0, 0, 83, 0, 0, 373, 374, + 152, 0, 0, 91, 339, 340, 88, 158, 0, 87, + 0, 90, 56, 57, 0, 0, 0, 0, 426, 52, + 428, 0, 0, 315, 0, 0, 0, 0, 92, 61, + 95, 89, 0, 93, 94, 96, 445, 0, 97, 98, + 0, 0, 0, 0, 0, 152, 152, 0, 0, 0, + 0, 400, 0, 0, 403, 0, 0, 0, 0, 0, + 0, 88, 158, 0, 87, 0, 90, 0, 0, 0, + 427, 0, 469, 435, 0, 438, 439, 440, 0, 473, + 58, 0, 477, 92, 91, 95, 99, 155, 93, 94, + 96, 0, 0, 97, 98, 0, 0, 0, 453, 0, + 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 460, 461, 0, 463, 0, 0, + 466, 0, 0, 0, 0, 0, 508, 0, 0, 0, + 511, 156, 157, 88, 158, 110, 87, 0, 90, 134, + 132, 130, 131, 126, 128, 127, 129, 124, 125, 123, + 122, 119, 120, 121, 0, 92, 0, 95, 0, 138, + 93, 94, 96, 91, 500, 97, 98, 99, 503, 0, + 543, 0, 0, 0, 0, 0, 136, 137, 135, 133, + 134, 132, 130, 131, 126, 128, 127, 129, 124, 125, + 123, 122, 119, 120, 121, 486, 0, 0, 0, 0, + 138, 0, 0, 557, 0, 0, 561, 0, 563, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, + 0, 78, 82, 55, 54, 81, 53, 62, 51, 0, + 0, 198, 546, 76, 68, 67, 89, 49, 75, 83, + 66, 551, 0, 63, 72, 0, 99, 73, 70, 74, + 0, 65, 71, 79, 80, 77, 56, 57, 84, 69, + 0, 64, 50, 52, 0, 0, 88, 48, 60, 87, + 59, 90, 154, 0, 0, 570, 0, 91, 0, 0, + 0, 238, 0, 0, 154, 0, 0, 0, 92, 91, + 95, 0, 0, 93, 94, 96, 0, 0, 97, 98, + 8, 153, 78, 82, 55, 54, 81, 53, 62, 51, + 0, 0, 0, 153, 76, 68, 67, 89, 49, 75, + 83, 66, 0, 0, 63, 72, 0, 0, 73, 70, + 74, 0, 65, 71, 79, 80, 77, 56, 57, 84, + 69, 0, 64, 50, 52, 0, 0, 88, 48, 60, + 87, 59, 90, 0, 0, 0, 0, 0, 0, 0, + 99, 0, 0, 0, 0, 0, 0, 0, 0, 92, + 0, 95, 99, 0, 93, 94, 96, 0, 0, 97, + 98, 78, 82, 55, 54, 81, 53, 62, 51, 0, + 0, 0, 0, 76, 68, 67, 89, 49, 75, 83, + 66, 0, 0, 63, 72, 0, 0, 73, 70, 74, + 0, 65, 71, 79, 80, 77, 56, 57, 84, 69, + 91, 64, 50, 52, 0, 0, 88, 48, 60, 87, + 59, 90, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 404, 0, 0, 0, 92, 0, + 95, 0, 0, 93, 94, 96, 0, 0, 97, 98, + 0, 136, 137, 135, 133, 134, 132, 130, 131, 126, + 128, 127, 129, 124, 125, 123, 122, 119, 120, 121, + 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, + 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, + 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 156, 157, + 88, 158, 0, 87, 0, 90, 0, 0, 0, 0, + 156, 157, 88, 158, 0, 87, 0, 90, 0, 0, + 0, 0, 92, 0, 95, 0, 0, 93, 94, 96, + 0, 0, 97, 98, 92, 0, 95, 0, 0, 93, + 94, 96, 0, 0, 97, 98, 136, 137, 135, 133, + 134, 132, 130, 131, 126, 128, 127, 129, 124, 125, + 123, 122, 119, 120, 121, 0, 0, 0, 0, 0, + 138, 137, 135, 133, 134, 132, 130, 131, 126, 128, + 127, 129, 124, 125, 123, 122, 119, 120, 121, 0, + 0, 0, 0, 0, 138, 135, 133, 134, 132, 130, + 131, 126, 128, 127, 129, 124, 125, 123, 122, 119, + 120, 121, 0, 89, 0, 0, 0, 138, 133, 134, + 132, 130, 131, 126, 128, 127, 129, 124, 125, 123, + 122, 119, 120, 121, 0, 0, 0, 0, 0, 138, + 0, 0, 0, 88, 158, 0, 87, 0, 90, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 92, 0, 95, 0, 0, + 93, 94, 96, 0, 0, 97, 98 }; +short yypact[]={ + + -63,-1000, 694,-1000, -75,-1000,-1000,-1000, -73, 773, +-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, +-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, +-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, +-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, 199, -87, + -87, -87, -87, -87, -87, -87, -87, -87, 926, 899, + 899,-1000, -87, -87, -87, -87,-1000,-1000, 408, -87, + -87, -87, -87, -87, -87, -87, -87, -87, -87, -87, +-1000, -87, -87, -87, -87,-288,-1000,-1000,-1000,-1000, +-1000, -87, -87, -87, -87, -87, -87, -87, -87,-1000, + 165, 164, 284, 613,-1000,-1000,-1000, 200, 273, -78, +-1000, 273, 85, 408, 408, 408, 408, 408, -33, -87, + -87, -87, -87, -87, -87, -87, -87, -87, -87, -87, + -87, -87, -87, -87, -87, -87, -87, -87, -87,-1000, + 887, 189,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, +-1000,-1000, 926, -87, -87,-1000, -56, -60,-1000,-1000, +-142,-143,-146,-147, -87, -87,-1000, 926,-148, 271, + 271, 85, 283, 282, 408,-148, 408, 408, 408, 278, + 276, 408, 408, -87,-1000,-1000, 408, 408, 408, 408, + 408, 408,-189,-189, 694, -87, -87, -87,-1000,-1000, +-1000, -66, -87, -87,-1000, -87, -87, 216, 926, 216, + 216, 216, 216,-1000, -87,-1000, 369, 408, 408, 408, + 408, 408, 408, 408, 408, 408, 408, 408, 408, 408, + 408, 408, 408, 408, 408, 408,-190,-1000, -87,-1000, +-1000, -87, 353, 408, -87,-309, -87, -87,-309,-1000, +-228,-1000,-240,-1000, -5,-1000, -47,-217,-191, 226, +-1000,-109, -87, -87, -87, -87, -87, -87, -87, 926, + 226, 926, 926, 926, -87, -87, 216, 926, 408, 516, +-297,-297,-297,-297,-297,-1000,-1000,-1000, 63, 408, + 408, 480,-1000,-1000, -87, -87, 85, 6, 85,-119, + -87,-193, 62,-1000,-1000, 369,-1000,-1000,-1000,-1000, +-1000,-1000,-1000,-1000,-1000, 199,-297,-297,-297,-267, +-267,-285,-285,-222,-222,-222,-222,-175,-175, -35, + 475, -99, 995, 950, 973,-1000, 899, 899, 926, -61, +-1000, 926, 408, -87,-194,1030, -87, -87, -87, 100, + -87, 93,-128,-128, -87, -87,-1000,-1000, -87, -87, + 85, 408, 85,-118, 408, 87, 408, 408, 408, 926, + 265, 694,-1000, 516, 516,-1000, -87,-1000, 41, 273, +-1000, -87,-1000, 6, -87,-1000,-1000, -87, -87, 408, +-1000,-1000, 369,-1000,-1000,-1000,-1000,-1000, -87,-309, + 516,-195,-1000, 516, -87, 408, 408, 408, 408,-241, + 408, 408,-247, -87, 85,-1000, 217,-1000,-1000, 163, + -87, 85, 274,-196, 40, 271,-1000, 516,-1000,-1000, + -87, -87, -87, -87, -87, 801,-1000, -87, 516, 516, + 516,-1000, 151, 150, 264,-1000,-1000, -66, 262,-1000, + 6, 273, 273, 926,-1000, 408, 145,-1000, 143, 408, + 926, 926, 216, 516, -87, 216, 516, -87, 85,-1000, + -87, -87, 85,-1000, -87, 66,-1000,-1000,-1000,-109, + 261, 271, 271, 271, 271, 259, -87, 67, 257, 256, + 253,-1000,-1000,-1000,-1000,-1000,-1000, -87,-1000,-1000, + 516,-1000,-1000, 516, 141, 408, 121, 408,-1000,-213, + 120,-1000, 85,-1000, 238,-1000,-1000,-1000,-1000,-1000, +-1000,-1000, -87, 408, -87,-1000,-1000, -87, -87,-1000, +-1000, -87, 408, 236, 119, 118,-259, 216,-264, 216, +-1000,-1000,-1000,-1000,-1000, 85, 297, 64, 85, 268, + 85, 926,-1000,-1000,-1000, -87, -87,-1000, -87,-1000, +-1000,-1000, -87,-1000, 408, 408, 408, 408, 216, 216, + 926, 155, 231,-1000 }; +short yypgo[]={ + + 0, 518, 517, 252, 0, 516, 38, 513, 511, 36, + 366, 160, 18, 510, 508, 33, 32, 29, 24, 23, + 20, 15, 506, 505, 503, 500, 497, 496, 495, 494, + 493, 486, 484, 17, 478, 477, 476, 473, 470, 469, + 463, 14, 461, 460, 456, 455, 13, 454, 16, 10, + 9, 28, 307, 8, 453, 1, 358, 172, 452, 451, + 22, 89, 190, 450, 449, 259, 19, 7, 446, 202, + 445, 4, 2, 444, 443, 11, 12, 5, 6, 436, + 430, 423, 3, 400, 398, 394, 391, 390, 387, 26, + 34, 386, 27, 384, 383, 209, 381, 380, 379, 365, + 357, 340, 337, 334, 333, 328 }; +short yyr1[]={ + + 0, 1, 1, 2, 4, 4, 5, 5, 3, 3, + 6, 6, 6, 6, 7, 8, 9, 9, 11, 11, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 12, 12, 12, 48, + 51, 53, 53, 53, 49, 50, 50, 50, 50, 13, + 14, 54, 54, 15, 46, 55, 55, 44, 45, 45, + 16, 17, 18, 19, 21, 21, 57, 58, 59, 59, + 60, 60, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 20, 23, 23, 23, 23, 24, 25, 63, 63, + 64, 64, 29, 29, 29, 29, 65, 66, 30, 32, + 69, 69, 68, 68, 67, 67, 67, 70, 70, 71, + 72, 27, 73, 73, 73, 73, 73, 28, 74, 74, + 74, 74, 74, 26, 33, 33, 33, 75, 78, 76, + 77, 77, 77, 77, 37, 79, 80, 80, 81, 81, + 82, 83, 83, 34, 35, 84, 84, 84, 84, 31, + 31, 85, 36, 86, 38, 39, 40, 41, 42, 47, + 43, 22, 62, 62, 87, 87, 87, 87, 87, 88, + 88, 88, 88, 89, 52, 91, 92, 92, 93, 93, + 94, 95, 95, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 96, 96, 97, 98, 90, 90, 90, 90, 90, 90, + 90, 99, 100, 101, 102, 102, 102, 103, 103, 103, + 103, 103, 103, 104, 104, 105 }; +short yyr2[]={ + + 0, 4, 1, 0, 1, 0, 1, 2, 1, 3, + 1, 1, 2, 1, 2, 1, 1, 2, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 4, 4, 3, + 5, 1, 2, 5, 3, 3, 3, 4, 4, 5, + 5, 3, 3, 3, 3, 1, 4, 9, 8, 7, + 3, 3, 3, 3, 3, 5, 1, 3, 1, 3, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 2, 1, 2, 1, 3, 1, 4, + 1, 4, 7, 6, 7, 6, 0, 1, 8, 3, + 1, 4, 2, 3, 1, 4, 1, 1, 4, 4, + 1, 3, 1, 4, 6, 9, 6, 3, 1, 4, + 6, 9, 6, 3, 3, 4, 4, 3, 5, 3, + 3, 3, 4, 4, 5, 5, 5, 3, 1, 3, + 3, 7, 1, 5, 5, 3, 3, 3, 3, 1, + 2, 1, 9, 7, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 2, 4, 2, 4, 1, + 4, 2, 4, 1, 4, 0, 3, 4, 6, 6, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, + 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 2, 2, 3, 3, + 4, 6, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 3, 1, 1, 1, 6, 6, 2, + 2, 3, 3, 8, 4, 8 }; +short yychk[]={ + +-1000, -1, -2, 268, -3, -6, -7, -8, 256, -9, + -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, + -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, + -30, -31, -32, -33, -34, -35, -36, -37, -38, -39, + -40, -41, -42, -43, -44, -45, -46, -47, 304, 274, + 299, 265, 300, 263, 261, 260, 293, 294, -56, 307, + 305, -52, 264, 280, 298, 288, 277, 272, 271, 296, + 285, 289, 281, 284, 286, 275, 270, 292, 258, 290, + 291, 262, 259, 276, 295, -95, -96, 306, 303, 273, + 308, 40, 325, 330, 331, 327, 332, 335, 336, 123, + -93, -94, -97, 269, 268, -10, -11, 58, -4, -5, + 269, -4, -4, -4, -4, -4, -4, -4, -4, 326, + 327, 328, 325, 324, 322, 323, 318, 320, 319, 321, + 316, 317, 315, 313, 314, 312, 310, 311, 334, -62, + -87, -88, -89, -90, -52, -99,-100,-101,-102,-103, +-104,-105, -56, 64, 35, 257, 301, 302, 304, -62, + -4, -4, -4, -4, -65, -65, -85, -56, -4, -4, + -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, + -4, -4, -4, 309, 335, 336, -4, -4, -4, -4, + -4, -4, -4, -4, -91, 91, 91, 40, 268, -6, + 58, -48, -51, 40, 269, -51, -52, -55, -56, -55, + -55, -55, -55, -57, -58, 304, 123, -4, -4, -4, + -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, + -4, -4, -4, -4, -4, -4, -4, -89, 44, -90, + -89, 44, -4, -4, 91, -92, 334, 91, -92, -63, + 304, -64, 304, -73, 304, -74, 304, -4, -4, -69, + 304, -75, -78, 40, -78, -52, 40, -79, 40, -56, + -69, -56, -56, -56, 40, 40, -55, -56, -4, -56, + -56, -56, -56, -56, -56, -95, 304, -95, -3, -4, + -4, -4, -49, -50, 266, 267, -4, -4, -4, -4, + 44, -4, -59, -60, -61, -9, -15, -16, -17, -18, + -19, -41, -20, -21, -46, 304, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, 304, -4, -4, -56, 301, + 302, -56, -4, 334, -4, -4, 309, 309, 309, 91, + 309, 91, 304, 305, 304, 44, -76, -77, 282, 283, + -4, -4, -4, -4, -4, -4, -4, -4, -4, -56, + -4, 269, 125, -56, -56, 41, -98, -62, -4, -4, + -52, -53, 303, 330, 40, -52, -54, 299, 297, -4, + -57, 125, 269, -61, -89, -90, -89, -90, 91, -92, + -56, -4, 304, -56, 64, -4, -4, -4, -4, 93, + -4, -4, 93, -66, -4, -67, -70, -71, -72, 304, + -66, -4, -4, -4, -4, -4, -52, -56, -52, -84, + 299, 289, 297, 287, -86, -56, -80, 123, -56, -56, + -56, 41, -4, -4, -4, -52, -12, -48, -4, -53, + -4, -4, -4, -56, -60, -4, -4, 304, -4, -4, + -56, -56, -55, -56, 309, -55, -56, 309, -4, -52, + 44, 91, -4, -52, -68, 40, 304, -52, -33, -75, + -4, -4, -4, -4, -4, -4, 44, -4, -4, -4, + -4, 93, 93, 41, -49, -50, 41, -53, -51, -51, + -56, 93, 93, -56, -4, -4, -4, -4, -52, -4, + -4, -52, -4, 41, -67, -76, -77, 41, -78, -78, + -78, -78, 41, -4, -81, 125, -82, -83, 278, 279, + 41, 41, 41, -4, -4, -4, 93, -55, 93, -55, + -71, -72, 93, -52, 41, -4, -56, -4, -4, -4, + -4, -56, 41, 93, 93, 309, 309, -52, 44, 125, + -82, -52, 40, -52, -4, -4, -4, -4, -55, -55, + -56, -55, -4, 41 }; +short yydef[]={ + + 3, -2, 101, 2, 0, 8, 10, 11, 13, 101, + 15, 16, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, -2, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 181, 102, + 104, 106, 5, 5, 5, 5, 116, 116, 169, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 180, 5, 5, 5, 5, 203, 204, 205, 206, 207, + 208, 5, 5, 5, 5, 5, 5, 5, 5, 195, + 201, 202, 0, 101, 12, 14, 17, 18, 0, 4, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 103, + 182, 183, 184, 189, 193, 244, 245, 246, 247, 248, + 249, 250, 251, 5, 5, 254, 255, 256, -2, 105, + 0, 0, 0, 0, 5, 5, 170, 171, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 236, 237, 0, 0, 0, 0, + 0, 0, 0, 0, 101, 5, 5, 5, 1, 9, + 19, 56, 5, 5, 7, 5, 5, 73, 75, 80, + 81, 82, 83, 84, 5, 86, 101, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 185, 5, 191, + 187, 5, 0, 0, 5, 259, 5, 5, 260, 107, + 108, 143, 110, 131, 132, 137, 138, 0, 0, 119, + 120, 144, 5, 5, 5, 5, 5, 5, 5, 174, + 175, 176, 177, 178, 5, 5, 74, 179, 0, 5, + 210, 211, 212, 213, 214, 238, 200, 239, 0, 0, + 0, 0, 57, 58, 5, 5, 0, 0, 0, 0, + 5, 0, 0, 88, 90, 101, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 0, 215, 216, 217, 218, + 219, 220, 221, -2, -2, -2, -2, -2, -2, 228, + 229, 230, 231, 232, 233, 234, 0, 0, 252, 261, + 262, 253, 0, 5, 0, 0, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 145, 146, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, + 0, 101, 194, 5, 5, 240, 5, 243, 0, 0, + 59, 5, 61, 0, 5, 69, 70, 5, 5, 0, + 85, 87, 101, 91, 186, 192, 188, 190, 5, 264, + 5, 0, 196, 5, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 0, 117, 124, 126, 127, 130, + 5, 0, 0, 0, 0, 0, 147, 5, 163, 164, + 5, 5, 5, 5, 5, 0, 154, 5, 5, 5, + 5, 209, 0, 0, 0, 64, 65, 66, 0, 62, + 0, 0, 0, 76, 89, 0, 0, 197, 0, 0, + 109, 111, 133, 5, 5, 139, 5, 5, 0, 113, + 5, 5, 0, 115, 5, 0, 121, 149, 150, 151, + 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, + 0, 199, 198, 241, 67, 68, 60, 5, 71, 72, + 5, 257, 258, 5, 0, 0, 0, 0, 112, 0, + 0, 114, 0, 122, 0, 152, 153, 148, 165, 166, + 167, 168, 5, 0, 5, 157, 158, 5, 5, 162, + 155, 5, 79, 0, 0, 0, 134, 136, 140, 142, + 125, 128, 129, 118, 123, 0, 0, 0, 0, 0, + 0, 78, 63, 263, 265, 5, 5, 172, 5, 156, + 159, 160, 5, 77, 0, 0, 0, 0, 135, 141, + 173, 5, 0, 161 }; +#ifndef lint +static char yaccpar_sccsid[] = "@(#)yaccpar 1.1 83/07/20 SMI"; /* from UCB 4.1 83/02/11 */ +#endif + +# +# define YYFLAG -1000 +# define YYERROR goto yyerrlab +# define YYACCEPT return(0) +# define YYABORT return(1) + +/* parser for yacc output */ + +#ifdef YYDEBUG +int yydebug = 0; /* 1 for debugging */ +#endif +YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */ +int yychar = -1; /* current input token number */ +int yynerrs = 0; /* number of errors */ +short yyerrflag = 0; /* error recovery flag */ + +yyparse() { + + short yys[YYMAXDEPTH]; + short yyj, yym; + register YYSTYPE *yypvt; + register short yystate, *yyps, yyn; + register YYSTYPE *yypv; + register short *yyxi; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyps= &yys[-1]; + yypv= &yyv[-1]; + + yystack: /* put a state and value onto the stack */ + +#ifdef YYDEBUG + if( yydebug ) printf( "state %d, char 0%o\n", yystate, yychar ); +#endif + if( ++yyps> &yys[YYMAXDEPTH] ) { yyerror( "yacc stack overflow" ); return(1); } + *yyps = yystate; + ++yypv; + *yypv = yyval; + + yynewstate: + + yyn = yypact[yystate]; + + if( yyn<= YYFLAG ) goto yydefault; /* simple state */ + + if( yychar<0 ) if( (yychar=yylex())<0 ) yychar=0; + if( (yyn += yychar)<0 || yyn >= YYLAST ) goto yydefault; + + if( yychk[ yyn=yyact[ yyn ] ] == yychar ){ /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if( yyerrflag > 0 ) --yyerrflag; + goto yystack; + } + + yydefault: + /* default state action */ + + if( (yyn=yydef[yystate]) == -2 ) { + if( yychar<0 ) if( (yychar=yylex())<0 ) yychar = 0; + /* look through exception table */ + + for( yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=yystate) ; yyxi += 2 ) ; /* VOID */ + + while( *(yyxi+=2) >= 0 ){ + if( *yyxi == yychar ) break; + } + if( (yyn = yyxi[1]) < 0 ) return(0); /* accept */ + } + + if( yyn == 0 ){ /* error */ + /* error ... attempt to resume parsing */ + + switch( yyerrflag ){ + + case 0: /* brand new error */ + + yyerror( "syntax error" ); + yyerrlab: + ++yynerrs; + + case 1: + case 2: /* incompletely recovered error ... try again */ + + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + + while ( yyps >= yys ) { + yyn = yypact[*yyps] + YYERRCODE; + if( yyn>= 0 && yyn < YYLAST && yychk[yyact[yyn]] == YYERRCODE ){ + yystate = yyact[yyn]; /* simulate a shift of "error" */ + goto yystack; + } + yyn = yypact[*yyps]; + + /* the current yyps has no shift onn "error", pop stack */ + +#ifdef YYDEBUG + if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] ); +#endif + --yyps; + --yypv; + } + + /* there is no state on the stack with an error shift ... abort */ + + yyabort: + return(1); + + + case 3: /* no shift yet; clobber input char */ + +#ifdef YYDEBUG + if( yydebug ) printf( "error recovery discards char %d\n", yychar ); +#endif + + if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */ + yychar = -1; + goto yynewstate; /* try again in the same state */ + + } + + } + + /* reduction by production yyn */ + +#ifdef YYDEBUG + if( yydebug ) printf("reduce %d\n",yyn); +#endif + yyps -= yyr2[yyn]; + yypvt = yypv; + yypv -= yyr2[yyn]; + yyval = yypv[1]; + yym=yyn; + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyj = yypgo[yyn] + *yyps + 1; + if( yyj>=YYLAST || yychk[ yystate = yyact[yyj] ] != -yyn ) yystate = yyact[yypgo[yyn]]; + switch(yym){ + +case 1: +# line 64 "macross_6502.y" +{ + yyval = yypvt[-2]; +} break; +case 2: +# line 68 "macross_6502.y" +{ + yyval = 0; +} break; +case 3: +# line 74 "macross_6502.y" +{ + statementListNestingDepth = 0; + errorFlag = FALSE; +} break; +case 6: +# line 87 "macross_6502.y" +{ + if (amListing()) + saveEOLForListing(); +} break; +case 7: +# line 92 "macross_6502.y" +{ + if (amListing()) + saveEOLForListing(); +} break; +case 8: +# line 99 "macross_6502.y" +{ + if (statementListNestingDepth == 0) { + yyval = eatStatement(yypvt[-0]); + } else { + yyval = buildStatementList(yypvt[-0], NULL); + } +} break; +case 9: +# line 107 "macross_6502.y" +{ + if (statementListNestingDepth == 0) { + yyval = eatStatement(yypvt[-0]); + } else { + yyval = buildStatementList(yypvt[-0], yypvt[-2]); + } +} break; +case 12: +# line 119 "macross_6502.y" +{ + yyval = NULL; + YYACCEPT; +} break; +case 13: +# line 124 "macross_6502.y" +{ + yyerrok; + yyclearin; + resynchronizeInput(); + yyval = NULL; +} break; +case 14: +# line 134 "macross_6502.y" +{ + yyval = addLabelToStatement(yypvt[-1], yypvt[-0]); +} break; +case 16: +# line 144 "macross_6502.y" +{ + yyval = buildLabelList(yypvt[-0], NULL); +} break; +case 17: +# line 148 "macross_6502.y" +{ + yyval = buildLabelList(yypvt[-0], yypvt[-1]); +} break; +case 18: +# line 154 "macross_6502.y" +{ + yyval = lookupOrEnterSymbol(yypvt[-1], LABEL_SYMBOL); +} break; +case 19: +# line 158 "macross_6502.y" +{ + yyval = lookupOrEnterSymbol(yypvt[-2], LABEL_SYMBOL); + addAttributeToSymbol(yyval, TENTATIVE_GLOBAL_ATT); +} break; +case 56: +# line 204 "macross_6502.y" +{ + yyval = buildIfStatement(yypvt[-0], NULL, NO_CONTINUATION); +} break; +case 57: +# line 208 "macross_6502.y" +{ + yyval = buildIfStatement(yypvt[-1], yypvt[-0], ELSE_CONTINUATION); +} break; +case 58: +# line 212 "macross_6502.y" +{ + yyval = buildIfStatement(yypvt[-1], yypvt[-0], ELSEIF_CONTINUATION); +} break; +case 59: +# line 218 "macross_6502.y" +{ + yyval = buildIfHead(yypvt[-2], yypvt[-0]); +} break; +case 60: +# line 224 "macross_6502.y" +{ + yyval = yypvt[-2]; +} break; +case 62: +# line 232 "macross_6502.y" +{ + yyval = invertConditionCode(yypvt[-0]); +} break; +case 63: +# line 236 "macross_6502.y" +{ + yyval = yypvt[-2]; +} break; +case 64: +# line 242 "macross_6502.y" +{ + yyval = yypvt[-0]; +} break; +case 65: +# line 248 "macross_6502.y" +{ + yyval = extractIfBody(yypvt[-0]); +} break; +case 66: +# line 252 "macross_6502.y" +{ + yyval = extractIfBody(buildIfStatement(yypvt[-0], NULL, NO_CONTINUATION)); +} break; +case 67: +# line 256 "macross_6502.y" +{ + yyval = extractIfBody(buildIfStatement(yypvt[-1], yypvt[-0], ELSE_CONTINUATION)); +} break; +case 68: +# line 260 "macross_6502.y" +{ + yyval = extractIfBody(buildIfStatement(yypvt[-1], yypvt[-0], ELSEIF_CONTINUATION)); +} break; +case 69: +# line 266 "macross_6502.y" +{ + yyval = buildWhileStatement(yypvt[-2], yypvt[-0]); +} break; +case 70: +# line 272 "macross_6502.y" +{ + yyval = buildDoStatement(yypvt[-2], yypvt[-0]); +} break; +case 71: +# line 278 "macross_6502.y" +{ + yyval = buildDoEnd(yypvt[-0], WHILE_END); +} break; +case 72: +# line 282 "macross_6502.y" +{ + yyval = buildDoEnd(yypvt[-0], UNTIL_END); +} break; +case 73: +# line 288 "macross_6502.y" +{ + yyval = buildWordStatement(yypvt[-0]); +} break; +case 74: +# line 294 "macross_6502.y" +{ + yyval = buildLongStatement(yypvt[-0]); +} break; +case 75: +# line 300 "macross_6502.y" +{ + yyval = buildExpressionList(yypvt[-0], NULL); +} break; +case 76: +# line 304 "macross_6502.y" +{ + yyval = buildExpressionList(yypvt[-0], yypvt[-3]); +} break; +case 77: +# line 311 "macross_6502.y" +{ + yyval = buildConstrainStatement(yypvt[-4], yypvt[-0]); +} break; +case 78: +# line 318 "macross_6502.y" +{ + yyval = buildAssertStatement(yypvt[-3], yypvt[-0]); +} break; +case 79: +# line 322 "macross_6502.y" +{ + yyval = buildAssertStatement(yypvt[-2], NULL); +} break; +case 80: +# line 328 "macross_6502.y" +{ + yyval = buildDbyteStatement(yypvt[-0]); +} break; +case 81: +# line 334 "macross_6502.y" +{ + yyval = buildByteStatement(yypvt[-0]); +} break; +case 82: +# line 340 "macross_6502.y" +{ + yyval = buildBlockStatement(yypvt[-0]); +} break; +case 83: +# line 347 "macross_6502.y" +{ + yyval = buildStringStatement(yypvt[-0]); +} break; +case 84: +# line 354 "macross_6502.y" +{ + yyval = buildStructStatement(yypvt[-0], NULL); +} break; +case 85: +# line 358 "macross_6502.y" +{ + yyval = buildStructStatement(yypvt[-0], yypvt[-2]); +} break; +case 86: +# line 364 "macross_6502.y" +{ + yyval = lookupOrEnterSymbol(yypvt[-0], STRUCT_NAME_SYMBOL); +} break; +case 87: +# line 370 "macross_6502.y" +{ + yyval = yypvt[-1]; +} break; +case 88: +# line 377 "macross_6502.y" +{ + yyval = buildStatementList(yypvt[-0], NULL); +} break; +case 89: +# line 381 "macross_6502.y" +{ + yyval = buildStatementList(yypvt[-0], yypvt[-2]); +} break; +case 91: +# line 389 "macross_6502.y" +{ + yyval = addLabelToStatement(yypvt[-1], yypvt[-0]); +} break; +case 101: +# line 407 "macross_6502.y" +{ + yyval = buildNullStatement(); +} break; +case 102: +# line 414 "macross_6502.y" +{ + yyval = buildInstructionStatement(yypvt[-0], NULL); +} break; +case 103: +# line 418 "macross_6502.y" +{ + yyval = buildInstructionStatement(yypvt[-1], yypvt[-0]); +} break; +case 104: +# line 422 "macross_6502.y" +{ + yyval = buildMacroInstructionStatement(yypvt[-0], NULL); +} break; +case 105: +# line 426 "macross_6502.y" +{ + yyval = buildMacroInstructionStatement(yypvt[-1], yypvt[-0]); +} break; +case 106: +# line 432 "macross_6502.y" +{ + yyval = buildGroupStatement(yypvt[-0]); +} break; +case 107: +# line 438 "macross_6502.y" +{ + yyval = yypvt[-0]; +} break; +case 108: +# line 445 "macross_6502.y" +{ + yyval = buildDefineStatement(yypvt[-0], UNASSIGNED); +} break; +case 109: +# line 449 "macross_6502.y" +{ + checkDefineAssignmentOperator(yypvt[-2]); + yyval = buildDefineStatement(yypvt[-3], yypvt[-0]); +} break; +case 110: +# line 457 "macross_6502.y" +{ + yyval = buildMdefineStatement(yypvt[-0], UNASSIGNED); +} break; +case 111: +# line 461 "macross_6502.y" +{ + checkDefineAssignmentOperator(yypvt[-2]); + yyval = buildMdefineStatement(yypvt[-3], yypvt[-0]); +} break; +case 112: +# line 469 "macross_6502.y" +{ + yyval = buildMacroStatement(createMacro(yypvt[-3]), yypvt[-2], yypvt[-0]); + popMacroOrFunctionNestingDepth(); +} break; +case 113: +# line 474 "macross_6502.y" +{ + yyval = buildMacroStatement(createMacro(yypvt[-2]), NULL, yypvt[-0]); + popMacroOrFunctionNestingDepth(); +} break; +case 114: +# line 479 "macross_6502.y" +{ + yyval = buildMacroStatement(yypvt[-3], yypvt[-2], yypvt[-0]); + popMacroOrFunctionNestingDepth(); +} break; +case 115: +# line 484 "macross_6502.y" +{ + yyval = buildMacroStatement(yypvt[-2], NULL, yypvt[-0]); + popMacroOrFunctionNestingDepth(); +} break; +case 116: +# line 491 "macross_6502.y" +{ + pushMacroOrFunctionNestingDepth(); +} break; +case 118: +# line 499 "macross_6502.y" +{ + yyval = buildFunctionStatement(yypvt[-4], yypvt[-2], yypvt[-0]); + popMacroOrFunctionNestingDepth(); +} break; +case 119: +# line 507 "macross_6502.y" +{ + yyval = buildUndefineStatement(yypvt[-0]); +} break; +case 120: +# line 513 "macross_6502.y" +{ + yyval = buildIdentifierList(yypvt[-0], NULL, unknownSymbolTag); +} break; +case 121: +# line 517 "macross_6502.y" +{ + yyval = buildIdentifierList(yypvt[-0], yypvt[-3], unknownSymbolTag); +} break; +case 122: +# line 523 "macross_6502.y" +{ + yyval = NULL; +} break; +case 123: +# line 527 "macross_6502.y" +{ + yyval = yypvt[-1]; +} break; +case 124: +# line 533 "macross_6502.y" +{ + yyval = yypvt[-0]; +} break; +case 125: +# line 537 "macross_6502.y" +{ + yyval = buildArgumentList(yypvt[-0], yypvt[-3], TRUE); +} break; +case 126: +# line 541 "macross_6502.y" +{ + yyval = buildArgumentList(yypvt[-0], NULL, TRUE); +} break; +case 127: +# line 548 "macross_6502.y" +{ + yyval = buildArgumentList(yypvt[-0], NULL, FALSE); +} break; +case 128: +# line 552 "macross_6502.y" +{ + yyval = buildArgumentList(yypvt[-0], yypvt[-3], FALSE); +} break; +case 131: +# line 565 "macross_6502.y" +{ + yyval = yypvt[-0]; +} break; +case 132: +# line 572 "macross_6502.y" +{ + yyval = buildVariableStatement(yypvt[-0], UNASSIGNED, NULL); +} break; +case 133: +# line 576 "macross_6502.y" +{ + checkDefineAssignmentOperator(yypvt[-2]); + yyval = buildVariableStatement(yypvt[-3], yypvt[-0], NULL); +} break; +case 134: +# line 581 "macross_6502.y" +{ + yyval = buildVariableStatement(yypvt[-5], UNASSIGNED, yypvt[-2]); +} break; +case 135: +# line 585 "macross_6502.y" +{ + checkDefineAssignmentOperator(yypvt[-7]); + yyval = buildVariableStatement(yypvt[-8], yypvt[-0], yypvt[-5]); +} break; +case 136: +# line 590 "macross_6502.y" +{ + checkDefineAssignmentOperator(yypvt[-4]); + yyval = buildVariableStatement(yypvt[-5], yypvt[-0], -1); +} break; +case 137: +# line 598 "macross_6502.y" +{ + yyval = yypvt[-0]; +} break; +case 138: +# line 605 "macross_6502.y" +{ + yyval = buildMvariableStatement(yypvt[-0], UNASSIGNED, NULL); +} break; +case 139: +# line 609 "macross_6502.y" +{ + checkDefineAssignmentOperator(yypvt[-2]); + yyval = buildMvariableStatement(yypvt[-3], yypvt[-0], NULL); +} break; +case 140: +# line 614 "macross_6502.y" +{ + yyval = buildMvariableStatement(yypvt[-5], UNASSIGNED, yypvt[-2]); +} break; +case 141: +# line 618 "macross_6502.y" +{ + checkDefineAssignmentOperator(yypvt[-7]); + yyval = buildMvariableStatement(yypvt[-8], yypvt[-0], yypvt[-5]); +} break; +case 142: +# line 623 "macross_6502.y" +{ + checkDefineAssignmentOperator(yypvt[-4]); + yyval = buildMvariableStatement(yypvt[-5], yypvt[-0], -1); +} break; +case 143: +# line 631 "macross_6502.y" +{ + yyval = yypvt[-0]; +} break; +case 144: +# line 638 "macross_6502.y" +{ + yyval = buildMifStatement(yypvt[-0], NULL, NO_CONTINUATION); +} break; +case 145: +# line 642 "macross_6502.y" +{ + yyval = buildMifStatement(yypvt[-1], yypvt[-0], ELSE_CONTINUATION); +} break; +case 146: +# line 646 "macross_6502.y" +{ + yyval = buildMifStatement(yypvt[-1], yypvt[-0], ELSEIF_CONTINUATION); +} break; +case 147: +# line 652 "macross_6502.y" +{ + yyval = buildMifHead(yypvt[-2], yypvt[-0]); +} break; +case 148: +# line 658 "macross_6502.y" +{ + yyval = yypvt[-2]; +} break; +case 149: +# line 664 "macross_6502.y" +{ + yyval = yypvt[-0]; +} break; +case 150: +# line 670 "macross_6502.y" +{ + yyval = extractMifBody(yypvt[-0]); +} break; +case 151: +# line 674 "macross_6502.y" +{ + yyval = extractMifBody(buildMifStatement(yypvt[-0], NULL, NO_CONTINUATION)); +} break; +case 152: +# line 678 "macross_6502.y" +{ + yyval = extractMifBody(buildMifStatement(yypvt[-1], yypvt[-0], ELSE_CONTINUATION)); +} break; +case 153: +# line 682 "macross_6502.y" +{ + yyval = extractMifBody(buildMifStatement(yypvt[-1], yypvt[-0], ELSEIF_CONTINUATION)); +} break; +case 154: +# line 689 "macross_6502.y" +{ + yyval = buildMswitchStatement(yypvt[-2], yypvt[-0]); +} break; +case 155: +# line 695 "macross_6502.y" +{ + yyval = yypvt[-2]; +} break; +case 156: +# line 701 "macross_6502.y" +{ + yyval = yypvt[-2]; +} break; +case 157: +# line 706 "macross_6502.y" +{ + yyval = NULL; +} break; +case 158: +# line 712 "macross_6502.y" +{ + yyval = buildCaseList(yypvt[-0], NULL); +} break; +case 159: +# line 716 "macross_6502.y" +{ + yyval = buildCaseList(yypvt[-0], yypvt[-2]); +} break; +case 160: +# line 722 "macross_6502.y" +{ + yyval = buildCase(yypvt[-2], yypvt[-0]); +} break; +case 161: +# line 728 "macross_6502.y" +{ + yyval = yypvt[-2]; +} break; +case 162: +# line 732 "macross_6502.y" +{ + yyval = NULL; +} break; +case 163: +# line 739 "macross_6502.y" +{ + yyval = buildMwhileStatement(yypvt[-2], yypvt[-0]); +} break; +case 164: +# line 746 "macross_6502.y" +{ + yyval = buildMdoStatement(yypvt[-2], yypvt[-0]); +} break; +case 165: +# line 752 "macross_6502.y" +{ + yyval = buildMdoEnd(yypvt[-0], WHILE_END); +} break; +case 166: +# line 756 "macross_6502.y" +{ + yyval = buildMdoEnd(yypvt[-0], WHILE_END); +} break; +case 167: +# line 760 "macross_6502.y" +{ + yyval = buildMdoEnd(yypvt[-0], UNTIL_END); +} break; +case 168: +# line 764 "macross_6502.y" +{ + yyval = buildMdoEnd(yypvt[-0], UNTIL_END); +} break; +case 169: +# line 771 "macross_6502.y" +{ + yyval = buildFreturnStatement(NULL); +} break; +case 170: +# line 775 "macross_6502.y" +{ + yyval = buildFreturnStatement(yypvt[-0]); +} break; +case 172: +# line 785 "macross_6502.y" +{ + yyval = buildMforStatement(yypvt[-4], yypvt[-0]); +} break; +case 173: +# line 792 "macross_6502.y" +{ + yyval = buildForExpressions(yypvt[-6], yypvt[-3], yypvt[-0]); +} break; +case 174: +# line 799 "macross_6502.y" +{ + yyval = buildIncludeStatement(yypvt[-0]); +} break; +case 175: +# line 806 "macross_6502.y" +{ + yyval = buildExternStatement(yypvt[-0]); +} break; +case 176: +# line 812 "macross_6502.y" +{ + yyval = buildStartStatement(yypvt[-0]); +} break; +case 177: +# line 818 "macross_6502.y" +{ + yyval = buildAlignStatement(yypvt[-0]); +} break; +case 178: +# line 824 "macross_6502.y" +{ + yyval = buildOrgStatement(yypvt[-0]); +} break; +case 179: +# line 831 "macross_6502.y" +{ + yyval = buildTargetStatement(yypvt[-0]); +} break; +case 180: +# line 837 "macross_6502.y" +{ + yyval = buildRelStatement(); +} break; +case 181: +# line 844 "macross_6502.y" +{ + yyval = buildPerformStatement(yypvt[-0]); +} break; +case 184: +# line 855 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], NULL); +} break; +case 185: +# line 859 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], yypvt[-1]); +} break; +case 186: +# line 863 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], yypvt[-3]); +} break; +case 187: +# line 867 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], yypvt[-1]); +} break; +case 188: +# line 871 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], yypvt[-3]); +} break; +case 189: +# line 878 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], NULL); +} break; +case 190: +# line 882 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], yypvt[-3]); +} break; +case 191: +# line 886 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], yypvt[-1]); +} break; +case 192: +# line 890 "macross_6502.y" +{ + yyval = buildOperandList(yypvt[-0], yypvt[-3]); +} break; +case 193: +# line 896 "macross_6502.y" +{ + yyval = buildOperand(BLOCK_OPND, yypvt[-0]); +} break; +case 194: +# line 902 "macross_6502.y" +{ + yyval = yypvt[-1]; + statementListNestingDepth--; +} break; +case 195: +# line 909 "macross_6502.y" +{ + statementListNestingDepth++; +} break; +case 196: +# line 914 "macross_6502.y" +{ + yyval = buildSelectionList(yypvt[-0], NULL); +} break; +case 197: +# line 918 "macross_6502.y" +{ + yyval = buildSelectionList(yypvt[-0], yypvt[-3]); +} break; +case 198: +# line 924 "macross_6502.y" +{ + yyval = buildExpressionTerm(ARRAY_EXPR, yypvt[-5], yypvt[-2]); +} break; +case 199: +# line 928 "macross_6502.y" +{ + yyval = buildExpressionTerm(ARRAY_EXPR, yypvt[-5], yypvt[-2]); +} break; +case 200: +# line 934 "macross_6502.y" +{ + yyval = buildExpressionTerm(IDENTIFIER_EXPR, lookupOrEnterSymbol(yypvt[-0], + unknownSymbolTag)); +} break; +case 203: +# line 945 "macross_6502.y" +{ + yyval = yypvt[-0]; +} break; +case 204: +# line 949 "macross_6502.y" +{ + yyval = buildExpressionTerm(FUNCTION_CALL_EXPR, yypvt[-0]); +} break; +case 205: +# line 953 "macross_6502.y" +{ + yyval = buildExpressionTerm(NUMBER_EXPR, yypvt[-0]); +} break; +case 206: +# line 957 "macross_6502.y" +{ + yyval = buildExpressionTerm(CONDITION_CODE_EXPR, yypvt[-0]); +} break; +case 207: +# line 961 "macross_6502.y" +{ + yyval = buildExpressionTerm(HERE_EXPR); +} break; +case 208: +# line 965 "macross_6502.y" +{ + yyval = buildExpressionTerm(STRING_EXPR, yypvt[-0]); +} break; +case 209: +# line 969 "macross_6502.y" +{ + yyval = buildExpressionTerm(SUBEXPRESSION_EXPR, yypvt[-2]); +} break; +case 210: +# line 973 "macross_6502.y" +{ + yyval = buildExpressionTerm(UNOP_EXPR, UNARY_MINUS, yypvt[-0]); +} break; +case 211: +# line 977 "macross_6502.y" +{ + yyval = buildExpressionTerm(UNOP_EXPR, LOGICAL_NOT, yypvt[-0]); +} break; +case 212: +# line 981 "macross_6502.y" +{ + yyval = buildExpressionTerm(UNOP_EXPR, BITWISE_NOT, yypvt[-0]); +} break; +case 213: +# line 985 "macross_6502.y" +{ + yyval = buildExpressionTerm(UNOP_EXPR, LO_BYTE, yypvt[-0]); +} break; +case 214: +# line 989 "macross_6502.y" +{ + yyval = buildExpressionTerm(UNOP_EXPR, HI_BYTE, yypvt[-0]); +} break; +case 215: +# line 993 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, MUL, yypvt[-3], yypvt[-0]); +} break; +case 216: +# line 997 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, DIV, yypvt[-3], yypvt[-0]); +} break; +case 217: +# line 1001 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, MOD, yypvt[-3], yypvt[-0]); +} break; +case 218: +# line 1005 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, SUB, yypvt[-3], yypvt[-0]); +} break; +case 219: +# line 1009 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, ADD, yypvt[-3], yypvt[-0]); +} break; +case 220: +# line 1013 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, LEFT_SHIFT, yypvt[-3], yypvt[-0]); +} break; +case 221: +# line 1017 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, RIGHT_SHIFT, yypvt[-3], yypvt[-0]); +} break; +case 222: +# line 1021 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, LESS_THAN, yypvt[-3], yypvt[-0]); +} break; +case 223: +# line 1025 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, GREATER_THAN, yypvt[-3], yypvt[-0]); +} break; +case 224: +# line 1029 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, LESS_THAN_OR_EQUAL_TO, yypvt[-3], yypvt[-0]); +} break; +case 225: +# line 1033 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, GREATER_THAN_OR_EQUAL_TO, yypvt[-3],yypvt[-0]); +} break; +case 226: +# line 1037 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, EQUAL_TO, yypvt[-3], yypvt[-0]); +} break; +case 227: +# line 1041 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, NOT_EQUAL_TO, yypvt[-3], yypvt[-0]); +} break; +case 228: +# line 1045 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, BITWISE_AND, yypvt[-3], yypvt[-0]); +} break; +case 229: +# line 1049 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, BITWISE_OR, yypvt[-3], yypvt[-0]); +} break; +case 230: +# line 1053 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, BITWISE_XOR, yypvt[-3], yypvt[-0]); +} break; +case 231: +# line 1057 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, LOGICAL_AND, yypvt[-3], yypvt[-0]); +} break; +case 232: +# line 1061 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, LOGICAL_OR, yypvt[-3], yypvt[-0]); +} break; +case 233: +# line 1065 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, LOGICAL_XOR, yypvt[-3], yypvt[-0]); +} break; +case 234: +# line 1069 "macross_6502.y" +{ + yyval = buildExpressionTerm(BINOP_EXPR, SELECT, yypvt[-3], + lookupOrEnterSymbol(yypvt[-0], STRUCT_FIELD_SYMBOL)); +} break; +case 235: +# line 1074 "macross_6502.y" +{ + yyval = buildExpressionTerm(ASSIGN_EXPR, yypvt[-2], yypvt[-3], yypvt[-0]); +} break; +case 236: +# line 1078 "macross_6502.y" +{ + yyval = buildExpressionTerm(POSTOP_EXPR, INCREMENT, yypvt[-1]); +} break; +case 237: +# line 1082 "macross_6502.y" +{ + yyval = buildExpressionTerm(POSTOP_EXPR, DECREMENT, yypvt[-1]); +} break; +case 238: +# line 1086 "macross_6502.y" +{ + yyval = buildExpressionTerm(PREOP_EXPR, INCREMENT, yypvt[-0]); +} break; +case 239: +# line 1090 "macross_6502.y" +{ + yyval = buildExpressionTerm(PREOP_EXPR, DECREMENT, yypvt[-0]); +} break; +case 240: +# line 1097 "macross_6502.y" +{ + yyval = buildFunctionCall(yypvt[-3], NULL); +} break; +case 241: +# line 1101 "macross_6502.y" +{ + yyval = buildFunctionCall(yypvt[-5], yypvt[-2]); +} break; +case 251: +# line 1127 "macross_6502.y" +{ + yyval = buildOperand(EXPRESSION_OPND, yypvt[-0]); +} break; +case 252: +# line 1133 "macross_6502.y" +{ + yyval = buildOperand(INDIRECT_OPND, yypvt[-0]); +} break; +case 253: +# line 1139 "macross_6502.y" +{ + yyval = buildOperand(IMMEDIATE_OPND, yypvt[-0]); +} break; +case 254: +# line 1146 "macross_6502.y" +{ + yyval = buildOperand(A_REGISTER_OPND, NULL); +} break; +case 255: +# line 1150 "macross_6502.y" +{ + yyval = buildOperand(X_REGISTER_OPND, NULL); +} break; +case 256: +# line 1154 "macross_6502.y" +{ + yyval = buildOperand(Y_REGISTER_OPND, NULL); +} break; +case 257: +# line 1161 "macross_6502.y" +{ + yyval = buildOperand(X_INDEXED_OPND, yypvt[-2]); +} break; +case 258: +# line 1165 "macross_6502.y" +{ + yyval = buildOperand(Y_INDEXED_OPND, yypvt[-2]); +} break; +case 259: +# line 1169 "macross_6502.y" +{ + yyval = buildOperand(X_SELECTED_OPND, yypvt[-0]); +} break; +case 260: +# line 1173 "macross_6502.y" +{ + yyval = buildOperand(Y_SELECTED_OPND, yypvt[-0]); +} break; +case 261: +# line 1177 "macross_6502.y" +{ + yyval = buildOperand(X_INDEXED_OPND, NULL); +} break; +case 262: +# line 1181 "macross_6502.y" +{ + yyval = buildOperand(Y_INDEXED_OPND, NULL); +} break; +case 263: +# line 1188 "macross_6502.y" +{ + yyval = buildOperand(PRE_INDEXED_X_OPND, yypvt[-2]); +} break; +case 264: +# line 1192 "macross_6502.y" +{ + yyval = buildOperand(PRE_SELECTED_X_OPND, yypvt[-0]); +} break; +case 265: +# line 1199 "macross_6502.y" +{ + yyval = buildOperand(POST_INDEXED_Y_OPND, yypvt[-2]); +} break; + } + goto yystack; /* stack new state and value */ + + } diff --git a/y.tab.h b/y.tab.h new file mode 100644 index 0000000..00a12d8 --- /dev/null +++ b/y.tab.h @@ -0,0 +1,80 @@ +# define A 257 +# define ALIGN 258 +# define ASSERT 259 +# define BLOCK 260 +# define BYTE 261 +# define CONSTRAIN 262 +# define DBYTE 263 +# define DEFINE 264 +# define DO 265 +# define ELSE 266 +# define ELSEIF 267 +# define ENDFILE 268 +# define EOL 269 +# define EXTERN 270 +# define FRETURN 271 +# define FUNCTION 272 +# define HERE 273 +# define IF 274 +# define INCLUDE 275 +# define LONG 276 +# define MACRO 277 +# define MCASE 278 +# define MDEFAULT 279 +# define MDEFINE 280 +# define MDO 281 +# define MELSE 282 +# define MELSEIF 283 +# define MFOR 284 +# define MIF 285 +# define MSWITCH 286 +# define MUNTIL 287 +# define MVARIABLE 288 +# define MWHILE 289 +# define ORG 290 +# define REL 291 +# define START 292 +# define STRING 293 +# define STRUCT 294 +# define TARGET 295 +# define UNDEFINE 296 +# define UNTIL 297 +# define VARIABLE 298 +# define WHILE 299 +# define WORD 300 +# define X 301 +# define Y 302 +# define ConditionCode 303 +# define Identifier 304 +# define MacroName 305 +# define Number 306 +# define Opcode 307 +# define TextString 308 +# define ASSIGN 309 +# define LOGICAL_OR 310 +# define LOGICAL_XOR 311 +# define LOGICAL_AND 312 +# define BITWISE_OR 313 +# define BITWISE_XOR 314 +# define BITWISE_AND 315 +# define EQUAL_TO 316 +# define NOT_EQUAL_TO 317 +# define LESS_THAN 318 +# define LESS_THAN_OR_EQUAL_TO 319 +# define GREATER_THAN 320 +# define GREATER_THAN_OR_EQUAL_TO 321 +# define LEFT_SHIFT 322 +# define RIGHT_SHIFT 323 +# define ADD 324 +# define SUB 325 +# define MUL 326 +# define DIV 327 +# define MOD 328 +# define UNARY_MINUS 329 +# define LOGICAL_NOT 330 +# define BITWISE_NOT 331 +# define HI_BYTE 332 +# define LO_BYTE 333 +# define SELECT 334 +# define INCREMENT 335 +# define DECREMENT 336 diff --git a/y.tab.o b/y.tab.o new file mode 100644 index 0000000..c034aad Binary files /dev/null and b/y.tab.o differ