/Tools/zmac/src/zmac.y
Happy | 7298 lines | 6532 code | 766 blank | 0 comment | 0 complexity | 95f9f1c4a1a8aec4e9cc5592fd34d0ab MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- %{
- // GWP - keep track of version via hand-maintained date stamp.
- #define VERSION "3dec2014"
-
- /*
- * zmac -- macro cross-assembler for the Zilog Z80 microprocessor
- *
- * Bruce Norskog 4/78
- *
- * Last modification 1-18-87 by cdk
- * This assembler is modeled after the Intel 8080 macro cross-assembler
- * for the Intel 8080 by Ken Borgendale. The major features are:
- * 1. Full macro capabilities
- * 2. Conditional assembly
- * 3. A very flexible set of listing options and pseudo-ops
- * 4. Symbol table output
- * 5. Error report
- * 6. Elimination of sequential searching
- * 7. Commenting of source
- * 8. Facilities for system definiton files
- *
- * Revision History:
- *
- * jrp 3-8-82 Converted to run on Vax, updated syntax to conform better
- * to the Zilog standard.
- *
- * jrp 3-15-82 Added underscore as a character type in the lex table
- * 'numpart' (0x5F).
- *
- * Changed maximum number of characters in a label to 15
- * from 7. Note that 'putsymtab' uses this value inside
- * of a quoted string, so we use 15.
- *
- * jrp 2-15-83 Fixed 'getlocal' to return better local labels. It used
- * to crash after 6 invocations.
- *
- * jrp 6-7-83 Fixed bug in the ADD IX,... instruction.
- *
- * jrp 5-11-84 Added code to print unused labels out with the symbol table
- * Also sped up the macro processor by using stdio.
- *
- * jrp 5-22-84 Added include files ala ormac
- *
- * jrp 8-27-84 Added PHASE/DEPHASE commands
- *
- * cdk 9-20-86 Converted to run on a Pyramid. This meant changing yylval
- * to be a %union, and then putting in the appropriate
- * typecasts where ints are pointers are used interchangeably.
- * The current version still probably won't run on machines where
- * sizeof(int) != sizeof(char *).
- * Also changed emit() to use varargs, and got rid of the
- * old style = in front of yacc action code.
- * -Colin Kelley vu-vlsi!colin
- *
- * cdk 10-2-86 Added some more typecasts to keep lint a little happier.
- * Removed several unused variables. Changed most vars
- * declared as char to int, since many of them were being
- * compared with -1! I still don't know what's going on with
- * est[][] being malloc'd and free'd everywhere...it looks pretty
- * fishy...
- *
- * cdk 1-18-87 Added MIO code to emulate 'mfile' using malloc()'d memory.
- * This was needed to get the code to work when compiled under
- * MSC 4.0 on a PC, and it's probably faster anyway.
- *
- * cdk 2-5-87 Added 'cmp' as a synonym for 'cp', 'jmp' as a synonym for
- * 'jp', and added tolerance of accumulator specification for arithmetic
- * and logical instructions. (For example, 'or a,12' is now accepted,
- * same as 'or 12'.)
- *
- * gwp 12-29-08 Changes to allow compilation with modern C compiler and using bison
- * as the .y to .c converter. assert, tstate pseudo-ops.
- * t(), tilo(), tihi() functions. ==, <=, >=, !=, !, <, > operators.
- * -c to turn cycle counts off in listing. Usage, -h and version.
- *
- * gwp 9-26-10 Add ocf() and setocf to track and set op code fetch counts.
- * Add sett as an alias for tstate
- *
- * gwp 12-30-11 Add undocumented instructions sl1, pfix, pfiy, in (c), out (c),0
- * bit/set/res (ixy+d),reg and ld/inc/dec ixylh.
- *
- * gwp 2-8-12 Increase MAXIFS massively due to massive lowt macro
- *
- * gwp 2-11-12 Support 32 bit constants. '%' alias for MOD. Add defd, dword.
- * lo(x) and hi(x) for easy low and high byte extraction. Allow
- * filenames longer than 15 characters. All output to "zout" subdirectory
- * of source file.
- *
- * gwp 2-15-12 Perform multiple passes while equates are changing. Support
- * .label for temporary label definitions and _label for file
- * scoped labels. Allow '.' within labels. Assert listing bugfix.
- *
- * gwp 4-27-12 Implement $ prefixed hex constants and double-quoted strings.
- *
- * gwp 6-30-12 Minor changes to allow compilation with gcc.
- *
- * gwp 9-05-12 incbin added.
- *
- * gwp 11-24-12 Fix macro expansion bug when symbol larger than MAXSYMBOLSIZE
- * due to file name prepending when symbol starts with '_'.
- *
- * gwp 12-04-12 Optional JR promotion and JP demotion errors. Output a warning
- * if no execute address given. Output ".bds" file to enable easy
- * simple source level debugging.
- *
- * gwp 4-14-13 Parens in expressions, else, .pseudo, full set of C operators
- * with conventional precedence and various aliases and code
- * changes to make source similar to zmac 1.3 on internet.
- *
- * gwp 5-5-13 .cmd,.cas,.lcas,.bin output. dc (both MACRO-80 and EDAS types).
- * lo, hi renamed to low, high and make unary operators. Allow
- * label::, placeholder public, extern declarations. Bug fixes
- * in defs, t, ocf, tihi, tilo in phase mode. Initial support
- * for -I include directories. 0x hex constants. --mras flag for
- * limited MRAS compatibility (allows $ in labels, $? to start
- * labels).
- *
- * gwp 4-6-13 --rel for .rel (Microsoft linker) output and extern, public,
- * aseg, cseg, dseg in support (big emit + expression revamp).
- * -I follows C preprocessor convention, output relative to
- * current directory. 8080 mnemonics, .z80, .8080, -z, -8.
- * Change .bin to .cim. Warn on labels not in first column.
- *
- * gwp 8-11-13 Allow $ to start identifiers and do '$' dropping when macro
- * parsed so we no longer need to drop '$' in identifiers.
- * Even $FCB allowed, with warning. Add --zmac for backwards
- * compatibility with zmac. ` now used for joining in macros.
- * Most reserved words can be used as labels or variables.
- * Free-form title, name, comment, subttl parsing. Allow #arg
- * for macro arguments (in --mras mode). Support <CR> delimited
- * files. Add .ams output. Integrate documentation (--doc).
- *
- * gwp 3-12-14 Emit jr even if out of range. z80.lib support.
- * Warning and bug fixes from Mark Galanger.
- * Macros can override built-ins and are no longer listed
- * in symbol table. A, B, C, D, E, H, L, M, PSW, SP are
- * pre-defined values which can be used in data statements
- * (db, dw, dd). Reserved words can be equated but are only
- * accessbile in data. SET can be used in place of DEFL
- * (MAC and MACRO-80 agree on this). '=' can be used in place
- * of EQU. 'maclib file' includes 'file.lib'. Bug fix in "dw 0,$".
- * Removed error flagging in expressions which could cause parse
- * to fail from that point onwards.
- * expression(ix) equivalent to (ix + expression).
- * Macro expanded lines didn't go through the line analyzer.
- * Empty macro arguments (e.g., mac 1,,2)
- * Implemented rept, irp, irpc, exitm. Add more detail on phase
- * errors. '' is an empty string in db/ascii/etc, 0 otherwise.
- * Almost any name can be used as a macro parameter name.
- * Allow 'if' in first column.
- * Fix .rel mode bug in dc, incbin.
- * Emit .bds output for dc, incbin.
- * Allow assembly to wrap past end of memory.
- * "pragma bds" for raw output to .bds file. Also output equates
- * to .bds file.
- * Macro bug fix from Sergey Erokhin.
- */
-
- #define MIO /* use emulation routines from mio.c */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <time.h>
- #include <sys/stat.h>
-
- #ifdef WIN32
- #include <windows.h> // just for colouring the output
- #endif
-
- #include "zi80dis.h"
-
- #ifdef vax11c
- #define unlink(filename) delete(filename)
- #endif
-
- #ifdef MIO
- #include "mio.h"
-
- FILE *mfopen();
- #else
- #define mfopen(filename,mode) fopen(filename,mode)
- #define mfclose(filename,mode) fclose(filename,mode)
- #define mfputc(c,f) putc(c,f)
- #define mfgetc(f) getc(f)
- #define mfseek(f,loc,origin) fseek(f,loc,origin)
- #define mfread(ptr,size,nitems,f) fread(ptr,size,nitems,f)
- #define mfwrite(ptr,size,nitems,f) fread(ptr,size,nitems,f)
- #endif /* MIO */
-
- /*
- * DEBUG turns on pass reporting.
- * DBUG enables -d to allow yacc/bison yydebug increment (but must be passed
- * on the command line)
- * Macro debug and Token debug enables.
- #define DEBUG
- #define M_DEBUG
- #define T_DEBUG
- */
-
- #ifdef DBUG
- #define YYDEBUG 1
- #endif
-
- #define ITEMTABLESIZE 100000
- #define TEMPBUFSIZE (1000+MAXSYMBOLSIZE)
- #define LINEBUFFERSIZE 1000
- #define EMITBUFFERSIZE 200
- #define MAXSYMBOLSIZE 40
- #define IFSTACKSIZE 20
- // GWP - I use lots of if's with my lowt macro
- #define MAXIFS 65536
- #define TITLELEN 50
- #define BINPERLINE 16
- #define PARMMAX 25
- #define MAXEXP 25
- #define SYMMAJIC 07203
- #define NEST_IN 32
- #define MAXPASS 32
- #define MAXINCPATH 32
-
- int iflist();
- int yylex();
- int phaseaddr(int addr);
- int nextchar();
- int getcol();
- int skipline(int ac);
- int tokenofitem(int deftoken, int keyexclude, int keyinclude);
- int getm();
- int counterr();
- int countwarn();
-
- void yyerror(char *err)
- {} /* we will do our own error printing */
-
- struct argparse {
- char *arg; // output buffer for argument
- int argsize; // size of output buffer
- int (*getch)(struct argparse *); // get next character
- int *peek; // pointer single item pushback buffer
- int macarg; // working on macro arguments
-
- char *user_ptr; // state for getch
- int user_int; // state for getch
- int user_peek; // state for getch
-
- int didarg; // internal parsing state
- int numarg; // internal parsing state
- };
-
- int getarg(struct argparse *ap);
-
- struct item {
- char *i_string;
- int i_value;
- int i_token;
- int i_uses;
- int i_scope;
- int i_chain;
- };
-
- void itemcpy(struct item *dst, struct item *src);
- struct item *keyword(char *name);
-
- #define SCOPE_NONE (0)
- #define SCOPE_PROGRAM (1)
- #define SCOPE_DATA (2)
- #define SCOPE_PUBLIC (4)
- #define SCOPE_EXTERNAL (8)
- #define SCOPE_NORELOC (16)
- #define SCOPE_BUILTIN (32) /* abuse */
-
- #define SCOPE_SEGMASK (3)
- #define SCOPE_SEG(s) ((s) & SCOPE_SEGMASK)
-
- struct expr {
- int e_value;
- int e_scope;
- int e_token;
- struct item *e_item;
- struct expr *e_left;
- struct expr *e_right;
- };
-
- #define EXPR_SEG(e) SCOPE_SEG(e->e_scope)
-
- FILE *fout,
- *fbuf,
- *fbds,
- *fcmd,
- *fcas,
- *flcas,
- *fcim,
- *fams,
- *frel,
- *fin[NEST_IN],
- *now_file ;
-
- int pass2; /*set when pass one completed*/
- int outpass; // set when we decide to stop doing passes */
- int passfail; // set when an error means passes should not continue
- int passretry; // set when an inconsistency will require another pass
- int dollarsign ; /* location counter */
- int olddollar ; /* kept to put out binary */
- int oldothdollar; // output address of next .cmd/.cas/.lcas block
- int emit_addr; // were code and data are being placed in memory
- int tstates; // cumulative T-states
- int ocf; // cumulative op code fetches
- int llseq; // local label sequence number
- int mras; // MRAS semi-compatibility mode
- int zcompat; // Original zmac compatibility mode
- char modstr[8]; // Replacement string for '?' in labels when MRAS compatible
- int relopt; // Only output .rel files.
- char progname[8]; // Program name for .rel output
- int note_depend; // Print names of files included
- int firstcol;
- int logcol;
- int coloncnt;
- int full_exprs; // expression parsing mode allowing almost any identifier
- struct item *label, pristine_label; //
- int list_dollarsign;// flag used to change list output for some operations
- int list_addr; // address to display for operation if !list_dollarsign
-
- // Include file search path
- char *incpath[MAXINCPATH];
- int incpath_cnt;
-
- /* program counter save for PHASE/DEPHASE */
- int phdollar, phbegin, phaseflag ;
-
- char *src_name[NEST_IN] ;
- int linein[NEST_IN] ;
- int now_in ;
-
-
- // These first 5 errors are singled out in lsterr1() for reasons I don't
- // quite understand.
- #define bflag 0 /* balance error */
- #define eflag 1 /* expression error */
- #define fflag 2 /* syntax error */
- #define iflag 3 /* bad digits */
- #define mflag 4 /* multiply defined */
-
- #define pflag 5 /* phase error */
- #define uflag 6 /* undeclared used */
- #define vflag 7 /* value out of range */
- #define oflag 8 /* phase/dephase error */
- #define aflag 9 /* assert failed */
- #define jflag 10 /* JP could be JR */
- #define rflag 11 /* expression not relocatable */
- #define gflag 12 /* incorrect register */
- #define zflag 13 /* Z-80 instruction */
-
- #define FIRSTWARN warn_hex
- #define warn_hex 14
- #define warn_notimpl 15
- #define warn_general 16
-
- #define FLAGS 17 /* number of errors and warnings */
-
- char err[FLAGS];
- int keeperr[FLAGS];
- char errlet[FLAGS]="BEFIMPUVOAJRGZHNW";
- char *errname[FLAGS]={
- "Balance",
- "Expression",
- "Syntax",
- "Digit",
- "Mult. def.",
- "Phase",
- "Undeclared",
- "Value",
- "Phase/Dephase",
- "Assertion failure",
- "Use JR",
- "Not relocatable",
- "Register usage",
- "Z-80 instruction in 8080 mode",
- "$hex constant interpreted as symbol",
- "Not implemented",
- "General"
- };
- char errdetail[FLAGS][1024];
- char detail[1024];
-
-
- unsigned char inpbuf[LINEBUFFERSIZE];
- unsigned char *inpptr;
-
- char linebuf[LINEBUFFERSIZE];
- char *lineptr;
- char *linemax = linebuf+LINEBUFFERSIZE;
-
- char outbin[BINPERLINE];
- char *outbinp = outbin;
- char *outbinm = outbin+BINPERLINE;
-
- char outoth[256];
- int outoth_cnt = 0;
-
- unsigned char emitbuf[EMITBUFFERSIZE];
- unsigned char *emitptr;
-
- char ifstack[IFSTACKSIZE];
- char *ifptr;
- char *ifstmax = ifstack+IFSTACKSIZE-1;
-
-
- char hexadec[] = "0123456789ABCDEF" ;
-
-
- int nitems;
- int linecnt;
- int nbytes;
- int invented;
- int npass;
- int njrpromo;
-
-
- char tempbuf[TEMPBUFSIZE];
- char *tempmax = tempbuf+TEMPBUFSIZE-1;
-
- char arg_flag;
- struct argparse arg_state;
- void arg_start();
- void arg_reset();
- int str_getch(struct argparse *ap);
-
- char inmlex;
- char mlex_list_on;
- int parm_number;
- int exp_number;
- char symlong[] = "Symbol/number too long";
- int raw;
-
- int disp;
-
- int param_parse;
- #define PARAMTABSIZE (PARMMAX * 2)
- struct item paramtab[PARAMTABSIZE];
-
- #define FLOC PARMMAX
- #define TEMPNUM PARMMAX+1
- #define REPNUM PARMMAX+2
- #define MSTART PARMMAX+3
- #define MSTR PARMMAX+4
- #define MARGP PARMMAX+5
- #define MIF PARMMAX+6
-
- #define PAREXT 7
-
- union exprec {
- char *param;
- int value;
- struct argparse *ap;
- };
- union exprec *est;
- union exprec *est2;
- union exprec *expstack[MAXEXP];
- int expptr;
-
- int floc;
- int mfptr;
- FILE *mfile;
-
- char *writesyms;
-
-
- char *title;
- char titlespace[TITLELEN];
- char *timp;
- char *sourcef;
- /* changed to cope with filenames longer than 14 chars -rjm 1998-12-15 */
- char src[1024];
- char bin[1024];
- char mtmp[1024];
- char listf[1024];
- char bds[1024];
- char oth[1024];
-
- char bopt = 1,
- copt = 1, /* cycle counts in listings by default */
- edef = 1,
- eopt = 1,
- fdef = 0,
- fopt = 0,
- gdef = 1,
- gopt = 1,
- iopt = 0 , /* list include files */
- jopt = 0,
- JPopt = 0,
- lstoff = 0,
- lston = 0, /* flag to force listing on */
- lopt = 0,
- mdef = 0,
- mopt = 0,
- nopt = 1 , /* line numbers on as default */
- oopt = 0,
- popt = 1, /* form feed as default page eject */
- sopt = 0, /* turn on symbol table listing */
- topt = 1, /* terse, only error count to terminal */
- printer_output = 0, // GWP - printer style output
- z80,
- saveopt;
-
- char default_jopt, default_JPopt, default_z80 = 1;
-
- char xeq_flag = 0;
- int xeq;
-
- time_t now;
- int line;
- int page = 1;
-
- struct stab {
- char t_name[MAXSYMBOLSIZE+1];
- int t_value;
- int t_token;
- };
-
- // GWP - support for cycle count tracking (and opens door for efficient .cmd, etc. output)
-
- unsigned char memory[1 << 16];
- char memflag[1 << 16];
- enum {
- MEM_DATA = 1,
- MEM_INST = 2,
- MEM_T_SET = 4
- };
- int tstatesum[1 << 16];
- int ocfsum[1 << 16];
-
- // GWP - expression handling extensions for .rel output.
- void advance_segment(int step);
- void expr_reloc_check(struct expr *ex);
- void expr_number_check(struct expr *ex);
- void expr_scope_same(struct expr *ex1, struct expr *ex2);
- void expr_word_check(struct expr *ex);
- int is_number(struct expr *ex);
- int is_external(struct expr *ex);
- struct expr *expr_num(int value);
- struct expr *expr_alloc(void);
- struct expr *expr_op(struct expr *left, int token, struct expr *right, int value);
- struct expr *expr_op_sc(struct expr *left, int token, struct expr *right, int value);
- void expr_free(struct expr *ex);
- int can_extend_link(struct expr *ex);
- void extend_link(struct expr *ex);
- void putrelop(int op);
- #define RELOP_BYTE (1)
- #define RELOP_WORD (2)
- #define RELOP_HIGH (3)
- #define RELOP_LOW (4)
- #define RELOP_NOT (5)
- #define RELOP_NEG (6)
- #define RELOP_SUB (7)
- #define RELOP_ADD (8)
- #define RELOP_MUL (9)
- #define RELOP_DIV (10)
- #define RELOP_MOD (11)
- struct item *item_lookup(char *name, struct item *table, int table_size);
- struct item *locate(char *name);
- // Data descriptions for emit()
- #define E_CODE (0)
- #define E_DATA (1)
- #define E_CODE8 (2)
- #define E_CODE16 (3)
- int segment;
- #define SEGCHAR(s) " '\"!"[s]
- #define SEG_ABS (0)
- #define SEG_CODE (1)
- #define SEG_DATA (2)
- int seg_pos[4]; // may eventually support SEG_COMMON
- int seg_size[4];
- int rel_main;
- int segchange;
- void putout(int value);
- int outrec;
- int outlen;
- unsigned char outbuf[1024 * 1024];
-
-
- /*
- * push back character
- */
- int peekc;
- int nextline_peek;
-
- /* function prototypes */
- void error(char *as);
- void usage(char *msg, char *param);
- void help();
- void erreport();
- void errorprt(int errnum);
- void errwarn(int errnum, char *message);
- void mlex(char *look);
- void popsi();
- void suffix(char *str, char *suff);
- char *basename(char *filename);
- char *getsuffix(char *str);
- void outpath(char *out, char *src, char *suff);
- void casname(char *out, char *src);
- void putm(int c);
- void insymtab(char *name);
- void outsymtab(char *name);
- void compactsymtab();
- void putsymtab();
- void clear();
- void setmem(int addr, int value, int type);
- void setvars();
- void flushbin();
- void flushoth();
- void lineout();
- void puthex(int byte, FILE *buf);
- void putcas(int byte);
- void putrelbits(int count, int bits);
- void putrel(int byte);
- void putrelname(char *str);
- void putrelextaddr(int extaddr);
- void putrelcmd(int cmd);
- void putrelsegref(int scope, int addr);
- void flushrel(void);
- void lsterr1();
- void lsterr2(int lst);
- void copyname(char *st1, char *st2);
- void next_source(char *sp);
- void incbin(char *filename);
- void dc(int count, int value);
- char *getmraslocal();
-
- #define RELCMD_PUBLIC (0)
- #define RELCMD_COMMON (1)
- #define RELCMD_PROGNAME (2)
- #define RELCMD_LIBLOOK (3)
- #define RELCMD_EXTLINK (4)
- #define RELCMD_COMSIZE (5)
- #define RELCMD_EXTCHAIN (6)
- #define RELCMD_PUBVALUE (7)
- #define RELCMD_EXTMINUS (8)
- #define RELCMD_EXTPLUS (9)
- #define RELCMD_DATASIZE (10)
- #define RELCMD_SETLOC (11)
- #define RELCMD_CODESIZE (13)
- #define RELCMD_ENDMOD (14)
- #define RELCMD_ENDPROG (15)
-
- /*
- * add a character to the output line buffer
- */
- void addtoline(int ac)
- {
- /* check for EOF from stdio */
- if (ac == -1)
- ac = 0 ;
- if (lineptr >= linemax)
- error("line buffer overflow");
- *lineptr++ = ac;
- }
-
- /*
- * put values in buffer for outputing
- */
-
- void emit(int bytes, int desc, struct expr *data, ...)
- {
- int type, i, args, dsize;
- va_list ap;
-
- if (relopt && segchange) {
- segchange = 0;
- putrelcmd(RELCMD_SETLOC);
- putrelsegref(segment, seg_pos[segment]);
- }
-
- // External references only supported in .rel output.
- if (!relopt && data && (data->e_scope & SCOPE_EXTERNAL)) {
- sprintf(detail, "External references only allowed in .rel output\n");
- errwarn(uflag, detail);
- }
-
- va_start(ap, data);
-
- type = desc == E_DATA ? MEM_DATA : MEM_INST;
-
- // Check emit is not adding instructions to the buffer.
- if (desc != E_DATA && emitptr != emitbuf)
- fprintf(stderr, "internal inconsistency in t-state counting\n");
-
- dsize = 0;
- args = bytes;
- if (desc == E_DATA) {
- args = 0;
- dsize = bytes;
- }
- else if (desc == E_CODE16)
- dsize = 2;
- else if (desc == E_CODE8)
- dsize = 1;
-
- for (i = 0; i < args; i++)
- {
- if (emitptr >= &emitbuf[EMITBUFFERSIZE])
- error("emit buffer overflow");
- else {
- int addr = (emit_addr + (emitptr - emitbuf)) & 0xffff;
- *emitptr = va_arg(ap, int);
- if (segment == SEG_CODE)
- setmem(addr, *emitptr, type);
- putrel(*emitptr);
- putout(*emitptr);
- emitptr++;
- }
- }
-
- va_end(ap);
-
- for (i = 0; i < dsize; i++) {
- int addr = (emit_addr + (emitptr - emitbuf)) & 0xffff;
- *emitptr = data->e_value >> (i * 8);
- if (segment == SEG_CODE)
- setmem(addr, *emitptr, type);
- putout(*emitptr);
- emitptr++;
- }
-
- if (desc != E_DATA)
- {
- int eaddr = emit_addr, low, fetch, low8080, addr_after;
-
- // emitbuf is OK since this only happens with single emits
-
- if (!z80) {
- // Check for invalid 8080 instructions.
- int op = emitbuf[0] & 0xff;
- if (op == 0x08 || op == 0x10 || op == 0x18 ||
- op == 0x20 || op == 0x28 || op == 0x30 ||
- op == 0x38 || op == 0xCB || op == 0xD9 ||
- op == 0xDD || op == 0xED || op == 0xFD)
- {
- err[zflag]++;
- }
- }
-
- zi_tstates(emitbuf, &low, 0, &fetch, &low8080, 0);
- if (!z80)
- low = low8080;
-
- // Sanity check
- if (low <= 0)
- {
- fprintf(stderr, "undefined instruction on %02x %02x (assembler or diassembler broken)\n",
- emitbuf[0], emitbuf[1]);
- }
-
- // Special case to catch promotion of djnz to DEC B JP NZ
- // Even update the tstatesum[] counter though that seems to
- // me to be above and beyond.
- if (emitbuf[0] == 5 && args == 2) {
- tstatesum[eaddr] = tstates;
- ocfsum[eaddr] = ocf;
- memflag[eaddr] |= MEM_T_SET;
- eaddr++;
- tstates += low;
- ocf += fetch;
- low = 10;
- // still 1 fetch
- }
-
- // Double setting of both sides of tstatesum[] seems like too
- // much, but must be done in the isolated instruction case:
- // org x ; inc a ; org y
-
- tstatesum[eaddr] = tstates;
- ocfsum[eaddr] = ocf;
- memflag[eaddr] |= MEM_T_SET;
-
- // Well, OK, should we default to high or low???
- // Guess it should be whatever makes sense for you
- // to get here which, generally, is the low.
-
- // low it is.
-
- tstates += low;
- ocf += fetch;
-
- addr_after = (emit_addr + (emitptr - emitbuf)) & 0xffff;
-
- tstatesum[addr_after] = tstates;
- ocfsum[addr_after] = ocf;
- memflag[addr_after] |= MEM_T_SET;
- }
-
- if (relopt && outpass && dsize > 0) {
- if (dsize == 1) {
- if (is_number(data))
- putrel(data->e_value);
- else if (can_extend_link(data)) {
- extend_link(data);
- putrelop(RELOP_BYTE);
- putrel(0);
- }
- else {
- err[rflag]++;
-
- putrel(0);
- }
- }
- else if (dsize == 2) {
- int handled = 0;
- if (data->e_scope & SCOPE_EXTERNAL) {
- struct item *var = 0;
- int offset = 0;
- // Simple external reference.
- if (is_external(data))
- var = data->e_item;
- else if (is_external(data->e_left) &&
- data->e_token == '+' &&
- is_number(data->e_right))
- {
- var = data->e_left->e_item;
- offset = data->e_right->e_value;
- }
- else if (is_number(data->e_left) &&
- data->e_token == '+' &&
- is_external(data->e_right))
- {
- offset = data->e_left->e_value;
- var = data->e_right->e_item;
- }
- else if (is_external(data->e_left) &&
- data->e_token == '-' &&
- is_number(data->e_right))
- {
- var = data->e_left->e_item;
- offset = data->e_right->e_value;
- }
-
- if (var && offset) {
- putrelcmd(data->e_token == '-' ?
- RELCMD_EXTMINUS : RELCMD_EXTPLUS);
- // Theoretically we could put a
- // program or data relative value here...
- putrelsegref(SEG_ABS, offset);
- }
-
- if (var) {
- if (var->i_chain == 0) {
- putrel(0);
- putrel(0);
- }
- else {
- putrelbits(1, 1);
- putrelextaddr(var->i_chain);
- }
- var->i_chain = (segment << 16) |
- ((dollarsign + args) & 0xffff);
- handled = 1;
- }
- }
- else if ((data->e_scope & ~SCOPE_PUBLIC) == 0) {
- // nice constant value
- putrel(data->e_value);
- putrel(data->e_value >> 8);
- handled = 1;
- }
- else if (!(data->e_scope & SCOPE_NORELOC)) {
- // relocatable value
- putrelbits(1, 1);
- putrelbits(2, data->e_scope);
- putrelbits(8, data->e_value);
- putrelbits(8, data->e_value >> 8);
- handled = 1;
- }
-
- if (!handled) {
- if (can_extend_link(data)) {
- extend_link(data);
- putrelop(RELOP_WORD);
- putrel(0);
- putrel(0);
- }
- else {
- err[rflag]++;
- putrel(data->e_value);
- putrel(data->e_value >> 8);
- }
- }
- }
- else if (dsize == 4) {
- // Only numbers are allowed.
- if (data->e_scope != 0) {
- err[vflag]++;
- if (data->e_scope & SCOPE_NORELOC)
- err[rflag]++;
- }
- for (i = 0; i < dsize; i++)
- putrel(data->e_value >> (i * 8));
- }
- else
- error("internal dsize error");
- }
- }
-
- #define ET_NOARG_DISP (0)
- #define ET_NOARG (1)
- #define ET_BYTE (2)
- #define ET_WORD (5)
-
- void emit1(int opcode, int regvalh, struct expr *data, int type)
- {
- if (type == ET_BYTE && (data->e_value < -128 || data->e_value > 255))
- err[vflag]++;
-
- if (regvalh & 0x10000) {
- switch (type) {
- case ET_NOARG_DISP:
- emit(2, E_CODE, 0, regvalh >> 8, opcode);
- break;
- case ET_BYTE:
- emit(2, E_CODE8, data, regvalh >> 8, opcode);
- break;
- }
- }
- else if (regvalh & 0x8000) {
- switch (type) {
- case ET_NOARG_DISP:
- if (opcode & 0x8000)
- emit(4, E_CODE, 0, regvalh >> 8, opcode >> 8, disp, opcode);
- else
- emit(3, E_CODE, 0, regvalh >> 8, opcode, disp);
- break;
- case ET_NOARG:
- emit(2, E_CODE, 0, regvalh >> 8, opcode);
- break;
- case ET_BYTE:
- emit(3, E_CODE8, data, regvalh >> 8, opcode, disp);
- break;
- case ET_WORD:
- emit(2, E_CODE16, data, regvalh >> 8, opcode);
- }
- } else
- switch(type) {
- case ET_NOARG_DISP:
- case ET_NOARG:
- if (opcode & 0100000)
- emit(2, E_CODE, 0, opcode >> 8, opcode);
- else
- emit(1, E_CODE, 0, opcode);
- break;
- case ET_BYTE:
- emit(1, E_CODE8, data, opcode);
- break;
- case ET_WORD:
- if (opcode & 0100000)
- emit(2, E_CODE16, data, opcode >> 8, opcode);
- else
- emit(1, E_CODE16, data, opcode);
- }
- }
-
-
-
-
- void emitdad(int rp1,int rp2)
- {
- if (rp1 & 0x8000)
- emit(2, E_CODE, 0, rp1 >> 8, rp2 + 9);
- else
- emit(1, E_CODE, 0, rp2 + 9);
- }
-
-
- void emitjr(int opcode, struct expr *dest)
- {
- int disp = dest->e_value - dollarsign - 2;
-
- if (dest->e_scope & SCOPE_NORELOC)
- err[rflag]++;
-
- // Can't relative jump to other segments or an external
- // However, without .rel output we default to the code segment
- // for various reasons thus we let "jr 0" (and such) be acceptable
- // in those cases.
- if (((relopt && (dest->e_scope & SCOPE_SEGMASK) != segment) ||
- (dest->e_scope & SCOPE_EXTERNAL) ||
- disp > 127 || disp < -128) && z80)
- {
- if (jopt) {
- njrpromo++;
- switch (opcode) {
- case 0x10: // DJNZ
- emit(2, E_CODE16, dest, 0x05, 0xC2); // DEC B, JP NZ
- break;
- case 0x18: // JR
- emit(1, E_CODE16, dest, 0xC3); // JP
- break;
- case 0x20: // JR NZ
- emit(1, E_CODE16, dest, 0xC2); // JP NZ
- break;
- case 0x28: // JR Z
- emit(1, E_CODE16, dest, 0xCA); // JP Z
- break;
- case 0x30: // JR NC
- emit(1, E_CODE16, dest, 0xD2); // JP NC
- break;
- case 0x38: // JR C
- emit(1, E_CODE16, dest, 0xDA); // JP C
- break;
- default:
- err[vflag]++; // shouldn't happen!
- expr_free(dest);
- break;
- }
- }
- else {
- emit(2, E_CODE, 0, opcode, -2); // branch to itself
- err[vflag]++;
- expr_free(dest);
- }
- }
- else {
- emit(2, E_CODE, 0, opcode, disp);
- expr_free(dest);
- }
- }
-
- void checkjp(int op, struct expr *dest)
- {
- op &= 0x030;
- // Only applies to Z-80 output and if JP optimization checking is on.
- // JR only has z, nz, nc, c
- // A jump to the current segment might have been optimizable
- if (z80 && JPopt && (op == 0 || op == 010 || op == 020 || op == 030) &&
- (dest->e_scope & (SCOPE_SEGMASK | SCOPE_EXTERNAL)) == segment)
- {
- int disp = dest->e_value - dollarsign - 2;
- if (disp >= -128 && disp <= 127)
- err[jflag]++;
- }
- }
-
- /*
- * put out a byte of binary
- */
- void putbin(int v)
- {
- if(!outpass || !bopt) return;
- *outbinp++ = v;
- if (outbinp >= outbinm) flushbin();
-
- outoth[outoth_cnt++] = v;
- if (outoth_cnt == 256) flushoth();
- }
-
-
-
- /*
- * output one line of binary in INTEL standard form
- */
- void flushbin()
- {
- char *p;
- int check=outbinp-outbin;
-
- if (!outpass || !bopt)
- return;
- nbytes += check;
- if (check) {
- putc(':', fbuf);
- puthex(check, fbuf);
- puthex(olddollar>>8, fbuf);
- puthex(olddollar, fbuf);
- puthex(0, fbuf);
- check += (olddollar >> 8) + olddollar;
- olddollar += (outbinp-outbin);
- for (p=outbin; p<outbinp; p++) {
- puthex(*p, fbuf);
- check += *p;
- }
- puthex(256-check, fbuf);
- putc('\n', fbuf);
- outbinp = outbin;
- }
- }
-
-
-
- /*
- * put out one byte of hex
- */
- void puthex(int byte, FILE *buf)
- {
- putc(hexadec[(byte >> 4) & 017], buf);
- putc(hexadec[byte & 017], buf);
- }
-
- // Case-independent strcmp()
-
- int ci_strcmp(char *s1, char *s2)
- {
- int c1, c2;
- do {
- c1 = *s1++;
- if (c1 >= 'A' && c1 <= 'Z') c1 += 'a' - 'A';
- c2 = *s2++;
- if (c2 >= 'A' && c2 <= 'Z') c2 += 'a' - 'A';
- if (c1 != c2)
- return c1 - c2;
- } while (c1 && c2);
-
- return 0;
- }
-
- void flushoth()
- {
- int i, checksum;
-
- if (!outpass || !bopt || outoth_cnt == 0)
- return;
-
- fprintf(fcmd, "%c%c%c%c", 1, outoth_cnt + 2, oldothdollar, oldothdollar >> 8);
- fwrite(outoth, outoth_cnt, 1, fcmd);
-
- putcas(0x3c);
- putcas(outoth_cnt);
- putcas(oldothdollar);
- putcas(oldothdollar >> 8);
- checksum = oldothdollar + (oldothdollar >> 8);
- for (i = 0; i < outoth_cnt; i++) {
- putcas(outoth[i]);
- checksum += outoth[i];
- }
- putcas(checksum);
-
- oldothdollar += outoth_cnt;
- outoth_cnt = 0;
- }
-
- int casbit, casbitcnt = 0;
-
- void putcas(int byte)
- {
- fputc(byte, flcas);
-
- // Buffer 0 stop bit and the 8 data bits.
- casbit = (casbit << 9) | (byte & 0xff);
- casbitcnt += 9;
- while (casbitcnt >= 8) {
- casbitcnt -= 8;
- fputc(casbit >> casbitcnt, fcas);
- }
- }
-
- void casname(char *out, char *src)
- {
- char *base = basename(src);
- int i;
-
- out[0] = 'N';
- for (i = 1; i < 6; i++)
- out[i] = ' ';
-
- for (i = 0; *base && i < 6; base++) {
- if (ci_strcmp(base, ".z") == 0)
- break;
-
- if (*base >= 'a' && *base <= 'z') {
- *out++ = *base - ('a' - 'A');
- i++;
- }
- else if (*base >= 'A' && *base <= 'Z') {
- *out++ = *base;
- i++;
- }
- }
- }
-
- int relbit, relbitcnt = 0;
-
- void putrelbits(int count, int bits)
- {
- if (!outpass || !relopt)
- return;
-
- relbit <<= count;
- relbit |= bits & ((1 << count) - 1);
- relbitcnt += count;
-
- while (relbitcnt >= 8) {
- relbitcnt -= 8;
- fputc(relbit >> relbitcnt, frel);
- }
- }
-
- void putrel(int byte)
- {
- // Add 0 bit indicating byte to load at next counter
- putrelbits(1, 0);
- // Add byte to load
- putrelbits(8, byte);
- }
-
- void putrelname(char *str)
- {
- int len = strlen(str);
-
- // .rel file format can do strings 7 long but for compatibility
- // we restrict them to 6. I believe this is important because
- // extended link functions require a character when they wish to
- // operate on an external symbol.
- if (len > 6)
- len = 6;
- putrelbits(3, len);
- while (len-- > 0) {
- int ch = *str++;
- if (ch >= 'a' && ch <= 'z')
- ch -= 'a' - 'A';
- putrelbits(8, ch);
- }
- }
-
- void putrelsegref(int scope, int addr)
- {
- putrelbits(2, scope);
- putrelbits(8, addr);
- putrelbits(8, addr >> 8);
- }
-
- void putrelextaddr(int extaddr)
- {
- putrelsegref(extaddr >> 16, extaddr);
- }
-
-
- void putrelcmd(int relcmd)
- {
- putrelbits(1, 1);
- putrelbits(2, 0);
- putrelbits(4, relcmd);
- }
-
- void flushrel(void)
- {
- if (relbitcnt > 0)
- putrelbits(8 - relbitcnt, 0);
-
- if (relopt)
- fflush(frel);
- }
-
- /*
- * put out a line of output -- also put out binary
- */
- void list(int optarg)
- {
- unsigned char * p;
- int i;
- int lst;
- char seg = ' ';
-
- if (!expptr)
- linecnt++;
- addtoline('\0');
- if (outpass) {
- lst = iflist();
- if (lst) {
- lineout();
- if (nopt)
- fprintf(fout, "%4d:", linein[now_in]);
-
- if (copt)
- {
- if (emitptr > emitbuf && (memflag[emit_addr] & MEM_INST))
- {
- int low, high, fetch, low8080, high8080;
- zi_tstates(memory + emit_addr, &low, &high, &fetch, &low8080, &high8080);
- if (!z80) {
- low = low8080;
- high = high8080;
- }
-
- // Special case to catch promotion of djnz to DEC B JP NZ
- if (memory[emit_addr] == 5 && emitptr - emitbuf == 4) {
- low += 10;
- high += 10;
- }
-
- fprintf(fout, nopt ? "%5d" : "%4d", tstatesum[emit_addr]);
-
- fprintf(fout, "+%d", low);
- if (low != high)
- fprintf(fout, "+%d", high - low);
- }
- else
- {
- fprintf(fout, nopt ? "%5s-" : "%4s-", "");
- }
- }
-
- if (nopt || copt)
- fprintf(fout, "\t");
-
- puthex(optarg >> 8, fout);
- puthex(optarg, fout);
- if (relopt)
- seg = SEGCHAR(segment);
- fputc(seg, fout);
- fputc(' ', fout);
- for (p = emitbuf; (p < emitptr) && (p - emitbuf < 4); p++) {
- puthex(*p, fout);
- }
- for (i = 4 - (p-emitbuf); i > 0; i--)
- fputs(" ", fout);
-
- putc('\t', fout);
- fputs(linebuf, fout);
- }
-
- if (bopt) {
- if (emitptr > emitbuf) {
- fprintf(fbds, "%04x %04x d ", dollarsign, emit_addr);
- for (p = emitbuf; p < emitptr; p++)
- fprintf(fbds, "%02x", *p & 0xff);
- fprintf(fbds, "\n");
- }
- fprintf(fbds, "%04x %04x s %s", dollarsign, emit_addr, linebuf);
-
- for (p = emitbuf; p < emitptr; p++)
- putbin(*p);
- }
-
-
- p = emitbuf+4;
- while (lst && gopt && p < emitptr) {
- lineout();
- if (nopt) putc('\t', fout);
- fputs(" ", fout);
- for (i = 0; (i < 4) && (p < emitptr);i++) {
- puthex(*p, fout);
- p++;
- }
- putc('\n', fout);
- }
-
- lsterr2(lst);
- } else
- lsterr1();
-
- dollarsign += emitptr - emitbuf;
- emit_addr += emitptr - emitbuf;
- dollarsign &= 0xffff;
- emit_addr &= 0xffff;
- emitptr = emitbuf;
- lineptr = linebuf;
- }
-
-
-
- /*
- * keep track of line numbers and put out headers as necessary
- */
- void lineout()
- {
- if (!printer_output)
- return;
-
- if (line == 60) {
- if (popt)
- putc('\014', fout); /* send the form feed */
- else
- fputs("\n\n\n\n\n", fout);
- line = 0;
- }
- if (line == 0) {
- fprintf(fout, "\n\n%s %s\t%s\t Page %d\n\n\n",
- &timp[4], &timp[20], title, page++);
- line = 4;
- }
- line++;
- }
-
-
- /*
- * cause a page eject
- */
- void eject()
- {
- if (printer_output)
- return;
-
- if (outpass && iflist()) {
- if (popt) {
- putc('\014', fout); /* send the form feed */
- } else {
- while (line < 65) {
- line++;
- putc('\n', fout);
- }
- }
- }
- line = 0;
- }
-
-
- /*
- * space n lines on the list file
- */
- void space(int n)
- {
- int i ;
- if (outpass && iflist())
- for (i = 0; i<n; i++) {
- lineout();
- putc('\n', fout);
- }
- }
-
- /*
- * Error handling - pass 1
- */
- void lsterr1()
- {
- int i;
- for (i = 0; i <= mflag; i++)
- if (err[i]) {
- if (topt)
- errorprt(i);
- passfail = 1;
- err[i] = 0;
- }
- }
-
-
- /*
- * Error handling - pass 2.
- */
- void lsterr2(int lst)
- {
- int i;
- for (i=0; i<FLAGS; i++)
- if (err[i]) {
- if (i < FIRSTWARN)
- passfail = 1;
- if (lst) {
- char *desc = errname[i];
- char *type = i < FIRSTWARN ? " error" : " warning";
- if (errdetail[i][0]) {
- desc = errdetail[i];
- type = "";
- }
- lineout();
- fprintf(fout, "%c %s%s\n",
- errlet[i], desc, type);
- }
- err[i] = 0;
- keeperr[i]++;
- if (i > mflag && topt)
- errorprt(i);
- }
-
- fflush(fout); /*to avoid putc(har) mix bug*/
- }
-
- /*
- * print diagnostic to error terminal
- */
- void errorprt(int errnum)
- {
- char *desc = errname[errnum];
- char *type = errnum < FIRSTWARN ? " error" : " warning";
- if (errdetail[errnum][0]) {
- desc = errdetail[errnum];
- type = "";
- }
- fprintf(stderr, "%s(%d) : %s%s",
- src_name[now_in], linein[now_in], desc, type);
-
- errdetail[errnum][0] = '\0';
-
- fprintf(stderr, "\n");
- fprintf(stderr, "%s\n", linebuf);
- fflush(stderr) ;
- }
-
- void errwarn(int errnum, char *message)
- {
- err[errnum]++;
- strcpy(errdetail[errnum], message);
- }
-
-
- /*
- * list without address -- for comments and if skipped lines
- */
- void list1()
- {
- int lst;
-
- addtoline('\0');
- lineptr = linebuf;
- if (!expptr) linecnt++;
- if (outpass) {
- if ((lst = iflist())) {
- lineout();
- if (nopt)
- fprintf(fout, "%4d:\t", linein[now_in]);
- if (copt)
- fprintf(fout, "\t");
- fprintf(fout, "\t\t%s", linebuf);
- lsterr2(lst);
- }
- if (bopt)
- fprintf(fbds, "%04x %04x s %s", dollarsign, emit_addr, linebuf);
- }
- else
- lsterr1();
- }
-
-
- /*
- * see if listing is desired
- */
- int iflist()
- {
- int i, j;
-
- if (inmlex)
- return mlex_list_on;
-
- if (lston)
- return(1) ;
- if (lopt)
- return(0);
- if (*ifptr && !fopt)
- return(0);
- if (!lstoff && !expptr)
- return(1);
- j = 0;
- for (i=0; i<FLAGS; i++)
- if (err[i])
- j++;
- if (expptr)
- return(mopt || j);
- if (eopt && j)
- return(1);
- return(0);
- }
-
- void do_equ(struct item *sym, struct expr *val, int call_list);
- void do_defl(struct item *sym, struct expr *val, int call_list);
-
- // GWP - This avoids an apparent bug in bison as it tries to start out the
- // Not needed under gcc which defines __STDC__ so I guard it to prevent
- // warnings.
- // yyparse() function with yyparse() ; { }.
- #ifndef __STDC__
- #define __STDC__
- #endif
-
- #define PSTITL (0) /* title */
- #define PSRSYM (1) /* rsym */
- #define PSWSYM (2) /* wsym */
- #define PSINC (3) /* include file */
- #define PSMACLIB (4) /* maclib (similar to include) */
-
- #define SPTITL (0) /* title */
- #define SPSBTL (1) /* sub title */
- #define SPNAME (2) /* name */
- #define SPCOM (3) /* comment */
- #define SPPRAGMA (4) /* pragma */
-
- %}
-
- %union {
- struct expr *exprptr;
- struct item *itemptr;
- int ival;
- char *cval;
- }
-
- %token <cval> STRING
- %token <itemptr> NOOPERAND
- %token <itemptr> ARITHC
- %token ADD
- %token <itemptr> LOGICAL
- %token <itemptr> AND
- %token <itemptr> OR
- %token <itemptr> XOR
- %token <ival> ANDAND
- %token <ival> OROR
- %token <itemptr> BIT
- %token CALL
- %token <itemptr> INCDEC
- %token <itemptr> DJNZ
- %token EX
- %token <itemptr> IM
- %token PHASE
- %token DEPHASE
- %token <itemptr> TK_IN
- %token <itemptr> JR
- %token LD
- %token <itemptr> TK_OUT
- %token <itemptr> PUSHPOP
- %token <itemptr> RET
- %token <itemptr> SHIFT
- %token <itemptr> RST
- %token <itemptr> REGNAME
- %token <itemptr> IXYLH
- %token <itemptr> ACC
- %token <itemptr> C
- %token <itemptr> RP
- %token <itemptr> HL
- %token <itemptr> INDEX
- %token <itemptr> AF
- %token AFp
- %token <itemptr> SP
- %token <itemptr> MISCREG
- %token <itemptr> COND
- %token <itemptr> SPCOND
- %token <ival> NUMBER
- %token <itemptr> UNDECLARED
- %token END
- %token ORG
- %token ASSERT
- %token TSTATE
- %token <ival> T
- %token <ival> TILO
- %token <ival> TIHI
- %token SETOCF
- %token <ival> OCF
- %token <ival> LOW
- %token <ival> HIGH
- %token DC
- %token DEFB
- %token DEFD
- %token DEFS
- %token DEFW
- %token EQU
- %token DEFL
- %token <itemptr> LABEL
- %token <itemptr> EQUATED
- %token <itemptr> WASEQUATED
- %token <itemptr> DEFLED
- %token <itemptr> MULTDEF
- %token <ival> MOD
- %token <ival> SHL
- %token <ival> SHR
- %token <ival> NOT
- %token <ival> LT
- %token <ival> GT
- %token <ival> LE
- %token <ival> GE
- %token <ival> NE
- %token IF_TK
- %token ELSE_TK
- %token ENDIF_TK
- %token <itemptr> ARGPSEUDO
- %token <itemptr> INCBIN
- %token <itemptr> LIST
- %token <itemptr> MINMAX
- %token MACRO
- %token <itemptr> MNAME
- %token ARG
- %token ENDM
- %token <ival> ONECHAR
- %token <ival> TWOCHAR
- %token JRPROMOTE
- %token JPERROR
- %token PUBLIC
- %token EXTRN
- %token MRAS_MOD
- %token <itemptr> SETSEG INSTSET
- %token LXI DAD STAX STA SHLD LDAX LHLD LDA MVI MOV
- %token <itemptr> INXDCX INRDCR PSW JUMP8 JP CALL8 ALUI8
- %token <itemptr> SPECIAL
- %token RAWTOKEN LOCAL
- // New token types for ZNONSTD support
- %token <itemptr> LD_XY ST_XY MV_XY ALU_XY BIT_XY SHIFT_XY INP OUTP JR_COND
- %token <itemptr> LDST16 ARITH16
- // Tokens for improved macro support
- %token REPT IRPC IRP EXITM
- %token NUL
- %token <itemptr> MPARM
-
- %type <itemptr> label.part symbol
- %type <ival> allreg reg evenreg ixylhreg realreg mem memxy pushable bcdesp bcdehlsp mar condition
- %type <ival> spcondition
- %type <exprptr> noparenexpr parenexpr expression lxexpression
- %type <ival> maybecolon maybeocto
- %type <ival> evenreg8 reg8 m pushable8
- // Types for improved macro support
- %type <cval> locals
-
- %right '?' ':'
- %left OROR
- %left ANDAND
- %left '|' OR
- %left '^' XOR
- %left '&' AND
- %left '=' NE
- %left '<' '>' LT GT LE GE
- %left SHL SHR
- %left '+' '-'
- %left '*' '/' '%' MOD
- %right '!' '~' NOT UNARY
-
- %{
- char *cp;
- int i;
-
- void do_equ(struct item *sym, struct expr *val, int call_list)
- {
- expr_reloc_check(val);
- switch(sym->i_token) {
- case UNDECLARED: case WASEQUATED:
- if (sym->i_token == WASEQUATED &&
- (sym->i_value != val->e_value ||
- ((sym->i_scope ^ val->e_scope) & SCOPE_SEGMASK)))
- {
- if (outpass) {
- if (sym->i_value != val->e_value)
- sprintf(detail, "%s error - %s went from $%04x to $%04x",
- errname[pflag], sym->i_string, sym->i_value, val->e_value);
- else
- sprintf(detail, "%s error - %s changed scope",
- errname[pflag], sym->i_string);
- errwarn(pflag, detail);
- }
- else
- passretry = 1;
- }
-
- sym->i_token = EQUATED;
- sym->i_value = val->e_value;
- sym->i_scope |= val->e_scope;
- break;
- default:
- // m80 allows multiple equates as long as the value
- // does not change. So does newer zmac.
- if (sym->i_value != val->e_value ||
- ((sym->i_scope ^ val->e_scope) & SCOPE_SEGMASK))
- {
- err[mflag]++;
- sym->i_token = MULTDEF;
- }
- }
- sym->i_scope &= ~SCOPE_BUILTIN;
- if (call_list)
- list(val->e_value);
- expr_free(val);
- }
-
- void do_defl(struct item *sym, struct expr *val, int call_list)
- {
- expr_reloc_check(val);
- switch(sym->i_token) {
- case UNDECLARED: case DEFLED:
- sym->i_token = DEFLED;
- sym->i_value = val->e_value;
- sym->i_scope = (sym->i_scope & SCOPE_SEGMASK) | val->e_scope;
- break;
- default:
- err[mflag]++;
- sym->i_token = MULTDEF;
- }
- if (call_list)
- list(val->e_value);
- expr_free(val);
- }
-
- %}
-
- %%
-
- statements:
- /* Empty file! */
- |
- statements statement
- ;
-
-
- statement:
- label.part '\n' {
- // An identfier without a colon all by itself on a line
- // will be interpreted as a label. But there's a very
- // good chance it is a misspelling of an instruction or
- // pseudo-op name creating silent errors. Since the condition
- // is unusual we print a warning. Unless it is followed by
- // a colon in which case there's no ambiguity.
- if ($1 && !firstcol && coloncnt == 0 && outpass) {
- fprintf(stderr, "%s(%d): warning: '%s' treated as label (instruction typo?)\n",
- src_name[now_in], linein[now_in], $1->i_string);
- fprintf(stderr, "\tAdd a colon or move to first column to stop this warning.\n");
- }
-
- if ($1) list(dollarsign);
- else list1();
- }
- |
- label.part { list_dollarsign = 1; } operation '\n' {
- list(list_dollarsign ? dollarsign : list_addr);
- }
- |
- symbol EQU expression '\n' {
- do_equ($1, $3, 1);
- }
- |
- symbol '=' expression '\n' {
- do_equ($1, $3, 1); // TODO: is '=' equate or defl?
- }
- |
- symbol DEFL expression '\n' {
- do_defl($1, $3, 1);
- }
- |
- symbol MINMAX expression ',' expression '\n' {
- int val3 = $3->e_value;
- int val5 = $5->e_value;
- expr_reloc_check($3);
- expr_reloc_check($5);
- expr_scope_same($3, $5);
- switch ($1->i_token) {
- case UNDECLARED: case DEFLED:
- $1->i_token = DEFLED;
- $1->i_scope |= $3->e_scope;
- if ($2->i_value) /* max */
- list($1->i_value = (val3 > val5? val3:val5));
- else list($1->i_value = (val3 < val5? val3:val5));
- break;
- default:
- err[mflag]++;
- $1->i_token = MULTDEF;
- list($1->i_value);
- }
- expr_free($3);
- expr_free($5);
- }
- |
- IF_TK expression '\n' {
- expr_number_check($2);
- if (ifptr >= ifstmax)
- error("Too many ifs");
- else
- *++ifptr = !($2->e_value);
-
- saveopt = fopt;
- fopt = 1;
- list($2->e_value);
- fopt = saveopt;
- expr_free($2);
- }
- |
- ELSE_TK '\n' {
- /* FIXME: it would be nice to spot repeated ELSEs, but how? */
- *ifptr = !*ifptr;
- saveopt = fopt;
- fopt = 1;
- list1();
- fopt = saveopt;
- }
- |
- ENDIF_TK '\n' {
- if (ifptr == ifstack) err[bflag]++;
- else --ifptr;
- list1();
- }
- |
- label.part END '\n' {
- list(dollarsign);
- peekc = 0;
- }
- |
- label.part END expression '\n' {
- expr_reloc_check($3);
- xeq_flag++;
- xeq = $3->e_value & 0xffff;
- list($3->e_value);
- peekc = 0;
- rel_main = (($3->e_scope & SCOPE_SEGMASK) << 16) | xeq;
- expr_free($3);
- }
- |
- label.part DEFS expression '\n' {
- expr_number_check($3);
- if ($3->e_value < 0) err[vflag]++;
- if ($3->e_value > 0) {
- if (!phaseflag) {
- list(dollarsign);
- flushbin();
- flushoth();
- dollarsign += $3->e_value;
- olddollar += $3->e_value;
- oldothdollar += $3->e_value;
- emit_addr += $3->e_value;
- advance_segment($3->e_value);
- putrelcmd(RELCMD_SETLOC);
- putrelsegref(segment, seg_pos[segment]);
- }
- else
- dc($3->e_value, 0);
- }
- else
- list1();
-
- expr_free($3);
- }
- |
- label.part DEFS expression ',' expression '\n' {
- expr_number_check($3);
- expr_number_check($5);
- if ($3->e_value < 0) err[vflag]++;
- if ($5->e_value < -128 || $5->e_value > 127) err[vflag]++;
- if ($3->e_value > 0) {
- dc($3->e_value, $5->e_value);
- }
- else
- list1();
-
- expr_free($3);
- expr_free($5);
- }
- |
- label.part DC ONECHAR '\n' { emit(1, E_DATA, expr_num($3 | 0x80)); list(dollarsign); }
- |
- label.part DC TWOCHAR '\n' { emit(1, E_DATA, expr_num($3)); emit(1, E_DATA, expr_num(($3 >> 8) | 0x80)); list(dollarsign); }
- |
- label.part DC STRING '\n'
- {
- for (cp = $3; *cp != '\0'; cp++)
- if (!cp[1])
- emit(1, E_DATA, expr_num(*cp | 0x80));
- else
- emit(1, E_DATA, expr_num(*cp));
-
- list(dollarsign);
- }
- |
- label.part DC expression ',' expression '\n'
- {
- expr_number_check($3);
- expr_number_check($5);
- dc($3->e_value, $5->e_value);
- expr_free($3);
- expr_free($5);
- }
- |
- ARGPSEUDO arg_on ARG arg_off '\n' {
- list1();
- switch ($1->i_value) {
-
- case PSTITL: /* title */
- lineptr = linebuf;
- cp = tempbuf;
- title = titlespace;
- while ((*title++ = *cp++) && (title < &titlespace[TITLELEN]));
- *title = 0;
- title = titlespace;
- break;
-
- case PSRSYM: /* rsym */
- if (pass2) break;
- insymtab(tempbuf);
- break;
-
- case PSWSYM: /* wsym */
- writesyms = malloc(strlen(tempbuf)+1);
- strcpy(writesyms, tempbuf);
- break;
- case PSINC: /* include file */
- next_source(tempbuf) ;
- break ;
- case PSMACLIB:
- strcat(tempbuf, ".lib");
- next_source(tempbuf);
- break;
- }
- }
- |
- ARGPSEUDO arg_on arg_off '\n' {
- fprintf(stderr, "Missing argument of '%s'\n", $1->i_string);
- err[fflag]++;
- list(dollarsign);
- }
- |
- label.part INCBIN arg_on ARG arg_off '\n' {
- incbin(tempbuf);
- }
- |
- SPECIAL { raw = 1; } RAWTOKEN {
- int quote = 0;
- char *p, *q;
- switch ($1->i_value) {
- case SPTITL:
- cp = tempbuf;
- title = titlespace;
- if (*cp == '\'' || *cp == '"')
- quote = *cp++;
- while ((*title++ = *cp++) && (title < &titlespace[TITLELEN]));
- if (quote && title > titlespace + 1 && title[-2] == quote)
- title[-2] = '\0';
- title = titlespace;
- list1();
- break;
- case SPSBTL:
- err[warn_notimpl]++;
- list1();
- break;
- case SPNAME:
- // Drop surrounding ('') if present
- p = tempbuf;
- q = strchr(tempbuf, '\0') - 1;
- if (*p == '(' && *q == ')' && q > p) p++, q--;
- if (*p == '\'' && *q == '\'' && q > p) p++, q--;
- q[1] = '\0';
- strncpy(progname, p, sizeof progname);
- progname[sizeof progname - 1] = '\0';
- list1();
- break;
- case SPCOM:
- quote = *tempbuf;
- list1();
- for (;;) {
- raw = 1;
- yychar = yylex();
- list1();
- if (yychar == 0)
- break;
- if (*tempbuf == quote) {
- yychar = yylex();
- break;
- }
- }
- break;
-
- case SPPRAGMA:
- if (strncmp(tempbuf, "bds", 3) == 0 && bopt && outpass) {
- fprintf(fbds, "%s\n", tempbuf + 4);
- }
- list1();
- break;
- }
- }
- |
- LIST '\n' {
- goto dolopt; }
- |
- LIST expression '\n' {
- int enable = $2->e_value;
- expr_number_check($2);
- expr_free($2);
- goto doloptA;
- dolopt:
- enable = 1;
- doloptA:
- linecnt++;
- if (outpass) {
- lineptr = linebuf;
- switch ($1->i_value) {
- case 0: /* list */
- if (enable < 0) lstoff = 1;
- if (enable > 0) lstoff = 0;
- break;
-
- case 1: /* eject */
- if (enable) eject();
- break;
-
- case 2: /* space */
- if ((line + enable) > 60) eject();
- else space(enable);
- break;
-
- case 3: /* elist */
- eopt = edef;
- if (enable < 0) eopt = 0;
- if (enable > 0) eopt = 1;
- break;
-
- case 4: /* fopt */
- fopt = fdef;
- if (enable < 0) fopt = 0;
- if (enable > 0) fopt = 1;
- break;
-
- case 5: /* gopt */
- gopt = gdef;
- if (enable < 0) gopt = 1;
- if (enable > 0) gopt = 0;
- break;
-
- case 6: /* mopt */
- mopt = mdef;
- if (enable < 0) mopt = 0;
- if (enable > 0) mopt = 1;
- }
- }
- }
- |
- JRPROMOTE expression '\n' {
- expr_number_check($2);
- jopt = !!$2->e_value;
- list1();
- expr_free($2);
- }
- |
- JPERROR expression '\n' {
- expr_number_check($2);
- JPopt = !!$2->e_value;
- list1();
- expr_free($2);
- }
- |
- PUBLIC public.list '\n' {
- list1();
- }
- |
- EXTRN extrn.list '\n' {
- list1();
- }
- |
- MRAS_MOD '\n' {
- char *p = strchr(modstr, '\0') - 1;
- for (; p >= modstr; p--) {
- (*p)++;
- if (*p < 'Z')
- break;
- *p = 'A';
- }
- list1();
- }
- |
- SETSEG '\n'…
Large files files are truncated, but you can click here to view the full file