PageRenderTime 120ms CodeModel.GetById 47ms RepoModel.GetById 1ms app.codeStats 1ms

/Tools/zmac/src/zmac.y

https://bitbucket.org/tim_ring/tz80-1
Happy | 7298 lines | 6532 code | 766 blank | 0 comment | 0 complexity | 95f9f1c4a1a8aec4e9cc5592fd34d0ab MD5 | raw file
  1. %{
  2. // GWP - keep track of version via hand-maintained date stamp.
  3. #define VERSION "3dec2014"
  4. /*
  5. * zmac -- macro cross-assembler for the Zilog Z80 microprocessor
  6. *
  7. * Bruce Norskog 4/78
  8. *
  9. * Last modification 1-18-87 by cdk
  10. * This assembler is modeled after the Intel 8080 macro cross-assembler
  11. * for the Intel 8080 by Ken Borgendale. The major features are:
  12. * 1. Full macro capabilities
  13. * 2. Conditional assembly
  14. * 3. A very flexible set of listing options and pseudo-ops
  15. * 4. Symbol table output
  16. * 5. Error report
  17. * 6. Elimination of sequential searching
  18. * 7. Commenting of source
  19. * 8. Facilities for system definiton files
  20. *
  21. * Revision History:
  22. *
  23. * jrp 3-8-82 Converted to run on Vax, updated syntax to conform better
  24. * to the Zilog standard.
  25. *
  26. * jrp 3-15-82 Added underscore as a character type in the lex table
  27. * 'numpart' (0x5F).
  28. *
  29. * Changed maximum number of characters in a label to 15
  30. * from 7. Note that 'putsymtab' uses this value inside
  31. * of a quoted string, so we use 15.
  32. *
  33. * jrp 2-15-83 Fixed 'getlocal' to return better local labels. It used
  34. * to crash after 6 invocations.
  35. *
  36. * jrp 6-7-83 Fixed bug in the ADD IX,... instruction.
  37. *
  38. * jrp 5-11-84 Added code to print unused labels out with the symbol table
  39. * Also sped up the macro processor by using stdio.
  40. *
  41. * jrp 5-22-84 Added include files ala ormac
  42. *
  43. * jrp 8-27-84 Added PHASE/DEPHASE commands
  44. *
  45. * cdk 9-20-86 Converted to run on a Pyramid. This meant changing yylval
  46. * to be a %union, and then putting in the appropriate
  47. * typecasts where ints are pointers are used interchangeably.
  48. * The current version still probably won't run on machines where
  49. * sizeof(int) != sizeof(char *).
  50. * Also changed emit() to use varargs, and got rid of the
  51. * old style = in front of yacc action code.
  52. * -Colin Kelley vu-vlsi!colin
  53. *
  54. * cdk 10-2-86 Added some more typecasts to keep lint a little happier.
  55. * Removed several unused variables. Changed most vars
  56. * declared as char to int, since many of them were being
  57. * compared with -1! I still don't know what's going on with
  58. * est[][] being malloc'd and free'd everywhere...it looks pretty
  59. * fishy...
  60. *
  61. * cdk 1-18-87 Added MIO code to emulate 'mfile' using malloc()'d memory.
  62. * This was needed to get the code to work when compiled under
  63. * MSC 4.0 on a PC, and it's probably faster anyway.
  64. *
  65. * cdk 2-5-87 Added 'cmp' as a synonym for 'cp', 'jmp' as a synonym for
  66. * 'jp', and added tolerance of accumulator specification for arithmetic
  67. * and logical instructions. (For example, 'or a,12' is now accepted,
  68. * same as 'or 12'.)
  69. *
  70. * gwp 12-29-08 Changes to allow compilation with modern C compiler and using bison
  71. * as the .y to .c converter. assert, tstate pseudo-ops.
  72. * t(), tilo(), tihi() functions. ==, <=, >=, !=, !, <, > operators.
  73. * -c to turn cycle counts off in listing. Usage, -h and version.
  74. *
  75. * gwp 9-26-10 Add ocf() and setocf to track and set op code fetch counts.
  76. * Add sett as an alias for tstate
  77. *
  78. * gwp 12-30-11 Add undocumented instructions sl1, pfix, pfiy, in (c), out (c),0
  79. * bit/set/res (ixy+d),reg and ld/inc/dec ixylh.
  80. *
  81. * gwp 2-8-12 Increase MAXIFS massively due to massive lowt macro
  82. *
  83. * gwp 2-11-12 Support 32 bit constants. '%' alias for MOD. Add defd, dword.
  84. * lo(x) and hi(x) for easy low and high byte extraction. Allow
  85. * filenames longer than 15 characters. All output to "zout" subdirectory
  86. * of source file.
  87. *
  88. * gwp 2-15-12 Perform multiple passes while equates are changing. Support
  89. * .label for temporary label definitions and _label for file
  90. * scoped labels. Allow '.' within labels. Assert listing bugfix.
  91. *
  92. * gwp 4-27-12 Implement $ prefixed hex constants and double-quoted strings.
  93. *
  94. * gwp 6-30-12 Minor changes to allow compilation with gcc.
  95. *
  96. * gwp 9-05-12 incbin added.
  97. *
  98. * gwp 11-24-12 Fix macro expansion bug when symbol larger than MAXSYMBOLSIZE
  99. * due to file name prepending when symbol starts with '_'.
  100. *
  101. * gwp 12-04-12 Optional JR promotion and JP demotion errors. Output a warning
  102. * if no execute address given. Output ".bds" file to enable easy
  103. * simple source level debugging.
  104. *
  105. * gwp 4-14-13 Parens in expressions, else, .pseudo, full set of C operators
  106. * with conventional precedence and various aliases and code
  107. * changes to make source similar to zmac 1.3 on internet.
  108. *
  109. * gwp 5-5-13 .cmd,.cas,.lcas,.bin output. dc (both MACRO-80 and EDAS types).
  110. * lo, hi renamed to low, high and make unary operators. Allow
  111. * label::, placeholder public, extern declarations. Bug fixes
  112. * in defs, t, ocf, tihi, tilo in phase mode. Initial support
  113. * for -I include directories. 0x hex constants. --mras flag for
  114. * limited MRAS compatibility (allows $ in labels, $? to start
  115. * labels).
  116. *
  117. * gwp 4-6-13 --rel for .rel (Microsoft linker) output and extern, public,
  118. * aseg, cseg, dseg in support (big emit + expression revamp).
  119. * -I follows C preprocessor convention, output relative to
  120. * current directory. 8080 mnemonics, .z80, .8080, -z, -8.
  121. * Change .bin to .cim. Warn on labels not in first column.
  122. *
  123. * gwp 8-11-13 Allow $ to start identifiers and do '$' dropping when macro
  124. * parsed so we no longer need to drop '$' in identifiers.
  125. * Even $FCB allowed, with warning. Add --zmac for backwards
  126. * compatibility with zmac. ` now used for joining in macros.
  127. * Most reserved words can be used as labels or variables.
  128. * Free-form title, name, comment, subttl parsing. Allow #arg
  129. * for macro arguments (in --mras mode). Support <CR> delimited
  130. * files. Add .ams output. Integrate documentation (--doc).
  131. *
  132. * gwp 3-12-14 Emit jr even if out of range. z80.lib support.
  133. * Warning and bug fixes from Mark Galanger.
  134. * Macros can override built-ins and are no longer listed
  135. * in symbol table. A, B, C, D, E, H, L, M, PSW, SP are
  136. * pre-defined values which can be used in data statements
  137. * (db, dw, dd). Reserved words can be equated but are only
  138. * accessbile in data. SET can be used in place of DEFL
  139. * (MAC and MACRO-80 agree on this). '=' can be used in place
  140. * of EQU. 'maclib file' includes 'file.lib'. Bug fix in "dw 0,$".
  141. * Removed error flagging in expressions which could cause parse
  142. * to fail from that point onwards.
  143. * expression(ix) equivalent to (ix + expression).
  144. * Macro expanded lines didn't go through the line analyzer.
  145. * Empty macro arguments (e.g., mac 1,,2)
  146. * Implemented rept, irp, irpc, exitm. Add more detail on phase
  147. * errors. '' is an empty string in db/ascii/etc, 0 otherwise.
  148. * Almost any name can be used as a macro parameter name.
  149. * Allow 'if' in first column.
  150. * Fix .rel mode bug in dc, incbin.
  151. * Emit .bds output for dc, incbin.
  152. * Allow assembly to wrap past end of memory.
  153. * "pragma bds" for raw output to .bds file. Also output equates
  154. * to .bds file.
  155. * Macro bug fix from Sergey Erokhin.
  156. */
  157. #define MIO /* use emulation routines from mio.c */
  158. #include <stdio.h>
  159. #include <string.h>
  160. #include <stdlib.h>
  161. #include <stdarg.h>
  162. #include <time.h>
  163. #include <sys/stat.h>
  164. #ifdef WIN32
  165. #include <windows.h> // just for colouring the output
  166. #endif
  167. #include "zi80dis.h"
  168. #ifdef vax11c
  169. #define unlink(filename) delete(filename)
  170. #endif
  171. #ifdef MIO
  172. #include "mio.h"
  173. FILE *mfopen();
  174. #else
  175. #define mfopen(filename,mode) fopen(filename,mode)
  176. #define mfclose(filename,mode) fclose(filename,mode)
  177. #define mfputc(c,f) putc(c,f)
  178. #define mfgetc(f) getc(f)
  179. #define mfseek(f,loc,origin) fseek(f,loc,origin)
  180. #define mfread(ptr,size,nitems,f) fread(ptr,size,nitems,f)
  181. #define mfwrite(ptr,size,nitems,f) fread(ptr,size,nitems,f)
  182. #endif /* MIO */
  183. /*
  184. * DEBUG turns on pass reporting.
  185. * DBUG enables -d to allow yacc/bison yydebug increment (but must be passed
  186. * on the command line)
  187. * Macro debug and Token debug enables.
  188. #define DEBUG
  189. #define M_DEBUG
  190. #define T_DEBUG
  191. */
  192. #ifdef DBUG
  193. #define YYDEBUG 1
  194. #endif
  195. #define ITEMTABLESIZE 100000
  196. #define TEMPBUFSIZE (1000+MAXSYMBOLSIZE)
  197. #define LINEBUFFERSIZE 1000
  198. #define EMITBUFFERSIZE 200
  199. #define MAXSYMBOLSIZE 40
  200. #define IFSTACKSIZE 20
  201. // GWP - I use lots of if's with my lowt macro
  202. #define MAXIFS 65536
  203. #define TITLELEN 50
  204. #define BINPERLINE 16
  205. #define PARMMAX 25
  206. #define MAXEXP 25
  207. #define SYMMAJIC 07203
  208. #define NEST_IN 32
  209. #define MAXPASS 32
  210. #define MAXINCPATH 32
  211. int iflist();
  212. int yylex();
  213. int phaseaddr(int addr);
  214. int nextchar();
  215. int getcol();
  216. int skipline(int ac);
  217. int tokenofitem(int deftoken, int keyexclude, int keyinclude);
  218. int getm();
  219. int counterr();
  220. int countwarn();
  221. void yyerror(char *err)
  222. {} /* we will do our own error printing */
  223. struct argparse {
  224. char *arg; // output buffer for argument
  225. int argsize; // size of output buffer
  226. int (*getch)(struct argparse *); // get next character
  227. int *peek; // pointer single item pushback buffer
  228. int macarg; // working on macro arguments
  229. char *user_ptr; // state for getch
  230. int user_int; // state for getch
  231. int user_peek; // state for getch
  232. int didarg; // internal parsing state
  233. int numarg; // internal parsing state
  234. };
  235. int getarg(struct argparse *ap);
  236. struct item {
  237. char *i_string;
  238. int i_value;
  239. int i_token;
  240. int i_uses;
  241. int i_scope;
  242. int i_chain;
  243. };
  244. void itemcpy(struct item *dst, struct item *src);
  245. struct item *keyword(char *name);
  246. #define SCOPE_NONE (0)
  247. #define SCOPE_PROGRAM (1)
  248. #define SCOPE_DATA (2)
  249. #define SCOPE_PUBLIC (4)
  250. #define SCOPE_EXTERNAL (8)
  251. #define SCOPE_NORELOC (16)
  252. #define SCOPE_BUILTIN (32) /* abuse */
  253. #define SCOPE_SEGMASK (3)
  254. #define SCOPE_SEG(s) ((s) & SCOPE_SEGMASK)
  255. struct expr {
  256. int e_value;
  257. int e_scope;
  258. int e_token;
  259. struct item *e_item;
  260. struct expr *e_left;
  261. struct expr *e_right;
  262. };
  263. #define EXPR_SEG(e) SCOPE_SEG(e->e_scope)
  264. FILE *fout,
  265. *fbuf,
  266. *fbds,
  267. *fcmd,
  268. *fcas,
  269. *flcas,
  270. *fcim,
  271. *fams,
  272. *frel,
  273. *fin[NEST_IN],
  274. *now_file ;
  275. int pass2; /*set when pass one completed*/
  276. int outpass; // set when we decide to stop doing passes */
  277. int passfail; // set when an error means passes should not continue
  278. int passretry; // set when an inconsistency will require another pass
  279. int dollarsign ; /* location counter */
  280. int olddollar ; /* kept to put out binary */
  281. int oldothdollar; // output address of next .cmd/.cas/.lcas block
  282. int emit_addr; // were code and data are being placed in memory
  283. int tstates; // cumulative T-states
  284. int ocf; // cumulative op code fetches
  285. int llseq; // local label sequence number
  286. int mras; // MRAS semi-compatibility mode
  287. int zcompat; // Original zmac compatibility mode
  288. char modstr[8]; // Replacement string for '?' in labels when MRAS compatible
  289. int relopt; // Only output .rel files.
  290. char progname[8]; // Program name for .rel output
  291. int note_depend; // Print names of files included
  292. int firstcol;
  293. int logcol;
  294. int coloncnt;
  295. int full_exprs; // expression parsing mode allowing almost any identifier
  296. struct item *label, pristine_label; //
  297. int list_dollarsign;// flag used to change list output for some operations
  298. int list_addr; // address to display for operation if !list_dollarsign
  299. // Include file search path
  300. char *incpath[MAXINCPATH];
  301. int incpath_cnt;
  302. /* program counter save for PHASE/DEPHASE */
  303. int phdollar, phbegin, phaseflag ;
  304. char *src_name[NEST_IN] ;
  305. int linein[NEST_IN] ;
  306. int now_in ;
  307. // These first 5 errors are singled out in lsterr1() for reasons I don't
  308. // quite understand.
  309. #define bflag 0 /* balance error */
  310. #define eflag 1 /* expression error */
  311. #define fflag 2 /* syntax error */
  312. #define iflag 3 /* bad digits */
  313. #define mflag 4 /* multiply defined */
  314. #define pflag 5 /* phase error */
  315. #define uflag 6 /* undeclared used */
  316. #define vflag 7 /* value out of range */
  317. #define oflag 8 /* phase/dephase error */
  318. #define aflag 9 /* assert failed */
  319. #define jflag 10 /* JP could be JR */
  320. #define rflag 11 /* expression not relocatable */
  321. #define gflag 12 /* incorrect register */
  322. #define zflag 13 /* Z-80 instruction */
  323. #define FIRSTWARN warn_hex
  324. #define warn_hex 14
  325. #define warn_notimpl 15
  326. #define warn_general 16
  327. #define FLAGS 17 /* number of errors and warnings */
  328. char err[FLAGS];
  329. int keeperr[FLAGS];
  330. char errlet[FLAGS]="BEFIMPUVOAJRGZHNW";
  331. char *errname[FLAGS]={
  332. "Balance",
  333. "Expression",
  334. "Syntax",
  335. "Digit",
  336. "Mult. def.",
  337. "Phase",
  338. "Undeclared",
  339. "Value",
  340. "Phase/Dephase",
  341. "Assertion failure",
  342. "Use JR",
  343. "Not relocatable",
  344. "Register usage",
  345. "Z-80 instruction in 8080 mode",
  346. "$hex constant interpreted as symbol",
  347. "Not implemented",
  348. "General"
  349. };
  350. char errdetail[FLAGS][1024];
  351. char detail[1024];
  352. unsigned char inpbuf[LINEBUFFERSIZE];
  353. unsigned char *inpptr;
  354. char linebuf[LINEBUFFERSIZE];
  355. char *lineptr;
  356. char *linemax = linebuf+LINEBUFFERSIZE;
  357. char outbin[BINPERLINE];
  358. char *outbinp = outbin;
  359. char *outbinm = outbin+BINPERLINE;
  360. char outoth[256];
  361. int outoth_cnt = 0;
  362. unsigned char emitbuf[EMITBUFFERSIZE];
  363. unsigned char *emitptr;
  364. char ifstack[IFSTACKSIZE];
  365. char *ifptr;
  366. char *ifstmax = ifstack+IFSTACKSIZE-1;
  367. char hexadec[] = "0123456789ABCDEF" ;
  368. int nitems;
  369. int linecnt;
  370. int nbytes;
  371. int invented;
  372. int npass;
  373. int njrpromo;
  374. char tempbuf[TEMPBUFSIZE];
  375. char *tempmax = tempbuf+TEMPBUFSIZE-1;
  376. char arg_flag;
  377. struct argparse arg_state;
  378. void arg_start();
  379. void arg_reset();
  380. int str_getch(struct argparse *ap);
  381. char inmlex;
  382. char mlex_list_on;
  383. int parm_number;
  384. int exp_number;
  385. char symlong[] = "Symbol/number too long";
  386. int raw;
  387. int disp;
  388. int param_parse;
  389. #define PARAMTABSIZE (PARMMAX * 2)
  390. struct item paramtab[PARAMTABSIZE];
  391. #define FLOC PARMMAX
  392. #define TEMPNUM PARMMAX+1
  393. #define REPNUM PARMMAX+2
  394. #define MSTART PARMMAX+3
  395. #define MSTR PARMMAX+4
  396. #define MARGP PARMMAX+5
  397. #define MIF PARMMAX+6
  398. #define PAREXT 7
  399. union exprec {
  400. char *param;
  401. int value;
  402. struct argparse *ap;
  403. };
  404. union exprec *est;
  405. union exprec *est2;
  406. union exprec *expstack[MAXEXP];
  407. int expptr;
  408. int floc;
  409. int mfptr;
  410. FILE *mfile;
  411. char *writesyms;
  412. char *title;
  413. char titlespace[TITLELEN];
  414. char *timp;
  415. char *sourcef;
  416. /* changed to cope with filenames longer than 14 chars -rjm 1998-12-15 */
  417. char src[1024];
  418. char bin[1024];
  419. char mtmp[1024];
  420. char listf[1024];
  421. char bds[1024];
  422. char oth[1024];
  423. char bopt = 1,
  424. copt = 1, /* cycle counts in listings by default */
  425. edef = 1,
  426. eopt = 1,
  427. fdef = 0,
  428. fopt = 0,
  429. gdef = 1,
  430. gopt = 1,
  431. iopt = 0 , /* list include files */
  432. jopt = 0,
  433. JPopt = 0,
  434. lstoff = 0,
  435. lston = 0, /* flag to force listing on */
  436. lopt = 0,
  437. mdef = 0,
  438. mopt = 0,
  439. nopt = 1 , /* line numbers on as default */
  440. oopt = 0,
  441. popt = 1, /* form feed as default page eject */
  442. sopt = 0, /* turn on symbol table listing */
  443. topt = 1, /* terse, only error count to terminal */
  444. printer_output = 0, // GWP - printer style output
  445. z80,
  446. saveopt;
  447. char default_jopt, default_JPopt, default_z80 = 1;
  448. char xeq_flag = 0;
  449. int xeq;
  450. time_t now;
  451. int line;
  452. int page = 1;
  453. struct stab {
  454. char t_name[MAXSYMBOLSIZE+1];
  455. int t_value;
  456. int t_token;
  457. };
  458. // GWP - support for cycle count tracking (and opens door for efficient .cmd, etc. output)
  459. unsigned char memory[1 << 16];
  460. char memflag[1 << 16];
  461. enum {
  462. MEM_DATA = 1,
  463. MEM_INST = 2,
  464. MEM_T_SET = 4
  465. };
  466. int tstatesum[1 << 16];
  467. int ocfsum[1 << 16];
  468. // GWP - expression handling extensions for .rel output.
  469. void advance_segment(int step);
  470. void expr_reloc_check(struct expr *ex);
  471. void expr_number_check(struct expr *ex);
  472. void expr_scope_same(struct expr *ex1, struct expr *ex2);
  473. void expr_word_check(struct expr *ex);
  474. int is_number(struct expr *ex);
  475. int is_external(struct expr *ex);
  476. struct expr *expr_num(int value);
  477. struct expr *expr_alloc(void);
  478. struct expr *expr_op(struct expr *left, int token, struct expr *right, int value);
  479. struct expr *expr_op_sc(struct expr *left, int token, struct expr *right, int value);
  480. void expr_free(struct expr *ex);
  481. int can_extend_link(struct expr *ex);
  482. void extend_link(struct expr *ex);
  483. void putrelop(int op);
  484. #define RELOP_BYTE (1)
  485. #define RELOP_WORD (2)
  486. #define RELOP_HIGH (3)
  487. #define RELOP_LOW (4)
  488. #define RELOP_NOT (5)
  489. #define RELOP_NEG (6)
  490. #define RELOP_SUB (7)
  491. #define RELOP_ADD (8)
  492. #define RELOP_MUL (9)
  493. #define RELOP_DIV (10)
  494. #define RELOP_MOD (11)
  495. struct item *item_lookup(char *name, struct item *table, int table_size);
  496. struct item *locate(char *name);
  497. // Data descriptions for emit()
  498. #define E_CODE (0)
  499. #define E_DATA (1)
  500. #define E_CODE8 (2)
  501. #define E_CODE16 (3)
  502. int segment;
  503. #define SEGCHAR(s) " '\"!"[s]
  504. #define SEG_ABS (0)
  505. #define SEG_CODE (1)
  506. #define SEG_DATA (2)
  507. int seg_pos[4]; // may eventually support SEG_COMMON
  508. int seg_size[4];
  509. int rel_main;
  510. int segchange;
  511. void putout(int value);
  512. int outrec;
  513. int outlen;
  514. unsigned char outbuf[1024 * 1024];
  515. /*
  516. * push back character
  517. */
  518. int peekc;
  519. int nextline_peek;
  520. /* function prototypes */
  521. void error(char *as);
  522. void usage(char *msg, char *param);
  523. void help();
  524. void erreport();
  525. void errorprt(int errnum);
  526. void errwarn(int errnum, char *message);
  527. void mlex(char *look);
  528. void popsi();
  529. void suffix(char *str, char *suff);
  530. char *basename(char *filename);
  531. char *getsuffix(char *str);
  532. void outpath(char *out, char *src, char *suff);
  533. void casname(char *out, char *src);
  534. void putm(int c);
  535. void insymtab(char *name);
  536. void outsymtab(char *name);
  537. void compactsymtab();
  538. void putsymtab();
  539. void clear();
  540. void setmem(int addr, int value, int type);
  541. void setvars();
  542. void flushbin();
  543. void flushoth();
  544. void lineout();
  545. void puthex(int byte, FILE *buf);
  546. void putcas(int byte);
  547. void putrelbits(int count, int bits);
  548. void putrel(int byte);
  549. void putrelname(char *str);
  550. void putrelextaddr(int extaddr);
  551. void putrelcmd(int cmd);
  552. void putrelsegref(int scope, int addr);
  553. void flushrel(void);
  554. void lsterr1();
  555. void lsterr2(int lst);
  556. void copyname(char *st1, char *st2);
  557. void next_source(char *sp);
  558. void incbin(char *filename);
  559. void dc(int count, int value);
  560. char *getmraslocal();
  561. #define RELCMD_PUBLIC (0)
  562. #define RELCMD_COMMON (1)
  563. #define RELCMD_PROGNAME (2)
  564. #define RELCMD_LIBLOOK (3)
  565. #define RELCMD_EXTLINK (4)
  566. #define RELCMD_COMSIZE (5)
  567. #define RELCMD_EXTCHAIN (6)
  568. #define RELCMD_PUBVALUE (7)
  569. #define RELCMD_EXTMINUS (8)
  570. #define RELCMD_EXTPLUS (9)
  571. #define RELCMD_DATASIZE (10)
  572. #define RELCMD_SETLOC (11)
  573. #define RELCMD_CODESIZE (13)
  574. #define RELCMD_ENDMOD (14)
  575. #define RELCMD_ENDPROG (15)
  576. /*
  577. * add a character to the output line buffer
  578. */
  579. void addtoline(int ac)
  580. {
  581. /* check for EOF from stdio */
  582. if (ac == -1)
  583. ac = 0 ;
  584. if (lineptr >= linemax)
  585. error("line buffer overflow");
  586. *lineptr++ = ac;
  587. }
  588. /*
  589. * put values in buffer for outputing
  590. */
  591. void emit(int bytes, int desc, struct expr *data, ...)
  592. {
  593. int type, i, args, dsize;
  594. va_list ap;
  595. if (relopt && segchange) {
  596. segchange = 0;
  597. putrelcmd(RELCMD_SETLOC);
  598. putrelsegref(segment, seg_pos[segment]);
  599. }
  600. // External references only supported in .rel output.
  601. if (!relopt && data && (data->e_scope & SCOPE_EXTERNAL)) {
  602. sprintf(detail, "External references only allowed in .rel output\n");
  603. errwarn(uflag, detail);
  604. }
  605. va_start(ap, data);
  606. type = desc == E_DATA ? MEM_DATA : MEM_INST;
  607. // Check emit is not adding instructions to the buffer.
  608. if (desc != E_DATA && emitptr != emitbuf)
  609. fprintf(stderr, "internal inconsistency in t-state counting\n");
  610. dsize = 0;
  611. args = bytes;
  612. if (desc == E_DATA) {
  613. args = 0;
  614. dsize = bytes;
  615. }
  616. else if (desc == E_CODE16)
  617. dsize = 2;
  618. else if (desc == E_CODE8)
  619. dsize = 1;
  620. for (i = 0; i < args; i++)
  621. {
  622. if (emitptr >= &emitbuf[EMITBUFFERSIZE])
  623. error("emit buffer overflow");
  624. else {
  625. int addr = (emit_addr + (emitptr - emitbuf)) & 0xffff;
  626. *emitptr = va_arg(ap, int);
  627. if (segment == SEG_CODE)
  628. setmem(addr, *emitptr, type);
  629. putrel(*emitptr);
  630. putout(*emitptr);
  631. emitptr++;
  632. }
  633. }
  634. va_end(ap);
  635. for (i = 0; i < dsize; i++) {
  636. int addr = (emit_addr + (emitptr - emitbuf)) & 0xffff;
  637. *emitptr = data->e_value >> (i * 8);
  638. if (segment == SEG_CODE)
  639. setmem(addr, *emitptr, type);
  640. putout(*emitptr);
  641. emitptr++;
  642. }
  643. if (desc != E_DATA)
  644. {
  645. int eaddr = emit_addr, low, fetch, low8080, addr_after;
  646. // emitbuf is OK since this only happens with single emits
  647. if (!z80) {
  648. // Check for invalid 8080 instructions.
  649. int op = emitbuf[0] & 0xff;
  650. if (op == 0x08 || op == 0x10 || op == 0x18 ||
  651. op == 0x20 || op == 0x28 || op == 0x30 ||
  652. op == 0x38 || op == 0xCB || op == 0xD9 ||
  653. op == 0xDD || op == 0xED || op == 0xFD)
  654. {
  655. err[zflag]++;
  656. }
  657. }
  658. zi_tstates(emitbuf, &low, 0, &fetch, &low8080, 0);
  659. if (!z80)
  660. low = low8080;
  661. // Sanity check
  662. if (low <= 0)
  663. {
  664. fprintf(stderr, "undefined instruction on %02x %02x (assembler or diassembler broken)\n",
  665. emitbuf[0], emitbuf[1]);
  666. }
  667. // Special case to catch promotion of djnz to DEC B JP NZ
  668. // Even update the tstatesum[] counter though that seems to
  669. // me to be above and beyond.
  670. if (emitbuf[0] == 5 && args == 2) {
  671. tstatesum[eaddr] = tstates;
  672. ocfsum[eaddr] = ocf;
  673. memflag[eaddr] |= MEM_T_SET;
  674. eaddr++;
  675. tstates += low;
  676. ocf += fetch;
  677. low = 10;
  678. // still 1 fetch
  679. }
  680. // Double setting of both sides of tstatesum[] seems like too
  681. // much, but must be done in the isolated instruction case:
  682. // org x ; inc a ; org y
  683. tstatesum[eaddr] = tstates;
  684. ocfsum[eaddr] = ocf;
  685. memflag[eaddr] |= MEM_T_SET;
  686. // Well, OK, should we default to high or low???
  687. // Guess it should be whatever makes sense for you
  688. // to get here which, generally, is the low.
  689. // low it is.
  690. tstates += low;
  691. ocf += fetch;
  692. addr_after = (emit_addr + (emitptr - emitbuf)) & 0xffff;
  693. tstatesum[addr_after] = tstates;
  694. ocfsum[addr_after] = ocf;
  695. memflag[addr_after] |= MEM_T_SET;
  696. }
  697. if (relopt && outpass && dsize > 0) {
  698. if (dsize == 1) {
  699. if (is_number(data))
  700. putrel(data->e_value);
  701. else if (can_extend_link(data)) {
  702. extend_link(data);
  703. putrelop(RELOP_BYTE);
  704. putrel(0);
  705. }
  706. else {
  707. err[rflag]++;
  708. putrel(0);
  709. }
  710. }
  711. else if (dsize == 2) {
  712. int handled = 0;
  713. if (data->e_scope & SCOPE_EXTERNAL) {
  714. struct item *var = 0;
  715. int offset = 0;
  716. // Simple external reference.
  717. if (is_external(data))
  718. var = data->e_item;
  719. else if (is_external(data->e_left) &&
  720. data->e_token == '+' &&
  721. is_number(data->e_right))
  722. {
  723. var = data->e_left->e_item;
  724. offset = data->e_right->e_value;
  725. }
  726. else if (is_number(data->e_left) &&
  727. data->e_token == '+' &&
  728. is_external(data->e_right))
  729. {
  730. offset = data->e_left->e_value;
  731. var = data->e_right->e_item;
  732. }
  733. else if (is_external(data->e_left) &&
  734. data->e_token == '-' &&
  735. is_number(data->e_right))
  736. {
  737. var = data->e_left->e_item;
  738. offset = data->e_right->e_value;
  739. }
  740. if (var && offset) {
  741. putrelcmd(data->e_token == '-' ?
  742. RELCMD_EXTMINUS : RELCMD_EXTPLUS);
  743. // Theoretically we could put a
  744. // program or data relative value here...
  745. putrelsegref(SEG_ABS, offset);
  746. }
  747. if (var) {
  748. if (var->i_chain == 0) {
  749. putrel(0);
  750. putrel(0);
  751. }
  752. else {
  753. putrelbits(1, 1);
  754. putrelextaddr(var->i_chain);
  755. }
  756. var->i_chain = (segment << 16) |
  757. ((dollarsign + args) & 0xffff);
  758. handled = 1;
  759. }
  760. }
  761. else if ((data->e_scope & ~SCOPE_PUBLIC) == 0) {
  762. // nice constant value
  763. putrel(data->e_value);
  764. putrel(data->e_value >> 8);
  765. handled = 1;
  766. }
  767. else if (!(data->e_scope & SCOPE_NORELOC)) {
  768. // relocatable value
  769. putrelbits(1, 1);
  770. putrelbits(2, data->e_scope);
  771. putrelbits(8, data->e_value);
  772. putrelbits(8, data->e_value >> 8);
  773. handled = 1;
  774. }
  775. if (!handled) {
  776. if (can_extend_link(data)) {
  777. extend_link(data);
  778. putrelop(RELOP_WORD);
  779. putrel(0);
  780. putrel(0);
  781. }
  782. else {
  783. err[rflag]++;
  784. putrel(data->e_value);
  785. putrel(data->e_value >> 8);
  786. }
  787. }
  788. }
  789. else if (dsize == 4) {
  790. // Only numbers are allowed.
  791. if (data->e_scope != 0) {
  792. err[vflag]++;
  793. if (data->e_scope & SCOPE_NORELOC)
  794. err[rflag]++;
  795. }
  796. for (i = 0; i < dsize; i++)
  797. putrel(data->e_value >> (i * 8));
  798. }
  799. else
  800. error("internal dsize error");
  801. }
  802. }
  803. #define ET_NOARG_DISP (0)
  804. #define ET_NOARG (1)
  805. #define ET_BYTE (2)
  806. #define ET_WORD (5)
  807. void emit1(int opcode, int regvalh, struct expr *data, int type)
  808. {
  809. if (type == ET_BYTE && (data->e_value < -128 || data->e_value > 255))
  810. err[vflag]++;
  811. if (regvalh & 0x10000) {
  812. switch (type) {
  813. case ET_NOARG_DISP:
  814. emit(2, E_CODE, 0, regvalh >> 8, opcode);
  815. break;
  816. case ET_BYTE:
  817. emit(2, E_CODE8, data, regvalh >> 8, opcode);
  818. break;
  819. }
  820. }
  821. else if (regvalh & 0x8000) {
  822. switch (type) {
  823. case ET_NOARG_DISP:
  824. if (opcode & 0x8000)
  825. emit(4, E_CODE, 0, regvalh >> 8, opcode >> 8, disp, opcode);
  826. else
  827. emit(3, E_CODE, 0, regvalh >> 8, opcode, disp);
  828. break;
  829. case ET_NOARG:
  830. emit(2, E_CODE, 0, regvalh >> 8, opcode);
  831. break;
  832. case ET_BYTE:
  833. emit(3, E_CODE8, data, regvalh >> 8, opcode, disp);
  834. break;
  835. case ET_WORD:
  836. emit(2, E_CODE16, data, regvalh >> 8, opcode);
  837. }
  838. } else
  839. switch(type) {
  840. case ET_NOARG_DISP:
  841. case ET_NOARG:
  842. if (opcode & 0100000)
  843. emit(2, E_CODE, 0, opcode >> 8, opcode);
  844. else
  845. emit(1, E_CODE, 0, opcode);
  846. break;
  847. case ET_BYTE:
  848. emit(1, E_CODE8, data, opcode);
  849. break;
  850. case ET_WORD:
  851. if (opcode & 0100000)
  852. emit(2, E_CODE16, data, opcode >> 8, opcode);
  853. else
  854. emit(1, E_CODE16, data, opcode);
  855. }
  856. }
  857. void emitdad(int rp1,int rp2)
  858. {
  859. if (rp1 & 0x8000)
  860. emit(2, E_CODE, 0, rp1 >> 8, rp2 + 9);
  861. else
  862. emit(1, E_CODE, 0, rp2 + 9);
  863. }
  864. void emitjr(int opcode, struct expr *dest)
  865. {
  866. int disp = dest->e_value - dollarsign - 2;
  867. if (dest->e_scope & SCOPE_NORELOC)
  868. err[rflag]++;
  869. // Can't relative jump to other segments or an external
  870. // However, without .rel output we default to the code segment
  871. // for various reasons thus we let "jr 0" (and such) be acceptable
  872. // in those cases.
  873. if (((relopt && (dest->e_scope & SCOPE_SEGMASK) != segment) ||
  874. (dest->e_scope & SCOPE_EXTERNAL) ||
  875. disp > 127 || disp < -128) && z80)
  876. {
  877. if (jopt) {
  878. njrpromo++;
  879. switch (opcode) {
  880. case 0x10: // DJNZ
  881. emit(2, E_CODE16, dest, 0x05, 0xC2); // DEC B, JP NZ
  882. break;
  883. case 0x18: // JR
  884. emit(1, E_CODE16, dest, 0xC3); // JP
  885. break;
  886. case 0x20: // JR NZ
  887. emit(1, E_CODE16, dest, 0xC2); // JP NZ
  888. break;
  889. case 0x28: // JR Z
  890. emit(1, E_CODE16, dest, 0xCA); // JP Z
  891. break;
  892. case 0x30: // JR NC
  893. emit(1, E_CODE16, dest, 0xD2); // JP NC
  894. break;
  895. case 0x38: // JR C
  896. emit(1, E_CODE16, dest, 0xDA); // JP C
  897. break;
  898. default:
  899. err[vflag]++; // shouldn't happen!
  900. expr_free(dest);
  901. break;
  902. }
  903. }
  904. else {
  905. emit(2, E_CODE, 0, opcode, -2); // branch to itself
  906. err[vflag]++;
  907. expr_free(dest);
  908. }
  909. }
  910. else {
  911. emit(2, E_CODE, 0, opcode, disp);
  912. expr_free(dest);
  913. }
  914. }
  915. void checkjp(int op, struct expr *dest)
  916. {
  917. op &= 0x030;
  918. // Only applies to Z-80 output and if JP optimization checking is on.
  919. // JR only has z, nz, nc, c
  920. // A jump to the current segment might have been optimizable
  921. if (z80 && JPopt && (op == 0 || op == 010 || op == 020 || op == 030) &&
  922. (dest->e_scope & (SCOPE_SEGMASK | SCOPE_EXTERNAL)) == segment)
  923. {
  924. int disp = dest->e_value - dollarsign - 2;
  925. if (disp >= -128 && disp <= 127)
  926. err[jflag]++;
  927. }
  928. }
  929. /*
  930. * put out a byte of binary
  931. */
  932. void putbin(int v)
  933. {
  934. if(!outpass || !bopt) return;
  935. *outbinp++ = v;
  936. if (outbinp >= outbinm) flushbin();
  937. outoth[outoth_cnt++] = v;
  938. if (outoth_cnt == 256) flushoth();
  939. }
  940. /*
  941. * output one line of binary in INTEL standard form
  942. */
  943. void flushbin()
  944. {
  945. char *p;
  946. int check=outbinp-outbin;
  947. if (!outpass || !bopt)
  948. return;
  949. nbytes += check;
  950. if (check) {
  951. putc(':', fbuf);
  952. puthex(check, fbuf);
  953. puthex(olddollar>>8, fbuf);
  954. puthex(olddollar, fbuf);
  955. puthex(0, fbuf);
  956. check += (olddollar >> 8) + olddollar;
  957. olddollar += (outbinp-outbin);
  958. for (p=outbin; p<outbinp; p++) {
  959. puthex(*p, fbuf);
  960. check += *p;
  961. }
  962. puthex(256-check, fbuf);
  963. putc('\n', fbuf);
  964. outbinp = outbin;
  965. }
  966. }
  967. /*
  968. * put out one byte of hex
  969. */
  970. void puthex(int byte, FILE *buf)
  971. {
  972. putc(hexadec[(byte >> 4) & 017], buf);
  973. putc(hexadec[byte & 017], buf);
  974. }
  975. // Case-independent strcmp()
  976. int ci_strcmp(char *s1, char *s2)
  977. {
  978. int c1, c2;
  979. do {
  980. c1 = *s1++;
  981. if (c1 >= 'A' && c1 <= 'Z') c1 += 'a' - 'A';
  982. c2 = *s2++;
  983. if (c2 >= 'A' && c2 <= 'Z') c2 += 'a' - 'A';
  984. if (c1 != c2)
  985. return c1 - c2;
  986. } while (c1 && c2);
  987. return 0;
  988. }
  989. void flushoth()
  990. {
  991. int i, checksum;
  992. if (!outpass || !bopt || outoth_cnt == 0)
  993. return;
  994. fprintf(fcmd, "%c%c%c%c", 1, outoth_cnt + 2, oldothdollar, oldothdollar >> 8);
  995. fwrite(outoth, outoth_cnt, 1, fcmd);
  996. putcas(0x3c);
  997. putcas(outoth_cnt);
  998. putcas(oldothdollar);
  999. putcas(oldothdollar >> 8);
  1000. checksum = oldothdollar + (oldothdollar >> 8);
  1001. for (i = 0; i < outoth_cnt; i++) {
  1002. putcas(outoth[i]);
  1003. checksum += outoth[i];
  1004. }
  1005. putcas(checksum);
  1006. oldothdollar += outoth_cnt;
  1007. outoth_cnt = 0;
  1008. }
  1009. int casbit, casbitcnt = 0;
  1010. void putcas(int byte)
  1011. {
  1012. fputc(byte, flcas);
  1013. // Buffer 0 stop bit and the 8 data bits.
  1014. casbit = (casbit << 9) | (byte & 0xff);
  1015. casbitcnt += 9;
  1016. while (casbitcnt >= 8) {
  1017. casbitcnt -= 8;
  1018. fputc(casbit >> casbitcnt, fcas);
  1019. }
  1020. }
  1021. void casname(char *out, char *src)
  1022. {
  1023. char *base = basename(src);
  1024. int i;
  1025. out[0] = 'N';
  1026. for (i = 1; i < 6; i++)
  1027. out[i] = ' ';
  1028. for (i = 0; *base && i < 6; base++) {
  1029. if (ci_strcmp(base, ".z") == 0)
  1030. break;
  1031. if (*base >= 'a' && *base <= 'z') {
  1032. *out++ = *base - ('a' - 'A');
  1033. i++;
  1034. }
  1035. else if (*base >= 'A' && *base <= 'Z') {
  1036. *out++ = *base;
  1037. i++;
  1038. }
  1039. }
  1040. }
  1041. int relbit, relbitcnt = 0;
  1042. void putrelbits(int count, int bits)
  1043. {
  1044. if (!outpass || !relopt)
  1045. return;
  1046. relbit <<= count;
  1047. relbit |= bits & ((1 << count) - 1);
  1048. relbitcnt += count;
  1049. while (relbitcnt >= 8) {
  1050. relbitcnt -= 8;
  1051. fputc(relbit >> relbitcnt, frel);
  1052. }
  1053. }
  1054. void putrel(int byte)
  1055. {
  1056. // Add 0 bit indicating byte to load at next counter
  1057. putrelbits(1, 0);
  1058. // Add byte to load
  1059. putrelbits(8, byte);
  1060. }
  1061. void putrelname(char *str)
  1062. {
  1063. int len = strlen(str);
  1064. // .rel file format can do strings 7 long but for compatibility
  1065. // we restrict them to 6. I believe this is important because
  1066. // extended link functions require a character when they wish to
  1067. // operate on an external symbol.
  1068. if (len > 6)
  1069. len = 6;
  1070. putrelbits(3, len);
  1071. while (len-- > 0) {
  1072. int ch = *str++;
  1073. if (ch >= 'a' && ch <= 'z')
  1074. ch -= 'a' - 'A';
  1075. putrelbits(8, ch);
  1076. }
  1077. }
  1078. void putrelsegref(int scope, int addr)
  1079. {
  1080. putrelbits(2, scope);
  1081. putrelbits(8, addr);
  1082. putrelbits(8, addr >> 8);
  1083. }
  1084. void putrelextaddr(int extaddr)
  1085. {
  1086. putrelsegref(extaddr >> 16, extaddr);
  1087. }
  1088. void putrelcmd(int relcmd)
  1089. {
  1090. putrelbits(1, 1);
  1091. putrelbits(2, 0);
  1092. putrelbits(4, relcmd);
  1093. }
  1094. void flushrel(void)
  1095. {
  1096. if (relbitcnt > 0)
  1097. putrelbits(8 - relbitcnt, 0);
  1098. if (relopt)
  1099. fflush(frel);
  1100. }
  1101. /*
  1102. * put out a line of output -- also put out binary
  1103. */
  1104. void list(int optarg)
  1105. {
  1106. unsigned char * p;
  1107. int i;
  1108. int lst;
  1109. char seg = ' ';
  1110. if (!expptr)
  1111. linecnt++;
  1112. addtoline('\0');
  1113. if (outpass) {
  1114. lst = iflist();
  1115. if (lst) {
  1116. lineout();
  1117. if (nopt)
  1118. fprintf(fout, "%4d:", linein[now_in]);
  1119. if (copt)
  1120. {
  1121. if (emitptr > emitbuf && (memflag[emit_addr] & MEM_INST))
  1122. {
  1123. int low, high, fetch, low8080, high8080;
  1124. zi_tstates(memory + emit_addr, &low, &high, &fetch, &low8080, &high8080);
  1125. if (!z80) {
  1126. low = low8080;
  1127. high = high8080;
  1128. }
  1129. // Special case to catch promotion of djnz to DEC B JP NZ
  1130. if (memory[emit_addr] == 5 && emitptr - emitbuf == 4) {
  1131. low += 10;
  1132. high += 10;
  1133. }
  1134. fprintf(fout, nopt ? "%5d" : "%4d", tstatesum[emit_addr]);
  1135. fprintf(fout, "+%d", low);
  1136. if (low != high)
  1137. fprintf(fout, "+%d", high - low);
  1138. }
  1139. else
  1140. {
  1141. fprintf(fout, nopt ? "%5s-" : "%4s-", "");
  1142. }
  1143. }
  1144. if (nopt || copt)
  1145. fprintf(fout, "\t");
  1146. puthex(optarg >> 8, fout);
  1147. puthex(optarg, fout);
  1148. if (relopt)
  1149. seg = SEGCHAR(segment);
  1150. fputc(seg, fout);
  1151. fputc(' ', fout);
  1152. for (p = emitbuf; (p < emitptr) && (p - emitbuf < 4); p++) {
  1153. puthex(*p, fout);
  1154. }
  1155. for (i = 4 - (p-emitbuf); i > 0; i--)
  1156. fputs(" ", fout);
  1157. putc('\t', fout);
  1158. fputs(linebuf, fout);
  1159. }
  1160. if (bopt) {
  1161. if (emitptr > emitbuf) {
  1162. fprintf(fbds, "%04x %04x d ", dollarsign, emit_addr);
  1163. for (p = emitbuf; p < emitptr; p++)
  1164. fprintf(fbds, "%02x", *p & 0xff);
  1165. fprintf(fbds, "\n");
  1166. }
  1167. fprintf(fbds, "%04x %04x s %s", dollarsign, emit_addr, linebuf);
  1168. for (p = emitbuf; p < emitptr; p++)
  1169. putbin(*p);
  1170. }
  1171. p = emitbuf+4;
  1172. while (lst && gopt && p < emitptr) {
  1173. lineout();
  1174. if (nopt) putc('\t', fout);
  1175. fputs(" ", fout);
  1176. for (i = 0; (i < 4) && (p < emitptr);i++) {
  1177. puthex(*p, fout);
  1178. p++;
  1179. }
  1180. putc('\n', fout);
  1181. }
  1182. lsterr2(lst);
  1183. } else
  1184. lsterr1();
  1185. dollarsign += emitptr - emitbuf;
  1186. emit_addr += emitptr - emitbuf;
  1187. dollarsign &= 0xffff;
  1188. emit_addr &= 0xffff;
  1189. emitptr = emitbuf;
  1190. lineptr = linebuf;
  1191. }
  1192. /*
  1193. * keep track of line numbers and put out headers as necessary
  1194. */
  1195. void lineout()
  1196. {
  1197. if (!printer_output)
  1198. return;
  1199. if (line == 60) {
  1200. if (popt)
  1201. putc('\014', fout); /* send the form feed */
  1202. else
  1203. fputs("\n\n\n\n\n", fout);
  1204. line = 0;
  1205. }
  1206. if (line == 0) {
  1207. fprintf(fout, "\n\n%s %s\t%s\t Page %d\n\n\n",
  1208. &timp[4], &timp[20], title, page++);
  1209. line = 4;
  1210. }
  1211. line++;
  1212. }
  1213. /*
  1214. * cause a page eject
  1215. */
  1216. void eject()
  1217. {
  1218. if (printer_output)
  1219. return;
  1220. if (outpass && iflist()) {
  1221. if (popt) {
  1222. putc('\014', fout); /* send the form feed */
  1223. } else {
  1224. while (line < 65) {
  1225. line++;
  1226. putc('\n', fout);
  1227. }
  1228. }
  1229. }
  1230. line = 0;
  1231. }
  1232. /*
  1233. * space n lines on the list file
  1234. */
  1235. void space(int n)
  1236. {
  1237. int i ;
  1238. if (outpass && iflist())
  1239. for (i = 0; i<n; i++) {
  1240. lineout();
  1241. putc('\n', fout);
  1242. }
  1243. }
  1244. /*
  1245. * Error handling - pass 1
  1246. */
  1247. void lsterr1()
  1248. {
  1249. int i;
  1250. for (i = 0; i <= mflag; i++)
  1251. if (err[i]) {
  1252. if (topt)
  1253. errorprt(i);
  1254. passfail = 1;
  1255. err[i] = 0;
  1256. }
  1257. }
  1258. /*
  1259. * Error handling - pass 2.
  1260. */
  1261. void lsterr2(int lst)
  1262. {
  1263. int i;
  1264. for (i=0; i<FLAGS; i++)
  1265. if (err[i]) {
  1266. if (i < FIRSTWARN)
  1267. passfail = 1;
  1268. if (lst) {
  1269. char *desc = errname[i];
  1270. char *type = i < FIRSTWARN ? " error" : " warning";
  1271. if (errdetail[i][0]) {
  1272. desc = errdetail[i];
  1273. type = "";
  1274. }
  1275. lineout();
  1276. fprintf(fout, "%c %s%s\n",
  1277. errlet[i], desc, type);
  1278. }
  1279. err[i] = 0;
  1280. keeperr[i]++;
  1281. if (i > mflag && topt)
  1282. errorprt(i);
  1283. }
  1284. fflush(fout); /*to avoid putc(har) mix bug*/
  1285. }
  1286. /*
  1287. * print diagnostic to error terminal
  1288. */
  1289. void errorprt(int errnum)
  1290. {
  1291. char *desc = errname[errnum];
  1292. char *type = errnum < FIRSTWARN ? " error" : " warning";
  1293. if (errdetail[errnum][0]) {
  1294. desc = errdetail[errnum];
  1295. type = "";
  1296. }
  1297. fprintf(stderr, "%s(%d) : %s%s",
  1298. src_name[now_in], linein[now_in], desc, type);
  1299. errdetail[errnum][0] = '\0';
  1300. fprintf(stderr, "\n");
  1301. fprintf(stderr, "%s\n", linebuf);
  1302. fflush(stderr) ;
  1303. }
  1304. void errwarn(int errnum, char *message)
  1305. {
  1306. err[errnum]++;
  1307. strcpy(errdetail[errnum], message);
  1308. }
  1309. /*
  1310. * list without address -- for comments and if skipped lines
  1311. */
  1312. void list1()
  1313. {
  1314. int lst;
  1315. addtoline('\0');
  1316. lineptr = linebuf;
  1317. if (!expptr) linecnt++;
  1318. if (outpass) {
  1319. if ((lst = iflist())) {
  1320. lineout();
  1321. if (nopt)
  1322. fprintf(fout, "%4d:\t", linein[now_in]);
  1323. if (copt)
  1324. fprintf(fout, "\t");
  1325. fprintf(fout, "\t\t%s", linebuf);
  1326. lsterr2(lst);
  1327. }
  1328. if (bopt)
  1329. fprintf(fbds, "%04x %04x s %s", dollarsign, emit_addr, linebuf);
  1330. }
  1331. else
  1332. lsterr1();
  1333. }
  1334. /*
  1335. * see if listing is desired
  1336. */
  1337. int iflist()
  1338. {
  1339. int i, j;
  1340. if (inmlex)
  1341. return mlex_list_on;
  1342. if (lston)
  1343. return(1) ;
  1344. if (lopt)
  1345. return(0);
  1346. if (*ifptr && !fopt)
  1347. return(0);
  1348. if (!lstoff && !expptr)
  1349. return(1);
  1350. j = 0;
  1351. for (i=0; i<FLAGS; i++)
  1352. if (err[i])
  1353. j++;
  1354. if (expptr)
  1355. return(mopt || j);
  1356. if (eopt && j)
  1357. return(1);
  1358. return(0);
  1359. }
  1360. void do_equ(struct item *sym, struct expr *val, int call_list);
  1361. void do_defl(struct item *sym, struct expr *val, int call_list);
  1362. // GWP - This avoids an apparent bug in bison as it tries to start out the
  1363. // Not needed under gcc which defines __STDC__ so I guard it to prevent
  1364. // warnings.
  1365. // yyparse() function with yyparse() ; { }.
  1366. #ifndef __STDC__
  1367. #define __STDC__
  1368. #endif
  1369. #define PSTITL (0) /* title */
  1370. #define PSRSYM (1) /* rsym */
  1371. #define PSWSYM (2) /* wsym */
  1372. #define PSINC (3) /* include file */
  1373. #define PSMACLIB (4) /* maclib (similar to include) */
  1374. #define SPTITL (0) /* title */
  1375. #define SPSBTL (1) /* sub title */
  1376. #define SPNAME (2) /* name */
  1377. #define SPCOM (3) /* comment */
  1378. #define SPPRAGMA (4) /* pragma */
  1379. %}
  1380. %union {
  1381. struct expr *exprptr;
  1382. struct item *itemptr;
  1383. int ival;
  1384. char *cval;
  1385. }
  1386. %token <cval> STRING
  1387. %token <itemptr> NOOPERAND
  1388. %token <itemptr> ARITHC
  1389. %token ADD
  1390. %token <itemptr> LOGICAL
  1391. %token <itemptr> AND
  1392. %token <itemptr> OR
  1393. %token <itemptr> XOR
  1394. %token <ival> ANDAND
  1395. %token <ival> OROR
  1396. %token <itemptr> BIT
  1397. %token CALL
  1398. %token <itemptr> INCDEC
  1399. %token <itemptr> DJNZ
  1400. %token EX
  1401. %token <itemptr> IM
  1402. %token PHASE
  1403. %token DEPHASE
  1404. %token <itemptr> TK_IN
  1405. %token <itemptr> JR
  1406. %token LD
  1407. %token <itemptr> TK_OUT
  1408. %token <itemptr> PUSHPOP
  1409. %token <itemptr> RET
  1410. %token <itemptr> SHIFT
  1411. %token <itemptr> RST
  1412. %token <itemptr> REGNAME
  1413. %token <itemptr> IXYLH
  1414. %token <itemptr> ACC
  1415. %token <itemptr> C
  1416. %token <itemptr> RP
  1417. %token <itemptr> HL
  1418. %token <itemptr> INDEX
  1419. %token <itemptr> AF
  1420. %token AFp
  1421. %token <itemptr> SP
  1422. %token <itemptr> MISCREG
  1423. %token <itemptr> COND
  1424. %token <itemptr> SPCOND
  1425. %token <ival> NUMBER
  1426. %token <itemptr> UNDECLARED
  1427. %token END
  1428. %token ORG
  1429. %token ASSERT
  1430. %token TSTATE
  1431. %token <ival> T
  1432. %token <ival> TILO
  1433. %token <ival> TIHI
  1434. %token SETOCF
  1435. %token <ival> OCF
  1436. %token <ival> LOW
  1437. %token <ival> HIGH
  1438. %token DC
  1439. %token DEFB
  1440. %token DEFD
  1441. %token DEFS
  1442. %token DEFW
  1443. %token EQU
  1444. %token DEFL
  1445. %token <itemptr> LABEL
  1446. %token <itemptr> EQUATED
  1447. %token <itemptr> WASEQUATED
  1448. %token <itemptr> DEFLED
  1449. %token <itemptr> MULTDEF
  1450. %token <ival> MOD
  1451. %token <ival> SHL
  1452. %token <ival> SHR
  1453. %token <ival> NOT
  1454. %token <ival> LT
  1455. %token <ival> GT
  1456. %token <ival> LE
  1457. %token <ival> GE
  1458. %token <ival> NE
  1459. %token IF_TK
  1460. %token ELSE_TK
  1461. %token ENDIF_TK
  1462. %token <itemptr> ARGPSEUDO
  1463. %token <itemptr> INCBIN
  1464. %token <itemptr> LIST
  1465. %token <itemptr> MINMAX
  1466. %token MACRO
  1467. %token <itemptr> MNAME
  1468. %token ARG
  1469. %token ENDM
  1470. %token <ival> ONECHAR
  1471. %token <ival> TWOCHAR
  1472. %token JRPROMOTE
  1473. %token JPERROR
  1474. %token PUBLIC
  1475. %token EXTRN
  1476. %token MRAS_MOD
  1477. %token <itemptr> SETSEG INSTSET
  1478. %token LXI DAD STAX STA SHLD LDAX LHLD LDA MVI MOV
  1479. %token <itemptr> INXDCX INRDCR PSW JUMP8 JP CALL8 ALUI8
  1480. %token <itemptr> SPECIAL
  1481. %token RAWTOKEN LOCAL
  1482. // New token types for ZNONSTD support
  1483. %token <itemptr> LD_XY ST_XY MV_XY ALU_XY BIT_XY SHIFT_XY INP OUTP JR_COND
  1484. %token <itemptr> LDST16 ARITH16
  1485. // Tokens for improved macro support
  1486. %token REPT IRPC IRP EXITM
  1487. %token NUL
  1488. %token <itemptr> MPARM
  1489. %type <itemptr> label.part symbol
  1490. %type <ival> allreg reg evenreg ixylhreg realreg mem memxy pushable bcdesp bcdehlsp mar condition
  1491. %type <ival> spcondition
  1492. %type <exprptr> noparenexpr parenexpr expression lxexpression
  1493. %type <ival> maybecolon maybeocto
  1494. %type <ival> evenreg8 reg8 m pushable8
  1495. // Types for improved macro support
  1496. %type <cval> locals
  1497. %right '?' ':'
  1498. %left OROR
  1499. %left ANDAND
  1500. %left '|' OR
  1501. %left '^' XOR
  1502. %left '&' AND
  1503. %left '=' NE
  1504. %left '<' '>' LT GT LE GE
  1505. %left SHL SHR
  1506. %left '+' '-'
  1507. %left '*' '/' '%' MOD
  1508. %right '!' '~' NOT UNARY
  1509. %{
  1510. char *cp;
  1511. int i;
  1512. void do_equ(struct item *sym, struct expr *val, int call_list)
  1513. {
  1514. expr_reloc_check(val);
  1515. switch(sym->i_token) {
  1516. case UNDECLARED: case WASEQUATED:
  1517. if (sym->i_token == WASEQUATED &&
  1518. (sym->i_value != val->e_value ||
  1519. ((sym->i_scope ^ val->e_scope) & SCOPE_SEGMASK)))
  1520. {
  1521. if (outpass) {
  1522. if (sym->i_value != val->e_value)
  1523. sprintf(detail, "%s error - %s went from $%04x to $%04x",
  1524. errname[pflag], sym->i_string, sym->i_value, val->e_value);
  1525. else
  1526. sprintf(detail, "%s error - %s changed scope",
  1527. errname[pflag], sym->i_string);
  1528. errwarn(pflag, detail);
  1529. }
  1530. else
  1531. passretry = 1;
  1532. }
  1533. sym->i_token = EQUATED;
  1534. sym->i_value = val->e_value;
  1535. sym->i_scope |= val->e_scope;
  1536. break;
  1537. default:
  1538. // m80 allows multiple equates as long as the value
  1539. // does not change. So does newer zmac.
  1540. if (sym->i_value != val->e_value ||
  1541. ((sym->i_scope ^ val->e_scope) & SCOPE_SEGMASK))
  1542. {
  1543. err[mflag]++;
  1544. sym->i_token = MULTDEF;
  1545. }
  1546. }
  1547. sym->i_scope &= ~SCOPE_BUILTIN;
  1548. if (call_list)
  1549. list(val->e_value);
  1550. expr_free(val);
  1551. }
  1552. void do_defl(struct item *sym, struct expr *val, int call_list)
  1553. {
  1554. expr_reloc_check(val);
  1555. switch(sym->i_token) {
  1556. case UNDECLARED: case DEFLED:
  1557. sym->i_token = DEFLED;
  1558. sym->i_value = val->e_value;
  1559. sym->i_scope = (sym->i_scope & SCOPE_SEGMASK) | val->e_scope;
  1560. break;
  1561. default:
  1562. err[mflag]++;
  1563. sym->i_token = MULTDEF;
  1564. }
  1565. if (call_list)
  1566. list(val->e_value);
  1567. expr_free(val);
  1568. }
  1569. %}
  1570. %%
  1571. statements:
  1572. /* Empty file! */
  1573. |
  1574. statements statement
  1575. ;
  1576. statement:
  1577. label.part '\n' {
  1578. // An identfier without a colon all by itself on a line
  1579. // will be interpreted as a label. But there's a very
  1580. // good chance it is a misspelling of an instruction or
  1581. // pseudo-op name creating silent errors. Since the condition
  1582. // is unusual we print a warning. Unless it is followed by
  1583. // a colon in which case there's no ambiguity.
  1584. if ($1 && !firstcol && coloncnt == 0 && outpass) {
  1585. fprintf(stderr, "%s(%d): warning: '%s' treated as label (instruction typo?)\n",
  1586. src_name[now_in], linein[now_in], $1->i_string);
  1587. fprintf(stderr, "\tAdd a colon or move to first column to stop this warning.\n");
  1588. }
  1589. if ($1) list(dollarsign);
  1590. else list1();
  1591. }
  1592. |
  1593. label.part { list_dollarsign = 1; } operation '\n' {
  1594. list(list_dollarsign ? dollarsign : list_addr);
  1595. }
  1596. |
  1597. symbol EQU expression '\n' {
  1598. do_equ($1, $3, 1);
  1599. }
  1600. |
  1601. symbol '=' expression '\n' {
  1602. do_equ($1, $3, 1); // TODO: is '=' equate or defl?
  1603. }
  1604. |
  1605. symbol DEFL expression '\n' {
  1606. do_defl($1, $3, 1);
  1607. }
  1608. |
  1609. symbol MINMAX expression ',' expression '\n' {
  1610. int val3 = $3->e_value;
  1611. int val5 = $5->e_value;
  1612. expr_reloc_check($3);
  1613. expr_reloc_check($5);
  1614. expr_scope_same($3, $5);
  1615. switch ($1->i_token) {
  1616. case UNDECLARED: case DEFLED:
  1617. $1->i_token = DEFLED;
  1618. $1->i_scope |= $3->e_scope;
  1619. if ($2->i_value) /* max */
  1620. list($1->i_value = (val3 > val5? val3:val5));
  1621. else list($1->i_value = (val3 < val5? val3:val5));
  1622. break;
  1623. default:
  1624. err[mflag]++;
  1625. $1->i_token = MULTDEF;
  1626. list($1->i_value);
  1627. }
  1628. expr_free($3);
  1629. expr_free($5);
  1630. }
  1631. |
  1632. IF_TK expression '\n' {
  1633. expr_number_check($2);
  1634. if (ifptr >= ifstmax)
  1635. error("Too many ifs");
  1636. else
  1637. *++ifptr = !($2->e_value);
  1638. saveopt = fopt;
  1639. fopt = 1;
  1640. list($2->e_value);
  1641. fopt = saveopt;
  1642. expr_free($2);
  1643. }
  1644. |
  1645. ELSE_TK '\n' {
  1646. /* FIXME: it would be nice to spot repeated ELSEs, but how? */
  1647. *ifptr = !*ifptr;
  1648. saveopt = fopt;
  1649. fopt = 1;
  1650. list1();
  1651. fopt = saveopt;
  1652. }
  1653. |
  1654. ENDIF_TK '\n' {
  1655. if (ifptr == ifstack) err[bflag]++;
  1656. else --ifptr;
  1657. list1();
  1658. }
  1659. |
  1660. label.part END '\n' {
  1661. list(dollarsign);
  1662. peekc = 0;
  1663. }
  1664. |
  1665. label.part END expression '\n' {
  1666. expr_reloc_check($3);
  1667. xeq_flag++;
  1668. xeq = $3->e_value & 0xffff;
  1669. list($3->e_value);
  1670. peekc = 0;
  1671. rel_main = (($3->e_scope & SCOPE_SEGMASK) << 16) | xeq;
  1672. expr_free($3);
  1673. }
  1674. |
  1675. label.part DEFS expression '\n' {
  1676. expr_number_check($3);
  1677. if ($3->e_value < 0) err[vflag]++;
  1678. if ($3->e_value > 0) {
  1679. if (!phaseflag) {
  1680. list(dollarsign);
  1681. flushbin();
  1682. flushoth();
  1683. dollarsign += $3->e_value;
  1684. olddollar += $3->e_value;
  1685. oldothdollar += $3->e_value;
  1686. emit_addr += $3->e_value;
  1687. advance_segment($3->e_value);
  1688. putrelcmd(RELCMD_SETLOC);
  1689. putrelsegref(segment, seg_pos[segment]);
  1690. }
  1691. else
  1692. dc($3->e_value, 0);
  1693. }
  1694. else
  1695. list1();
  1696. expr_free($3);
  1697. }
  1698. |
  1699. label.part DEFS expression ',' expression '\n' {
  1700. expr_number_check($3);
  1701. expr_number_check($5);
  1702. if ($3->e_value < 0) err[vflag]++;
  1703. if ($5->e_value < -128 || $5->e_value > 127) err[vflag]++;
  1704. if ($3->e_value > 0) {
  1705. dc($3->e_value, $5->e_value);
  1706. }
  1707. else
  1708. list1();
  1709. expr_free($3);
  1710. expr_free($5);
  1711. }
  1712. |
  1713. label.part DC ONECHAR '\n' { emit(1, E_DATA, expr_num($3 | 0x80)); list(dollarsign); }
  1714. |
  1715. label.part DC TWOCHAR '\n' { emit(1, E_DATA, expr_num($3)); emit(1, E_DATA, expr_num(($3 >> 8) | 0x80)); list(dollarsign); }
  1716. |
  1717. label.part DC STRING '\n'
  1718. {
  1719. for (cp = $3; *cp != '\0'; cp++)
  1720. if (!cp[1])
  1721. emit(1, E_DATA, expr_num(*cp | 0x80));
  1722. else
  1723. emit(1, E_DATA, expr_num(*cp));
  1724. list(dollarsign);
  1725. }
  1726. |
  1727. label.part DC expression ',' expression '\n'
  1728. {
  1729. expr_number_check($3);
  1730. expr_number_check($5);
  1731. dc($3->e_value, $5->e_value);
  1732. expr_free($3);
  1733. expr_free($5);
  1734. }
  1735. |
  1736. ARGPSEUDO arg_on ARG arg_off '\n' {
  1737. list1();
  1738. switch ($1->i_value) {
  1739. case PSTITL: /* title */
  1740. lineptr = linebuf;
  1741. cp = tempbuf;
  1742. title = titlespace;
  1743. while ((*title++ = *cp++) && (title < &titlespace[TITLELEN]));
  1744. *title = 0;
  1745. title = titlespace;
  1746. break;
  1747. case PSRSYM: /* rsym */
  1748. if (pass2) break;
  1749. insymtab(tempbuf);
  1750. break;
  1751. case PSWSYM: /* wsym */
  1752. writesyms = malloc(strlen(tempbuf)+1);
  1753. strcpy(writesyms, tempbuf);
  1754. break;
  1755. case PSINC: /* include file */
  1756. next_source(tempbuf) ;
  1757. break ;
  1758. case PSMACLIB:
  1759. strcat(tempbuf, ".lib");
  1760. next_source(tempbuf);
  1761. break;
  1762. }
  1763. }
  1764. |
  1765. ARGPSEUDO arg_on arg_off '\n' {
  1766. fprintf(stderr, "Missing argument of '%s'\n", $1->i_string);
  1767. err[fflag]++;
  1768. list(dollarsign);
  1769. }
  1770. |
  1771. label.part INCBIN arg_on ARG arg_off '\n' {
  1772. incbin(tempbuf);
  1773. }
  1774. |
  1775. SPECIAL { raw = 1; } RAWTOKEN {
  1776. int quote = 0;
  1777. char *p, *q;
  1778. switch ($1->i_value) {
  1779. case SPTITL:
  1780. cp = tempbuf;
  1781. title = titlespace;
  1782. if (*cp == '\'' || *cp == '"')
  1783. quote = *cp++;
  1784. while ((*title++ = *cp++) && (title < &titlespace[TITLELEN]));
  1785. if (quote && title > titlespace + 1 && title[-2] == quote)
  1786. title[-2] = '\0';
  1787. title = titlespace;
  1788. list1();
  1789. break;
  1790. case SPSBTL:
  1791. err[warn_notimpl]++;
  1792. list1();
  1793. break;
  1794. case SPNAME:
  1795. // Drop surrounding ('') if present
  1796. p = tempbuf;
  1797. q = strchr(tempbuf, '\0') - 1;
  1798. if (*p == '(' && *q == ')' && q > p) p++, q--;
  1799. if (*p == '\'' && *q == '\'' && q > p) p++, q--;
  1800. q[1] = '\0';
  1801. strncpy(progname, p, sizeof progname);
  1802. progname[sizeof progname - 1] = '\0';
  1803. list1();
  1804. break;
  1805. case SPCOM:
  1806. quote = *tempbuf;
  1807. list1();
  1808. for (;;) {
  1809. raw = 1;
  1810. yychar = yylex();
  1811. list1();
  1812. if (yychar == 0)
  1813. break;
  1814. if (*tempbuf == quote) {
  1815. yychar = yylex();
  1816. break;
  1817. }
  1818. }
  1819. break;
  1820. case SPPRAGMA:
  1821. if (strncmp(tempbuf, "bds", 3) == 0 && bopt && outpass) {
  1822. fprintf(fbds, "%s\n", tempbuf + 4);
  1823. }
  1824. list1();
  1825. break;
  1826. }
  1827. }
  1828. |
  1829. LIST '\n' {
  1830. goto dolopt; }
  1831. |
  1832. LIST expression '\n' {
  1833. int enable = $2->e_value;
  1834. expr_number_check($2);
  1835. expr_free($2);
  1836. goto doloptA;
  1837. dolopt:
  1838. enable = 1;
  1839. doloptA:
  1840. linecnt++;
  1841. if (outpass) {
  1842. lineptr = linebuf;
  1843. switch ($1->i_value) {
  1844. case 0: /* list */
  1845. if (enable < 0) lstoff = 1;
  1846. if (enable > 0) lstoff = 0;
  1847. break;
  1848. case 1: /* eject */
  1849. if (enable) eject();
  1850. break;
  1851. case 2: /* space */
  1852. if ((line + enable) > 60) eject();
  1853. else space(enable);
  1854. break;
  1855. case 3: /* elist */
  1856. eopt = edef;
  1857. if (enable < 0) eopt = 0;
  1858. if (enable > 0) eopt = 1;
  1859. break;
  1860. case 4: /* fopt */
  1861. fopt = fdef;
  1862. if (enable < 0) fopt = 0;
  1863. if (enable > 0) fopt = 1;
  1864. break;
  1865. case 5: /* gopt */
  1866. gopt = gdef;
  1867. if (enable < 0) gopt = 1;
  1868. if (enable > 0) gopt = 0;
  1869. break;
  1870. case 6: /* mopt */
  1871. mopt = mdef;
  1872. if (enable < 0) mopt = 0;
  1873. if (enable > 0) mopt = 1;
  1874. }
  1875. }
  1876. }
  1877. |
  1878. JRPROMOTE expression '\n' {
  1879. expr_number_check($2);
  1880. jopt = !!$2->e_value;
  1881. list1();
  1882. expr_free($2);
  1883. }
  1884. |
  1885. JPERROR expression '\n' {
  1886. expr_number_check($2);
  1887. JPopt = !!$2->e_value;
  1888. list1();
  1889. expr_free($2);
  1890. }
  1891. |
  1892. PUBLIC public.list '\n' {
  1893. list1();
  1894. }
  1895. |
  1896. EXTRN extrn.list '\n' {
  1897. list1();
  1898. }
  1899. |
  1900. MRAS_MOD '\n' {
  1901. char *p = strchr(modstr, '\0') - 1;
  1902. for (; p >= modstr; p--) {
  1903. (*p)++;
  1904. if (*p < 'Z')
  1905. break;
  1906. *p = 'A';
  1907. }
  1908. list1();
  1909. }
  1910. |
  1911. SETSEG '\n' {
  1912. if (relopt && segment != $1->i_value) {
  1913. segment = $1->i_value;
  1914. segchange = 1;
  1915. dollarsign = seg_pos[$1->i_value];
  1916. }
  1917. list1();
  1918. }
  1919. |
  1920. INSTSET '\n' {
  1921. z80 = $1->i_value;
  1922. list1();
  1923. }
  1924. |
  1925. UNDECLARED MACRO { param_parse = 1; } parm.list '\n' {
  1926. param_parse = 0;
  1927. $1->i_token = MNAME;
  1928. $1->i_value = mfptr;
  1929. if (keyword($1->i_string)) {
  1930. sprintf(detail, "Macro '%s' will override the built-in '%s'",
  1931. $1->i_string, $1->i_string);
  1932. errwarn(warn_general, detail);
  1933. }
  1934. #ifdef M_DEBUG
  1935. fprintf (stderr, "%s(%d) [UNDECLARED MACRO %s]\n",
  1936. src_name[now_in], linein[now_in], $1->i_string);
  1937. #endif
  1938. list1();
  1939. }
  1940. locals {
  1941. mlex_list_on++;
  1942. mfseek(mfile, (long)mfptr, 0);
  1943. mlex($7);
  1944. mlex_list_on--;
  1945. parm_number = 0;
  1946. }
  1947. |
  1948. label.part MNAME al { arg_state.macarg = 1; } arg.list '\n' {
  1949. #ifdef M_DEBUG
  1950. fprintf (stderr, "%s(%d) [MNAME %s]\n",
  1951. src_name[now_in], linein[now_in], $2->i_string);
  1952. #endif
  1953. $2->i_uses++ ;
  1954. arg_reset();
  1955. parm_number = 0;
  1956. list(dollarsign);
  1957. expptr++;
  1958. est = est2;
  1959. est2 = NULL; // GWP - this may leak, but it avoids double-free crashes
  1960. est[FLOC].value = floc;
  1961. est[TEMPNUM].value = exp_number++;
  1962. est[MIF].param = ifptr;
  1963. est[REPNUM].value = 0;
  1964. est[MSTR].param = NULL;
  1965. floc = $2->i_value;
  1966. mfseek(mfile, (long)floc, 0);
  1967. }
  1968. |
  1969. label.part REPT expression al '\n' {
  1970. expr_reloc_check($3);
  1971. list1();
  1972. arg_reset();
  1973. }
  1974. locals {
  1975. int pos = mfptr;
  1976. mfseek(mfile, (long)mfptr, 0);
  1977. mlex($7);
  1978. parm_number = 0;
  1979. // MRAS compat would require treating the repeat count
  1980. // as a byte value with 0 == 256.
  1981. if ($3->e_value > 0) {
  1982. expptr++;
  1983. est = est2;
  1984. est2 = NULL;
  1985. est[FLOC].value = floc;
  1986. est[TEMPNUM].value = exp_number++;
  1987. est[MIF].param = ifptr;
  1988. est[REPNUM].value = $3->e_value - 1;
  1989. est[MSTART].value = pos;
  1990. est[MSTR].param = NULL;
  1991. floc = pos;
  1992. mfseek(mfile, (long)floc, 0);
  1993. }
  1994. }
  1995. |
  1996. label.part IRPC parm.single ',' { parm_number = 0; } al arg.element arg_off '\n'
  1997. {
  1998. list1();
  1999. }
  2000. locals {
  2001. int pos = mfptr;
  2002. mfseek(mfile, (long)mfptr, 0);
  2003. mlex($11);
  2004. parm_number = 0;
  2005. if (est2[0].param[0]) {
  2006. expptr++;
  2007. est = est2;
  2008. est2 = NULL;
  2009. est[FLOC].value = floc;
  2010. est[TEMPNUM].value = exp_number++;
  2011. est[MIF].param = ifptr;
  2012. est[REPNUM].value = 0;
  2013. est[MSTART].value = pos;
  2014. est[MSTR].param = est[0].param;
  2015. est[0].param = malloc(2);
  2016. est[0].param[0] = est[MSTR].param[0];
  2017. est[0].param[1] = '\0';
  2018. floc = pos;
  2019. mfseek(mfile, (long)floc, 0);
  2020. }
  2021. }
  2022. |
  2023. label.part IRP parm.single ',' { parm_number = 0; } al arg.element arg_off '\n'
  2024. {
  2025. list1();
  2026. }
  2027. locals {
  2028. int pos = mfptr;
  2029. mfseek(mfile, (long)mfptr, 0);
  2030. mlex($11);
  2031. parm_number = 0;
  2032. // if the sub list is not empty
  2033. if (est2[0].param[0] && est2[0].param[0] != ';'
  2034. && est2[0].param[0] != '\n')
  2035. {
  2036. expptr++;
  2037. est = est2;
  2038. est2 = NULL;
  2039. est[FLOC].value = floc;
  2040. est[TEMPNUM].value = exp_number++;
  2041. est[MIF].param = ifptr;
  2042. est[REPNUM].value = -1;
  2043. est[MSTART].value = pos;
  2044. est[MSTR].param = NULL;
  2045. est[MARGP].ap = malloc(sizeof *est[MARGP].ap);
  2046. est[MARGP].ap->arg = malloc(TEMPBUFSIZE);
  2047. est[MARGP].ap->argsize = TEMPBUFSIZE;
  2048. est[MARGP].ap->getch = str_getch;
  2049. est[MARGP].ap->user_ptr = est[0].param;
  2050. est[MARGP].ap->user_int = 0;
  2051. est[MARGP].ap->user_peek = -1;
  2052. est[MARGP].ap->peek = &est[MARGP].ap->user_peek;
  2053. est[MARGP].ap->macarg = 0;
  2054. est[MARGP].ap->didarg = 0;
  2055. est[MARGP].ap->numarg = 0;
  2056. est[0].param = est[MARGP].ap->arg;
  2057. getarg(est[MARGP].ap);
  2058. floc = pos;
  2059. mfseek(mfile, (long)floc, 0);
  2060. }
  2061. }
  2062. |
  2063. label.part EXITM '\n' {
  2064. // XXX - popsi() is not safe, There is type-specific cleanup.
  2065. // But for now...
  2066. // popsi() must be made safe as others use it.
  2067. list1();
  2068. popsi();
  2069. }
  2070. |
  2071. error {
  2072. err[fflag]++;
  2073. arg_reset();
  2074. parm_number = 0;
  2075. param_parse = 0;
  2076. if (est2)
  2077. {
  2078. int i;
  2079. for (i=0; i<PARMMAX; i++) {
  2080. if (est2[i].param) {
  2081. #ifdef M_DEBUG
  2082. fprintf (stderr, "[Freeing2 arg%u(%p)]\n", i, est2[i].param),
  2083. #endif
  2084. free(est2[i].param);
  2085. }
  2086. }
  2087. free(est2);
  2088. est2 = NULL;
  2089. }
  2090. while(yychar != '\n' && yychar != '\0') yychar = yylex();
  2091. list(dollarsign);
  2092. yyclearin;yyerrok;
  2093. }
  2094. ;
  2095. maybecolon:
  2096. /* empty */ { $$ = 0; }
  2097. |
  2098. ':' { $$ = 1; }
  2099. |
  2100. ':' ':' { $$ = 2; }
  2101. ;
  2102. label.part:
  2103. /*empty*/
  2104. { label = $$ = NULL; }
  2105. |
  2106. symbol maybecolon {
  2107. coloncnt = $2;
  2108. itemcpy(&pristine_label, $1);
  2109. label = coloncnt == 0 ? $1 : NULL;
  2110. $1->i_scope |= segment;
  2111. if ($2 == 2)
  2112. $1->i_scope |= SCOPE_PUBLIC;
  2113. if ($1->i_string[0] != '.')
  2114. llseq++;
  2115. switch($1->i_token) {
  2116. case UNDECLARED:
  2117. if (pass2) {
  2118. sprintf(detail, "%s error - label '%s' not declared",
  2119. errname[pflag], $1->i_string);
  2120. errwarn(pflag, detail);
  2121. }
  2122. else {
  2123. $1->i_token = LABEL;
  2124. $1->i_value = dollarsign;
  2125. }
  2126. break;
  2127. case LABEL:
  2128. if (!pass2) {
  2129. $1->i_token = MULTDEF;
  2130. err[mflag]++;
  2131. } else if ($1->i_value != dollarsign) {
  2132. // XXX - perhaps only allow retrys if JR promotions are in play?
  2133. if (outpass) {
  2134. if (!passfail) {
  2135. sprintf(detail, "%s error - label '%s' changed from $%04x to $%04x",
  2136. errname[pflag], $1->i_string, $1->i_value, dollarsign);
  2137. errwarn(pflag, detail);
  2138. }
  2139. }
  2140. else {
  2141. $1->i_value = dollarsign;
  2142. passretry = 1;
  2143. }
  2144. }
  2145. break;
  2146. default:
  2147. err[mflag]++;
  2148. $1->i_token = MULTDEF;
  2149. }
  2150. }
  2151. ;
  2152. public.list:
  2153. public.part
  2154. |
  2155. public.list ',' public.part
  2156. ;
  2157. public.part:
  2158. symbol {
  2159. $1->i_scope |= SCOPE_PUBLIC;
  2160. if (pass2) {
  2161. if ($1->i_token == UNDECLARED) {
  2162. sprintf(detail, "'%s' %s", $1->i_string, errname[uflag]);
  2163. errwarn(uflag, detail);
  2164. }
  2165. }
  2166. }
  2167. ;
  2168. extrn.list:
  2169. extrn.part
  2170. |
  2171. extrn.list ',' extrn.part
  2172. ;
  2173. extrn.part:
  2174. symbol {
  2175. if (pass2 && $1->i_scope != SCOPE_NONE && !($1->i_scope & SCOPE_EXTERNAL)) {
  2176. fprintf(stderr, "Label scope change\n");
  2177. err[fflag]++;
  2178. }
  2179. $1->i_scope |= SCOPE_EXTERNAL;
  2180. if (pass2) {
  2181. if ($1->i_token != UNDECLARED) {
  2182. fprintf(stderr, "External label defined locally.\n");
  2183. err[fflag]++;
  2184. }
  2185. }
  2186. }
  2187. ;
  2188. operation:
  2189. NOOPERAND
  2190. { emit1($1->i_value, 0, 0, ET_NOARG); }
  2191. |
  2192. NOOPERAND expression
  2193. {
  2194. // XXX - maybe splitting out CPI is better?
  2195. if (!z80 && $1->i_value == 0166641)
  2196. emit1(0376, 0, $2, ET_BYTE);
  2197. else
  2198. err[fflag]++;
  2199. }
  2200. |
  2201. SHIFT
  2202. {
  2203. if (!z80 && $1->i_value < 2)
  2204. emit(1, E_CODE, 0, 007 | ($1->i_value << 3));
  2205. else
  2206. err[fflag]++;
  2207. }
  2208. |
  2209. JP expression
  2210. {
  2211. if (z80 || $1->i_value == 0303) {
  2212. checkjp(0, $2);
  2213. emit(1, E_CODE16, $2, 0303);
  2214. }
  2215. else
  2216. // can't optimize jump on plus
  2217. emit(1, E_CODE16, $2, 0362);
  2218. }
  2219. |
  2220. CALL expression
  2221. { emit(1, E_CODE16, $2, 0315); }
  2222. |
  2223. RST expression
  2224. {
  2225. // accepts rst 0-7 or rst 0,8,16,...,56
  2226. int vec = $2->e_value;
  2227. expr_number_check($2);
  2228. if ((vec > 7 || vec < 0) && (vec & ~(7 << 3)))
  2229. err[vflag]++;
  2230. if (vec > 7) vec >>= 3;
  2231. emit(1, E_CODE, 0, $1->i_value + ((vec & 7) << 3));
  2232. expr_free($2);
  2233. }
  2234. |
  2235. ALUI8 expression
  2236. { emit1($1->i_value, 0, $2, ET_BYTE); }
  2237. |
  2238. ALU_XY dxy
  2239. {
  2240. emit(3, E_CODE, 0, $1->i_value >> 8, $1->i_value, disp);
  2241. }
  2242. |
  2243. ADD expression
  2244. { emit1(0306, 0, $2, ET_BYTE); }
  2245. |
  2246. ADD ACC ',' expression
  2247. { emit1(0306, 0, $4, ET_BYTE); }
  2248. |
  2249. ARITHC expression
  2250. { emit1(0306 + ($1->i_value << 3), 0, $2, ET_BYTE); }
  2251. |
  2252. ARITHC ACC ',' expression
  2253. { emit1(0306 + ($1->i_value << 3), 0, $4, ET_BYTE); }
  2254. |
  2255. LOGICAL expression
  2256. {
  2257. if (!z80 && $1->i_value == 7)
  2258. emit(1, E_CODE16, $2, 0364);
  2259. else
  2260. emit1(0306 | ($1->i_value << 3), 0, $2, ET_BYTE);
  2261. }
  2262. |
  2263. AND expression
  2264. { emit1(0306 | ($1->i_value << 3), 0, $2, ET_BYTE); }
  2265. |
  2266. OR expression
  2267. { emit1(0306 | ($1->i_value << 3), 0, $2, ET_BYTE); }
  2268. |
  2269. XOR expression
  2270. { emit1(0306 | ($1->i_value << 3), 0, $2, ET_BYTE); }
  2271. |
  2272. LOGICAL ACC ',' expression /* -cdk */
  2273. { emit1(0306 | ($1->i_value << 3), 0, $4, ET_BYTE); }
  2274. |
  2275. AND ACC ',' expression /* -cdk */
  2276. { emit1(0306 | ($1->i_value << 3), 0, $4, ET_BYTE); }
  2277. |
  2278. OR ACC ',' expression /* -cdk */
  2279. { emit1(0306 | ($1->i_value << 3), 0, $4, ET_BYTE); }
  2280. |
  2281. XOR ACC ',' expression /* -cdk */
  2282. { emit1(0306 | ($1->i_value << 3), 0, $4, ET_BYTE); }
  2283. |
  2284. ADD allreg
  2285. { emit1(0200 + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2286. |
  2287. ADD ACC ',' allreg
  2288. { emit1(0200 + ($4 & 0377), $4, 0, ET_NOARG_DISP); }
  2289. |
  2290. ADD m
  2291. { emit(1, E_CODE, 0, 0206); }
  2292. |
  2293. ARITHC allreg
  2294. { emit1(0200 + ($1->i_value << 3) + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2295. |
  2296. ARITHC ACC ',' allreg
  2297. { emit1(0200 + ($1->i_value << 3) + ($4 & 0377), $4, 0, ET_NOARG_DISP); }
  2298. |
  2299. ARITHC m
  2300. { emit1(0200 + ($1->i_value << 3) + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2301. |
  2302. LOGICAL allreg
  2303. { emit1(0200 + ($1->i_value << 3) + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2304. |
  2305. LOGICAL m
  2306. { emit1(0200 + ($1->i_value << 3) + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2307. |
  2308. AND allreg
  2309. { emit1(0200 + ($1->i_value << 3) + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2310. |
  2311. OR allreg
  2312. { emit1(0200 + ($1->i_value << 3) + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2313. |
  2314. XOR allreg
  2315. { emit1(0200 + ($1->i_value << 3) + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2316. |
  2317. LOGICAL ACC ',' allreg /* -cdk */
  2318. { emit1(0200 + ($1->i_value << 3) + ($4 & 0377), $4, 0, ET_NOARG_DISP); }
  2319. |
  2320. AND ACC ',' allreg /* -cdk */
  2321. { emit1(0200 + ($1->i_value << 3) + ($4 & 0377), $4, 0, ET_NOARG_DISP); }
  2322. |
  2323. OR ACC ',' allreg /* -cdk */
  2324. { emit1(0200 + ($1->i_value << 3) + ($4 & 0377), $4, 0, ET_NOARG_DISP); }
  2325. |
  2326. XOR ACC ',' allreg /* -cdk */
  2327. { emit1(0200 + ($1->i_value << 3) + ($4 & 0377), $4, 0, ET_NOARG_DISP); }
  2328. |
  2329. SHIFT reg
  2330. { emit1(0145400 + ($1->i_value << 3) + ($2 & 0377), $2, 0, ET_NOARG_DISP); }
  2331. |
  2332. SHIFT_XY dxy
  2333. {
  2334. emit(4, E_CODE, 0, $1->i_value >> 8, 0xcb, disp, $1->i_value);
  2335. }
  2336. |
  2337. SHIFT memxy ',' realreg
  2338. { emit1(0xCB00 + ($1->i_value << 3) + ($4 & 0377), $2, 0, ET_NOARG_DISP); }
  2339. |
  2340. INCDEC allreg
  2341. { emit1($1->i_value + (($2 & 0377) << 3) + 4, $2, 0, ET_NOARG_DISP); }
  2342. |
  2343. INRDCR reg8
  2344. { emit1($1->i_value + (($2 & 0377) << 3) + 4, $2, 0, ET_NOARG_DISP); }
  2345. |
  2346. ARITHC HL ',' bcdehlsp
  2347. { if ($1->i_value == 1)
  2348. emit(2,E_CODE,0,0355,0112+$4);
  2349. else
  2350. emit(2,E_CODE,0,0355,0102+$4);
  2351. }
  2352. |
  2353. ADD mar ',' bcdesp
  2354. { emitdad($2,$4); }
  2355. |
  2356. ADD mar ',' mar
  2357. {
  2358. if ($2 != $4) {
  2359. fprintf(stderr,"ADD mar, mar error\n");
  2360. err[gflag]++;
  2361. }
  2362. emitdad($2,$4);
  2363. }
  2364. |
  2365. DAD evenreg8 { emitdad(040, $2); }
  2366. |
  2367. ARITH16 bcdesp
  2368. {
  2369. emit(2, E_CODE, 0, $1->i_value >> 8, $1->i_value | $2);
  2370. }
  2371. |
  2372. ARITH16 mar
  2373. {
  2374. int dst = $1->i_value >> 8;
  2375. int reg = $2 >> 8;
  2376. if (!reg) reg = 0xed;
  2377. if (dst != reg) {
  2378. if (dst == 0xed)
  2379. fprintf(stderr, "dadc/dsbc cannot take ix or iy\n");
  2380. else if (dst == 0xdd)
  2381. fprintf(stderr, "dadx cannot take hl or iy\n");
  2382. else
  2383. fprintf(stderr, "dady cannot take hl or ix\n");
  2384. err[gflag]++;
  2385. }
  2386. emit(2, E_CODE, 0, $1->i_value >> 8, $1->i_value | $2);
  2387. }
  2388. |
  2389. INCDEC evenreg
  2390. { emit1(($1->i_value << 3) + ($2 & 0377) + 3, $2, 0, ET_NOARG); }
  2391. |
  2392. INXDCX evenreg8
  2393. { emit1(($1->i_value << 3) + ($2 & 0377) + 3, $2, 0, ET_NOARG); }
  2394. |
  2395. PUSHPOP pushable
  2396. { emit1($1->i_value + ($2 & 0377), $2, 0, ET_NOARG); }
  2397. |
  2398. PUSHPOP pushable8
  2399. { emit1($1->i_value + ($2 & 0377), $2, 0, ET_NOARG); }
  2400. |
  2401. BIT expression
  2402. {
  2403. if (strcmp($1->i_string, "set") == 0 && label) {
  2404. // Clear error that label definition will have been set
  2405. err[mflag] = 0;
  2406. itemcpy(label, &pristine_label);
  2407. do_defl(label, $2, 0);
  2408. list_dollarsign = 0;
  2409. list_addr = label->i_value;
  2410. }
  2411. else {
  2412. err[fflag]++;
  2413. }
  2414. }
  2415. |
  2416. BIT expression ',' reg
  2417. {
  2418. int bit = $2->e_value;
  2419. expr_number_check($2);
  2420. expr_free($2);
  2421. if (bit < 0 || bit > 7)
  2422. err[vflag]++;
  2423. emit1($1->i_value + ((bit & 7) << 3) + ($4 & 0377), $4, 0, ET_NOARG_DISP);
  2424. }
  2425. |
  2426. BIT_XY expression ',' dxy
  2427. {
  2428. int bit = $2->e_value;
  2429. expr_number_check($2);
  2430. expr_free($2);
  2431. if (bit < 0 || bit > 7)
  2432. err[vflag]++;
  2433. emit(4, E_CODE, 0, $1->i_value >> 8, 0xcb, disp,
  2434. $1->i_value | (bit << 3));
  2435. }
  2436. |
  2437. BIT expression ',' memxy ',' realreg
  2438. {
  2439. int bit = $2->e_value;
  2440. expr_number_check($2);
  2441. expr_free($2);
  2442. if (bit < 0 || bit > 7)
  2443. err[vflag]++;
  2444. emit1($1->i_value + ((bit & 7) << 3) + ($6 & 0377), $4, 0, ET_NOARG_DISP);
  2445. }
  2446. |
  2447. JP condition ',' expression
  2448. {
  2449. checkjp($2, $4);
  2450. emit(1, E_CODE16, $4, 0302 + $2);
  2451. }
  2452. |
  2453. JUMP8 expression
  2454. {
  2455. checkjp($1->i_value, $2);
  2456. emit(1, E_CODE16, $2, $1->i_value);
  2457. }
  2458. |
  2459. JP '(' mar ')'
  2460. { emit1(0351, $3, 0, ET_NOARG); }
  2461. |
  2462. CALL condition ',' expression
  2463. { emit(1, E_CODE16, $4, 0304 + $2); }
  2464. |
  2465. CALL8 expression
  2466. { emit(1, E_CODE16, $2, $1->i_value); }
  2467. |
  2468. JR expression
  2469. { emitjr(030,$2); }
  2470. |
  2471. JR spcondition ',' expression
  2472. { emitjr($1->i_value + $2, $4); }
  2473. |
  2474. JR_COND expression
  2475. { emitjr($1->i_value, $2); }
  2476. |
  2477. DJNZ expression
  2478. { emitjr($1->i_value, $2); }
  2479. |
  2480. RET
  2481. { emit(1, E_CODE, 0, $1->i_value); }
  2482. |
  2483. RET condition
  2484. { emit(1, E_CODE, 0, 0300 + $2); }
  2485. |
  2486. LD allreg ',' allreg
  2487. {
  2488. // Many constraints on byte access to IX/IY registers.
  2489. if (($2 | $4) >> 16) {
  2490. int a = $2;
  2491. int b = $4;
  2492. // Only ixh,ixh; ixh,ixl; ixl,ixh; ixl,ixl allowed.
  2493. if (a >> 16 && b >> 16) {
  2494. if (a >> 8 != b >> 8) {
  2495. fprintf(stderr, "LD cannot move between ix and iy\n");
  2496. err[gflag]++;
  2497. }
  2498. }
  2499. else {
  2500. int c = b >> 16 ? a : b;
  2501. // No access to h, l, (hl), (ix), (iy)
  2502. if (c == 4 || c == 5 || (c & 0xff) == 6) {
  2503. fprintf(stderr, "LD cannot combine i/xy/lh and h,l,(hl),(ix) or (iy).\n");
  2504. err[gflag]++;
  2505. }
  2506. }
  2507. }
  2508. if (($2 & 0377) == 6 && ($4 & 0377) == 6) {
  2509. fprintf(stderr,"LD reg, reg error: can't do memory to memory\n");
  2510. err[gflag]++;
  2511. }
  2512. emit1(0100 + (($2 & 7) << 3) + ($4 & 7),$2 | $4, 0, ET_NOARG_DISP);
  2513. }
  2514. |
  2515. LD_XY realreg ',' dxy
  2516. {
  2517. emit(3, E_CODE, 0, $1->i_value >> 8, $1->i_value | ($2 << 3), disp);
  2518. }
  2519. |
  2520. ST_XY realreg ',' dxy
  2521. {
  2522. emit(3, E_CODE, 0, $1->i_value >> 8, $1->i_value | $2, disp);
  2523. }
  2524. |
  2525. MOV reg8 ',' reg8
  2526. {
  2527. if ($2 == 6 && $4 == 6) err[gflag]++;
  2528. emit1(0100 + (($2 & 7) << 3) + ($4 & 7),$2 | $4, 0, ET_NOARG_DISP);
  2529. }
  2530. |
  2531. LD allreg ',' noparenexpr
  2532. { emit1(6 + (($2 & 0377) << 3), $2, $4, ET_BYTE); }
  2533. |
  2534. MV_XY expression ',' dxy
  2535. {
  2536. emit(3, E_CODE8, $2, $1->i_value >> 8, $1->i_value, disp);
  2537. }
  2538. |
  2539. MVI reg8 ',' expression
  2540. { emit1(6 + (($2 & 0377) << 3), $2, $4, ET_BYTE); }
  2541. |
  2542. LD allreg ',' '(' RP ')'
  2543. { if ($2 != 7) {
  2544. fprintf(stderr,"LD reg, (RP) error\n");
  2545. err[gflag]++;
  2546. }
  2547. else emit(1, E_CODE, 0, 012 + $5->i_value);
  2548. }
  2549. |
  2550. LDAX realreg
  2551. {
  2552. if ($2 != 0 && $2 != 2) err[gflag]++;
  2553. emit(1, E_CODE, 0, 012 + ($2 << 3));
  2554. }
  2555. |
  2556. LD allreg ',' parenexpr
  2557. {
  2558. if ($2 != 7) {
  2559. fprintf(stderr,"LD reg, (expr) error: A only valid destination\n");
  2560. err[gflag]++;
  2561. }
  2562. else {
  2563. expr_word_check($4);
  2564. emit(1, E_CODE16, $4, 072);
  2565. }
  2566. }
  2567. |
  2568. LDA expression
  2569. {
  2570. expr_word_check($2);
  2571. emit(1, E_CODE16, $2, 072);
  2572. }
  2573. |
  2574. LD '(' RP ')' ',' ACC
  2575. { emit(1, E_CODE, 0, 2 + $3->i_value); }
  2576. |
  2577. STAX realreg
  2578. {
  2579. if ($2 != 0 && $2 != 2) err[gflag]++;
  2580. emit(1, E_CODE, 0, 2 + ($2 << 3));
  2581. }
  2582. |
  2583. LD parenexpr ',' ACC
  2584. {
  2585. expr_word_check($2);
  2586. emit(1, E_CODE16, $2, 062);
  2587. }
  2588. |
  2589. STA expression
  2590. {
  2591. expr_word_check($2);
  2592. emit(1, E_CODE16, $2, 062);
  2593. }
  2594. |
  2595. LD allreg ',' MISCREG
  2596. {
  2597. if ($2 != 7) {
  2598. fprintf(stderr,"LD reg, MISCREG error: A only valid destination\n");
  2599. err[gflag]++;
  2600. }
  2601. else emit(2, E_CODE, 0, 0355, 0127 + $4->i_value);
  2602. }
  2603. |
  2604. LD MISCREG ',' ACC
  2605. { emit(2, E_CODE, 0, 0355, 0107 + $2->i_value); }
  2606. |
  2607. LD evenreg ',' lxexpression
  2608. {
  2609. expr_word_check($4);
  2610. emit1(1 + ($2 & 060), $2, $4, ET_WORD);
  2611. }
  2612. |
  2613. LXI evenreg8 ',' lxexpression
  2614. {
  2615. expr_word_check($4);
  2616. emit1(1 + ($2 & 060), $2, $4, ET_WORD);
  2617. }
  2618. |
  2619. LD evenreg ',' parenexpr
  2620. {
  2621. expr_word_check($4);
  2622. if (($2 & 060) == 040)
  2623. emit1(052, $2, $4, ET_WORD);
  2624. else
  2625. emit(2, E_CODE16, $4, 0355, 0113 + $2);
  2626. }
  2627. |
  2628. LHLD expression
  2629. {
  2630. expr_word_check($2);
  2631. emit1(052, 040, $2, ET_WORD);
  2632. }
  2633. |
  2634. LD parenexpr ',' evenreg
  2635. {
  2636. expr_word_check($2);
  2637. if (($4 & 060) == 040)
  2638. emit1(042, $4, $2, ET_WORD);
  2639. else
  2640. emit(2, E_CODE16, $2, 0355, 0103 + $4);
  2641. }
  2642. |
  2643. SHLD expression
  2644. {
  2645. expr_word_check($2);
  2646. emit1(042, 040, $2, ET_WORD);
  2647. }
  2648. |
  2649. LD evenreg ',' mar
  2650. {
  2651. if ($2 != 060) {
  2652. fprintf(stderr,"LD evenreg error\n");
  2653. err[gflag]++;
  2654. }
  2655. else
  2656. emit1(0371, $4, 0, ET_NOARG);
  2657. }
  2658. |
  2659. LDST16 expression
  2660. {
  2661. expr_word_check($2);
  2662. emit(2, E_CODE16, $2, $1->i_value >> 8, $1->i_value);
  2663. }
  2664. |
  2665. EX RP ',' HL
  2666. {
  2667. if ($2->i_value != 020) {
  2668. fprintf(stderr,"EX RP, HL error\n");
  2669. err[gflag]++;
  2670. }
  2671. else
  2672. emit(1, E_CODE, 0, 0353);
  2673. }
  2674. |
  2675. EX AF ',' AFp
  2676. { emit(1, E_CODE, 0, 010); }
  2677. |
  2678. EX '(' SP ')' ',' mar
  2679. { emit1(0343, $6, 0, ET_NOARG); }
  2680. |
  2681. TK_IN realreg ',' parenexpr
  2682. {
  2683. if ($2 != 7) {
  2684. fprintf(stderr,"IN reg, (expr) error\n");
  2685. err[gflag]++;
  2686. }
  2687. else {
  2688. if ($4->e_value < 0 || $4->e_value > 255)
  2689. err[vflag]++;
  2690. emit(1, E_CODE8, $4, $1->i_value);
  2691. }
  2692. }
  2693. |
  2694. TK_IN expression
  2695. {
  2696. if ($2->e_value < 0 || $2->e_value > 255)
  2697. err[vflag]++;
  2698. emit(1, E_CODE8, $2, $1->i_value);
  2699. }
  2700. |
  2701. TK_IN realreg ',' '(' C ')'
  2702. { emit(2, E_CODE, 0, 0355, 0100 + ($2 << 3)); }
  2703. |
  2704. INP realreg
  2705. { emit(2, E_CODE, 0, 0355, 0101 + ($2 << 3)); }
  2706. |
  2707. TK_IN 'F' ',' '(' C ')'
  2708. { emit(2, E_CODE, 0, 0355, 0160); }
  2709. |
  2710. TK_IN '(' C ')'
  2711. { emit(2, E_CODE, 0, 0355, 0160); }
  2712. |
  2713. TK_OUT parenexpr ',' ACC
  2714. {
  2715. if ($2->e_value < 0 || $2->e_value > 255)
  2716. err[vflag]++;
  2717. emit(1, E_CODE8, $2, $1->i_value);
  2718. }
  2719. |
  2720. TK_OUT expression
  2721. {
  2722. if ($2->e_value < 0 || $2->e_value > 255)
  2723. err[vflag]++;
  2724. emit(1, E_CODE8, $2, $1->i_value);
  2725. }
  2726. |
  2727. TK_OUT '(' C ')' ',' realreg
  2728. { emit(2, E_CODE, 0, 0355, 0101 + ($6 << 3)); }
  2729. |
  2730. OUTP realreg
  2731. { emit(2, E_CODE, 0, 0355, 0101 + ($2 << 3)); }
  2732. |
  2733. TK_OUT '(' C ')' ',' expression
  2734. {
  2735. expr_number_check($6);
  2736. if ($6->e_value != 0) {
  2737. fprintf(stderr, "Can only output 0 to port C with OUT\n");
  2738. err[vflag]++;
  2739. }
  2740. expr_free($6);
  2741. emit(2, E_CODE8, 0, 0355, 0101 + (6 << 3));
  2742. }
  2743. |
  2744. IM expression
  2745. {
  2746. int im = $2->e_value;
  2747. expr_number_check($2);
  2748. expr_free($2);
  2749. if (im > 2 || im < 0)
  2750. err[vflag]++;
  2751. else
  2752. emit(2, E_CODE, 0, $1->i_value >> 8, $1->i_value + ((im + (im > 0)) << 3));
  2753. }
  2754. |
  2755. PHASE expression
  2756. {
  2757. expr_number_check($2);
  2758. if (phaseflag) {
  2759. err[oflag]++;
  2760. } else {
  2761. phaseflag = 1;
  2762. phdollar = dollarsign;
  2763. dollarsign = $2->e_value;
  2764. phbegin = dollarsign;
  2765. }
  2766. expr_free($2);
  2767. }
  2768. |
  2769. DEPHASE
  2770. {
  2771. if (!phaseflag) {
  2772. err[oflag]++;
  2773. } else {
  2774. phaseflag = 0;
  2775. dollarsign = phdollar + dollarsign - phbegin;
  2776. }
  2777. }
  2778. |
  2779. ORG expression
  2780. {
  2781. expr_reloc_check($2);
  2782. // Cannot org to the other segment (but absolute values are OK)
  2783. if (relopt && segment && ($2->e_scope & SCOPE_SEGMASK) != segment)
  2784. err[rflag]++;
  2785. if (phaseflag) {
  2786. err[oflag]++;
  2787. dollarsign = phdollar + dollarsign - phbegin;
  2788. phaseflag = 0;
  2789. }
  2790. if ($2->e_value-dollarsign) {
  2791. flushbin();
  2792. flushoth();
  2793. olddollar = $2->e_value;
  2794. oldothdollar = $2->e_value;
  2795. dollarsign = $2->e_value;
  2796. emit_addr = $2->e_value;
  2797. seg_pos[segment] = dollarsign;
  2798. if (seg_pos[segment] > seg_size[segment])
  2799. seg_size[segment] = seg_pos[segment];
  2800. putrelcmd(RELCMD_SETLOC);
  2801. putrelsegref(segment, seg_pos[segment]);
  2802. segchange = 0;
  2803. }
  2804. expr_free($2);
  2805. }
  2806. |
  2807. ASSERT expression
  2808. {
  2809. list_dollarsign = 0;
  2810. list_addr = $2->e_value;
  2811. expr_number_check($2);
  2812. if (outpass && !$2->e_value)
  2813. {
  2814. err[aflag]++;
  2815. }
  2816. expr_free($2);
  2817. }
  2818. |
  2819. TSTATE expression
  2820. {
  2821. list_dollarsign = 0;
  2822. list_addr = $2->e_value;
  2823. expr_number_check($2);
  2824. tstates = $2->e_value;
  2825. tstatesum[emit_addr] = tstates;
  2826. expr_free($2);
  2827. }
  2828. |
  2829. SETOCF expression
  2830. {
  2831. list_dollarsign = 0;
  2832. list_addr = $2->e_value;
  2833. expr_number_check($2);
  2834. ocf = $2->e_value;
  2835. ocfsum[emit_addr] = ocf;
  2836. expr_free($2);
  2837. }
  2838. |
  2839. DEFB { full_exprs = 1; } db.list { full_exprs = 0; }
  2840. |
  2841. DEFW { full_exprs = 1; } dw.list { full_exprs = 0; }
  2842. |
  2843. DEFD { full_exprs = 1; } dd.list { full_exprs = 0; }
  2844. |
  2845. ENDM
  2846. ;
  2847. parm.list:
  2848. |
  2849. parm.element
  2850. |
  2851. parm.list ',' parm.element
  2852. ;
  2853. parm.single: { param_parse = 1; } parm.element { param_parse = 0; };
  2854. maybeocto: { $$ = 0; } | '#' { $$ = 1; };
  2855. parm.element:
  2856. maybeocto MPARM
  2857. {
  2858. if (parm_number >= PARMMAX)
  2859. error("Too many parameters");
  2860. $2->i_value = parm_number++;
  2861. $2->i_scope = $1;
  2862. $2->i_chain = 0;
  2863. }
  2864. ;
  2865. locals: local_decls {
  2866. static char macpush[LINEBUFFERSIZE];
  2867. // Because of locals the parser has to look ahead.
  2868. // We'll have buffered that as we usually do so just a
  2869. // matter of picking that up and cancelling any look-ahead.
  2870. *lineptr = '\0';
  2871. strcpy(macpush, linebuf);
  2872. lineptr = linebuf;
  2873. peekc = -1;
  2874. yychar = YYEMPTY;
  2875. $$ = macpush;
  2876. }
  2877. ;
  2878. local_decls:
  2879. |
  2880. local_decls LOCAL { param_parse = 1; } local.list '\n' { param_parse = 0; list1(); }
  2881. ;
  2882. local.list:
  2883. |
  2884. local.element
  2885. |
  2886. local.list ',' local.element
  2887. ;
  2888. local.element:
  2889. MPARM
  2890. {
  2891. if (parm_number >= PARMMAX)
  2892. error("Too many parameters");
  2893. $1->i_value = parm_number++;
  2894. $1->i_scope = 0;
  2895. $1->i_chain = 1;
  2896. }
  2897. ;
  2898. arg.list:
  2899. /* empty */
  2900. |
  2901. arg.element
  2902. |
  2903. arg.list ',' arg.element
  2904. ;
  2905. arg.element:
  2906. ARG
  2907. {
  2908. cp = malloc(strlen(tempbuf)+1);
  2909. #ifdef M_DEBUG
  2910. fprintf (stderr, "[Arg%u(%p): %s]\n", parm_number, cp, tempbuf);
  2911. #endif
  2912. est2[parm_number++].param = cp;
  2913. strcpy(cp, tempbuf);
  2914. }
  2915. |
  2916. '%' { arg_flag = 0; } expression
  2917. {
  2918. arg_flag = 1;
  2919. expr_reloc_check($3);
  2920. sprintf(tempbuf, "%d", $3->e_value);
  2921. est2[parm_number++].param = strdup(tempbuf);
  2922. expr_free($3);
  2923. }
  2924. ;
  2925. allreg:
  2926. reg
  2927. |
  2928. ixylhreg
  2929. ;
  2930. reg:
  2931. realreg
  2932. |
  2933. mem
  2934. ;
  2935. ixylhreg:
  2936. IXYLH
  2937. {
  2938. $$ = $1->i_value;
  2939. }
  2940. ;
  2941. reg8:
  2942. realreg
  2943. |
  2944. m
  2945. ;
  2946. m:
  2947. COND { if ($1->i_value != 070) err[gflag]++; $$ = 6; }
  2948. ;
  2949. realreg:
  2950. REGNAME
  2951. {
  2952. $$ = $1->i_value;
  2953. }
  2954. |
  2955. ACC
  2956. {
  2957. $$ = $1->i_value;
  2958. }
  2959. |
  2960. C
  2961. {
  2962. $$ = $1->i_value;
  2963. }
  2964. ;
  2965. mem:
  2966. '(' HL ')'
  2967. {
  2968. $$ = 6;
  2969. }
  2970. |
  2971. memxy
  2972. ;
  2973. memxy:
  2974. '(' INDEX dxy ')'
  2975. {
  2976. $$ = ($2->i_value & 0177400) | 6;
  2977. }
  2978. |
  2979. '(' INDEX ')'
  2980. {
  2981. disp = 0;
  2982. $$ = ($2->i_value & 0177400) | 6;
  2983. }
  2984. |
  2985. dxy '(' INDEX ')'
  2986. {
  2987. $$ = ($3->i_value & 0177400) | 6;
  2988. }
  2989. ;
  2990. dxy: expression
  2991. {
  2992. expr_number_check($1);
  2993. disp = $1->e_value;
  2994. expr_free($1);
  2995. if (disp > 127 || disp < -128)
  2996. err[vflag]++;
  2997. }
  2998. ;
  2999. evenreg:
  3000. bcdesp
  3001. |
  3002. mar
  3003. ;
  3004. evenreg8:
  3005. realreg { if ($1 & 1) err[gflag]++; $$ = $1 << 3; }
  3006. |
  3007. SP { $$ = $1->i_value; }
  3008. ;
  3009. pushable:
  3010. RP
  3011. {
  3012. $$ = $1->i_value;
  3013. }
  3014. |
  3015. AF
  3016. {
  3017. $$ = $1->i_value;
  3018. }
  3019. |
  3020. mar
  3021. ;
  3022. pushable8:
  3023. realreg { if ($1 & 1) err[gflag]++; $$ = $1 << 3; }
  3024. |
  3025. PSW { $$ = $1->i_value; }
  3026. ;
  3027. bcdesp:
  3028. RP
  3029. {
  3030. $$ = $1->i_value;
  3031. }
  3032. |
  3033. SP
  3034. {
  3035. $$ = $1->i_value;
  3036. }
  3037. ;
  3038. bcdehlsp:
  3039. bcdesp
  3040. |
  3041. HL
  3042. {
  3043. $$ = $1->i_value;
  3044. }
  3045. ;
  3046. mar:
  3047. HL
  3048. {
  3049. $$ = $1->i_value;
  3050. }
  3051. |
  3052. INDEX
  3053. {
  3054. $$ = $1->i_value;
  3055. }
  3056. ;
  3057. condition:
  3058. spcondition
  3059. |
  3060. COND
  3061. {
  3062. $$ = $1->i_value;
  3063. }
  3064. ;
  3065. spcondition:
  3066. SPCOND
  3067. {
  3068. $$ = $1->i_value;
  3069. }
  3070. |
  3071. C
  3072. { $$ = 030; }
  3073. ;
  3074. db.list:
  3075. db.list.element
  3076. |
  3077. db.list ',' db.list.element
  3078. ;
  3079. db.list.element:
  3080. TWOCHAR
  3081. {
  3082. emit(1, E_DATA, expr_num($1));
  3083. emit(1, E_DATA, expr_num($1>>8));
  3084. }
  3085. |
  3086. STRING
  3087. {
  3088. cp = $1;
  3089. while (*cp != '\0')
  3090. emit(1,E_DATA,expr_num(*cp++));
  3091. }
  3092. |
  3093. expression
  3094. {
  3095. if (is_number($1) && ($1->e_value < -128 || $1->e_value > 255))
  3096. err[vflag]++;
  3097. emit(1, E_DATA, $1);
  3098. }
  3099. ;
  3100. dw.list:
  3101. dw.list.element
  3102. |
  3103. dw.list ',' dw.list.element
  3104. ;
  3105. dw.list.element:
  3106. expression
  3107. {
  3108. if ($1->e_value < -32768 || $1->e_value > 65535) {
  3109. err[vflag]++;
  3110. }
  3111. emit(2, E_DATA, $1);
  3112. }
  3113. ;
  3114. dd.list:
  3115. dd.list.element
  3116. |
  3117. dd.list ',' dd.list.element
  3118. ;
  3119. dd.list.element:
  3120. expression
  3121. {
  3122. // Can't check overflow as I only have 32 bit ints.
  3123. emit(4, E_DATA, $1);
  3124. }
  3125. ;
  3126. lxexpression:
  3127. noparenexpr
  3128. |
  3129. TWOCHAR
  3130. {
  3131. $$ = expr_num($1);
  3132. }
  3133. ;
  3134. expression:
  3135. parenexpr
  3136. |
  3137. noparenexpr
  3138. ;
  3139. parenexpr:
  3140. '(' expression ')'
  3141. { $$ = $2; }
  3142. ;
  3143. noparenexpr:
  3144. /*
  3145. This rule commented out because it doesn't actually produce expression
  3146. errors but instead stops parsing. That's because it doesn't clear the
  3147. parse error with yyerrok. I tried to add that but couldn't come up with
  3148. a recovery that works in all cases. In fact, it often infinite loops.
  3149. error
  3150. {
  3151. err[eflag]++;
  3152. $$ = expr_num(0);
  3153. }
  3154. |
  3155. */
  3156. LABEL
  3157. {
  3158. $$ = expr_alloc();
  3159. $$->e_token = 'v';
  3160. $$->e_item = $1;
  3161. $$->e_scope = $1->i_scope;
  3162. $$->e_value = $1->i_value;
  3163. $1->i_uses++;
  3164. }
  3165. |
  3166. NUMBER
  3167. {
  3168. $$ = expr_num($1);
  3169. }
  3170. |
  3171. ONECHAR
  3172. {
  3173. $$ = expr_num($1);
  3174. }
  3175. |
  3176. EQUATED
  3177. {
  3178. $$ = expr_alloc();
  3179. $$->e_token = 'v';
  3180. $$->e_item = $1; // not necessary
  3181. $$->e_scope = $1->i_scope;
  3182. $$->e_value = $1->i_value;
  3183. }
  3184. |
  3185. WASEQUATED
  3186. {
  3187. $$ = expr_alloc();
  3188. $$->e_token = 'v';
  3189. $$->e_item = $1; // not necessary
  3190. $$->e_scope = $1->i_scope;
  3191. $$->e_value = $1->i_value;
  3192. }
  3193. |
  3194. DEFLED
  3195. {
  3196. $$ = expr_alloc();
  3197. $$->e_token = 'v';
  3198. $$->e_item = $1; // not necessary
  3199. $$->e_scope = $1->i_scope;
  3200. $$->e_value = $1->i_value;
  3201. }
  3202. |
  3203. '$'
  3204. {
  3205. $$ = expr_num(dollarsign + emitptr - emitbuf);
  3206. $$->e_scope = segment;
  3207. }
  3208. |
  3209. UNDECLARED
  3210. {
  3211. $$ = expr_alloc();
  3212. $$->e_token = 'u';
  3213. $$->e_item = $1;
  3214. $$->e_scope = $1->i_scope;
  3215. $$->e_value = 0;
  3216. if (!($1->i_scope & SCOPE_EXTERNAL)) {
  3217. sprintf(detail, "'%s' %s", $1->i_string, errname[uflag]);
  3218. // Would be nice to add to list of undeclared errors
  3219. errwarn(uflag, detail);
  3220. }
  3221. }
  3222. |
  3223. MULTDEF
  3224. {
  3225. $$ = expr_alloc();
  3226. $$->e_token = 'm';
  3227. $$->e_item = $1;
  3228. $$->e_scope = $1->i_scope;
  3229. // Use the current value. Harmless enough as this
  3230. // will normally error out yet vital to allow
  3231. // "var set var+1" to function.
  3232. $$->e_value = $1->i_value;
  3233. }
  3234. |
  3235. NUL { raw = 2; } RAWTOKEN
  3236. {
  3237. $$ = expr_num(tempbuf[0] ? -1 : 0);
  3238. }
  3239. |
  3240. expression '+' expression
  3241. {
  3242. $$ = expr_op($1, '+', $3, $1->e_value + $3->e_value);
  3243. // Can't operate on external labels.
  3244. // But we can add constants to any scope.
  3245. if (!(($1->e_scope | $3->e_scope) & SCOPE_EXTERNAL) &&
  3246. (($1->e_scope & SCOPE_SEGMASK) == 0 ||
  3247. ($3->e_scope & SCOPE_SEGMASK) == 0))
  3248. {
  3249. $$->e_scope &= ~(SCOPE_NORELOC | SCOPE_SEGMASK);
  3250. $$->e_scope |= ($1->e_scope | $3->e_scope) & SCOPE_SEGMASK;
  3251. }
  3252. }
  3253. |
  3254. expression '-' expression
  3255. {
  3256. $$ = expr_op_sc($1, '-', $3, $1->e_value - $3->e_value);
  3257. // But we can subtract a constant.
  3258. if (!(($1->e_scope | $3->e_scope) & SCOPE_EXTERNAL) &&
  3259. (($3->e_scope & SCOPE_SEGMASK) == 0))
  3260. {
  3261. $$->e_scope &= ~(SCOPE_NORELOC | SCOPE_SEGMASK);
  3262. $$->e_scope |= ($1->e_scope & SCOPE_SEGMASK);
  3263. }
  3264. }
  3265. |
  3266. expression '/' expression
  3267. {
  3268. int val = 0;
  3269. if ($3->e_value == 0)
  3270. err[eflag]++;
  3271. else
  3272. val = $1->e_value / $3->e_value;
  3273. $$ = expr_op($1, '/', $3, val);
  3274. }
  3275. |
  3276. expression '*' expression
  3277. { $$ = expr_op($1, '*', $3, $1->e_value * $3->e_value); }
  3278. |
  3279. expression '%' expression
  3280. {
  3281. int val;
  3282. domod:
  3283. val = 0;
  3284. if ($3->e_value == 0)
  3285. err[eflag]++;
  3286. else
  3287. val = $1->e_value % $3->e_value;
  3288. $$ = expr_op($1, '%', $3, val);
  3289. }
  3290. |
  3291. expression MOD expression
  3292. { goto domod; }
  3293. |
  3294. expression '&' expression
  3295. { $$ = expr_op($1, '&', $3, $1->e_value & $3->e_value); }
  3296. |
  3297. expression AND expression
  3298. { $$ = expr_op($1, '&', $3, $1->e_value & $3->e_value); }
  3299. |
  3300. expression '|' expression
  3301. { $$ = expr_op($1, '|', $3, $1->e_value | $3->e_value); }
  3302. |
  3303. expression OR expression
  3304. { $$ = expr_op($1, '|', $3, $1->e_value | $3->e_value); }
  3305. |
  3306. expression '^' expression
  3307. { $$ = expr_op($1, '^', $3, $1->e_value ^ $3->e_value); }
  3308. |
  3309. expression XOR expression
  3310. { $$ = expr_op($1, '^', $3, $1->e_value ^ $3->e_value); }
  3311. |
  3312. expression SHL expression
  3313. { $$ = expr_op($1, $2, $3, $1->e_value << $3->e_value); }
  3314. |
  3315. expression SHR expression
  3316. {
  3317. int val = $3->e_value == 0 ? $1->e_value : (($1->e_value >> 1) & ((0x7fff << 16) | 0xffff)) >> ($3->e_value - 1);
  3318. $$ = expr_op($1, $2, $3, val);
  3319. }
  3320. |
  3321. expression '<' expression
  3322. { $$ = expr_op_sc($1, '<', $3, $1->e_value < $3->e_value); }
  3323. |
  3324. expression '=' expression
  3325. { $$ = expr_op_sc($1, '=', $3, $1->e_value == $3->e_value); }
  3326. |
  3327. expression '>' expression
  3328. { $$ = expr_op_sc($1, '>', $3, $1->e_value > $3->e_value); }
  3329. |
  3330. expression LT expression
  3331. { $$ = expr_op_sc($1, $2, $3, $1->e_value < $3->e_value); }
  3332. |
  3333. expression GT expression
  3334. { $$ = expr_op_sc($1, $2, $3, $1->e_value > $3->e_value); }
  3335. |
  3336. expression LE expression
  3337. { $$ = expr_op_sc($1, $2, $3, $1->e_value <= $3->e_value); }
  3338. |
  3339. expression GE expression
  3340. { $$ = expr_op_sc($1, $2, $3, $1->e_value >= $3->e_value); }
  3341. |
  3342. expression NE expression
  3343. { $$ = expr_op_sc($1, $2, $3, $1->e_value != $3->e_value); }
  3344. |
  3345. expression ANDAND expression
  3346. { $$ = expr_op($1, $2, $3, $1->e_value && $3->e_value); }
  3347. |
  3348. expression OROR expression
  3349. { $$ = expr_op($1, $2, $3, $1->e_value || $3->e_value); }
  3350. |
  3351. expression '?' expression ':' expression
  3352. {
  3353. expr_number_check($1);
  3354. if ($1->e_value) {
  3355. $$ = $3;
  3356. expr_free($5);
  3357. }
  3358. else {
  3359. $$ = $5;
  3360. expr_free($3);
  3361. }
  3362. expr_free($1);
  3363. }
  3364. |
  3365. '[' expression ']'
  3366. { $$ = $2; }
  3367. |
  3368. NOT expression
  3369. { $$ = expr_op($2, '~', 0, ~$2->e_value); }
  3370. |
  3371. '~' expression
  3372. { $$ = expr_op($2, '~', 0, ~$2->e_value); }
  3373. |
  3374. '!' expression
  3375. { $$ = expr_op($2, '!', 0, !$2->e_value); }
  3376. |
  3377. '+' expression %prec UNARY
  3378. { $$ = $2; /* no effect */ }
  3379. |
  3380. '-' expression %prec UNARY
  3381. { $$ = expr_op($2, '-', 0, -$2->e_value); }
  3382. |
  3383. T expression %prec UNARY
  3384. {
  3385. expr_reloc_check($2);
  3386. $$ = expr_num(tstatesum[phaseaddr($2->e_value)]);
  3387. expr_free($2);
  3388. }
  3389. |
  3390. TILO expression %prec UNARY
  3391. {
  3392. int low, low8080, fetch;
  3393. expr_reloc_check($2);
  3394. zi_tstates(memory + phaseaddr($2->e_value), &low, 0, &fetch, &low8080, 0);
  3395. $$ = expr_num(z80 ? low : low8080);
  3396. expr_free($2);
  3397. }
  3398. |
  3399. TIHI expression %prec UNARY
  3400. {
  3401. int high, high8080, fetch;
  3402. expr_reloc_check($2);
  3403. zi_tstates(memory + phaseaddr($2->e_value), 0, &high, &fetch, 0, &high8080);
  3404. $$ = expr_num(z80 ? high : high8080);
  3405. expr_free($2);
  3406. }
  3407. |
  3408. OCF expression %prec UNARY
  3409. {
  3410. expr_reloc_check($2);
  3411. $$ = expr_num(ocfsum[phaseaddr($2->e_value)]);
  3412. expr_free($2);
  3413. }
  3414. |
  3415. LOW expression %prec UNARY
  3416. {
  3417. $$ = expr_op($2, $1, 0, $2->e_value & 0xff);
  3418. }
  3419. |
  3420. HIGH expression %prec UNARY
  3421. {
  3422. $$ = expr_op($2, $1, 0, ($2->e_value >> 8) & 0xff);
  3423. }
  3424. ;
  3425. symbol:
  3426. UNDECLARED
  3427. |
  3428. LABEL
  3429. |
  3430. MULTDEF
  3431. |
  3432. EQUATED
  3433. |
  3434. WASEQUATED
  3435. |
  3436. DEFLED
  3437. ;
  3438. al:
  3439. { int i;
  3440. if (expptr >= MAXEXP)
  3441. error("Macro expansion level too deep");
  3442. est2 = (union exprec *) malloc((PARMMAX + PAREXT) * sizeof *est2);
  3443. expstack[expptr] = est2;
  3444. for (i=0; i<PARMMAX; i++)
  3445. est2[i].param = 0;
  3446. arg_start();
  3447. }
  3448. ;
  3449. arg_on:
  3450. { arg_start(); }
  3451. ;
  3452. arg_off:
  3453. { arg_reset(); }
  3454. ;
  3455. %%
  3456. /*extern int yylval;*/
  3457. #define F_END 0
  3458. #define OTHER 1
  3459. #define SPACE 2
  3460. #define DIGIT 3
  3461. #define LETTER 4
  3462. #define STARTER 5
  3463. #define DOLLAR 6
  3464. /*
  3465. * This is the table of character classes. It is used by the lexical
  3466. * analyser. (yylex())
  3467. */
  3468. char charclass[] = {
  3469. F_END, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
  3470. OTHER, SPACE, OTHER, OTHER, OTHER, SPACE, OTHER, OTHER,
  3471. OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
  3472. OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
  3473. SPACE, OTHER, OTHER, OTHER, DOLLAR, OTHER, OTHER, OTHER, // !"#$%&'
  3474. OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, STARTER,OTHER, // ()*+,-./
  3475. DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, // 01234567
  3476. DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, STARTER,// 89:;<=>?
  3477. STARTER,LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, // @ABCDEFG
  3478. LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, // HIJKLMNO
  3479. LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, // PQRSTUVW
  3480. LETTER, LETTER, LETTER, OTHER, OTHER, OTHER, OTHER, LETTER, // XYZ[\]^_
  3481. OTHER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, // `abcdefg
  3482. LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, // hijklmno
  3483. LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, // pqrstuvw
  3484. LETTER, LETTER, LETTER, OTHER, OTHER, OTHER, OTHER, OTHER, // xyz{|}~
  3485. };
  3486. /*
  3487. * the following table tells which characters are parts of numbers.
  3488. * The entry is non-zero for characters which can be parts of numbers.
  3489. */
  3490. char numpart[] = {
  3491. 0, 0, 0, 0, 0, 0, 0, 0,
  3492. 0, 0, 0, 0, 0, 0, 0, 0,
  3493. 0, 0, 0, 0, 0, 0, 0, 0,
  3494. 0, 0, 0, 0, 0, 0, 0, 0,
  3495. 0, 0, 0, 0, 0, 0, 0, 0,
  3496. 0, 0, 0, 0, 0, 0, 0, 0,
  3497. '0', '1', '2', '3', '4', '5', '6', '7',
  3498. '8', '9', 0, 0, 0, 0, 0, 0,
  3499. 0, 'A', 'B', 'C', 'D', 'E', 'F', 0,
  3500. 'H', 0, 0, 0, 0, 0, 0, 'O',
  3501. 0, 'Q', 0, 0, 0, 0, 0, 0,
  3502. 0, 0, 0, 0, 0, 0, 0, 0,
  3503. 0, 'a', 'b', 'c', 'd', 'e', 'f', 0,
  3504. 'h', 0, 0, 0, 0, 0, 0, 'o',
  3505. 0, 'q', 0, 0, 0, 0, 0, 0,
  3506. 'x', 0, 0, 0, 0, 0, 0, 0,
  3507. 0};
  3508. /*
  3509. * the following table is a list of assembler mnemonics;
  3510. * for each mnemonic the associated machine-code bit pattern
  3511. * and symbol type are given.
  3512. *
  3513. * The i_uses field is overloaded to indicate the possible uses for
  3514. * a token.
  3515. */
  3516. #define VERB (1) /* opcode or psuedo-op */
  3517. #define I8080 (2) /* used in 8080 instructions */
  3518. #define Z80 (4) /* used in Z80 instructions */
  3519. #define UNDOC (8) /* used only in undocumented instructions */
  3520. #define TERM (16) /* can appear in expressions (not all marked) */
  3521. #define ZNONSTD (32) /* non-standard Z-80 mnemonic (probably TDL or DRI) */
  3522. #define COL0 (64) /* will always be recognized in logical column 0 */
  3523. struct item keytab[] = {
  3524. {"*mod", 0, MRAS_MOD, VERB },
  3525. {".8080", 0, INSTSET, VERB },
  3526. {"a", 7, ACC, I8080 | Z80 },
  3527. {"aci", 0316, ALUI8, VERB | I8080 },
  3528. {"adc", 1, ARITHC, VERB | I8080 | Z80 },
  3529. {"adcx", 0xdd8e, ALU_XY, VERB | Z80 | ZNONSTD },
  3530. {"adcy", 0xfd8e, ALU_XY, VERB | Z80 | ZNONSTD },
  3531. {"add", 0, ADD, VERB | I8080 | Z80 },
  3532. {"addx", 0xdd86, ALU_XY, VERB | Z80 | ZNONSTD },
  3533. {"addy", 0xfd86, ALU_XY, VERB | Z80 | ZNONSTD },
  3534. {"adi", 0306, ALUI8, VERB | I8080 },
  3535. {"af", 060, AF, Z80 },
  3536. {"ana", 4, ARITHC, VERB | I8080},
  3537. {"and", 4, AND, VERB | Z80 | TERM },
  3538. {"andx", 0xdda6, ALU_XY, VERB | Z80 | ZNONSTD },
  3539. {"andy", 0xfda6, ALU_XY, VERB | Z80 | ZNONSTD },
  3540. {"ani", 0346, ALUI8, VERB | I8080 },
  3541. {".ascii", 0, DEFB, VERB },
  3542. {".aseg", SEG_ABS,SETSEG, VERB },
  3543. {".aset", 0, DEFL, VERB },
  3544. {".assert", 0, ASSERT, VERB },
  3545. {"b", 0, REGNAME, I8080 | Z80 },
  3546. {"bc", 0, RP, Z80 },
  3547. {"bit", 0145500,BIT, VERB | Z80 },
  3548. {"bitx", 0xdd46, BIT_XY, VERB | Z80 | ZNONSTD },
  3549. {"bity", 0xfd46, BIT_XY, VERB | Z80 | ZNONSTD },
  3550. {".block", 0, DEFS, VERB },
  3551. {".byte", 0, DEFB, VERB },
  3552. {"c", 1, C, I8080 | Z80 },
  3553. {"call", 0315, CALL, VERB | I8080 | Z80 },
  3554. {"cc", 0334, CALL8, VERB | I8080 },
  3555. {"ccd", 0xeda9, NOOPERAND, VERB | Z80 | ZNONSTD },
  3556. {"ccdr", 0xedb9, NOOPERAND, VERB | Z80 | ZNONSTD },
  3557. {"ccf", 077, NOOPERAND, VERB | Z80 },
  3558. {"cci", 0xeda1, NOOPERAND, VERB | Z80 | ZNONSTD },
  3559. {"ccir", 0xedb1, NOOPERAND, VERB | Z80 | ZNONSTD },
  3560. {"cm", 0374, CALL8, VERB | I8080 },
  3561. {"cma", 057, NOOPERAND, VERB | I8080 },
  3562. {"cmc", 077, NOOPERAND, VERB | I8080 },
  3563. {"cmp", 7, LOGICAL, VERB | I8080 },
  3564. {"cmpx", 0xddbe, ALU_XY, VERB | Z80 | ZNONSTD },
  3565. {"cmpy", 0xfdbe, ALU_XY, VERB | Z80 | ZNONSTD },
  3566. {"cnc", 0324, CALL8, VERB | I8080 },
  3567. {"cnz", 0304, CALL8, VERB | I8080 },
  3568. {".comment", SPCOM, SPECIAL, VERB },
  3569. {".cond", 0, IF_TK, VERB },
  3570. {"cp", 7, LOGICAL, VERB | I8080 | Z80 },
  3571. {"cpd", 0166651,NOOPERAND, VERB | Z80 },
  3572. {"cpdr", 0166671,NOOPERAND, VERB | Z80 },
  3573. {"cpe", 0354, CALL8, VERB | I8080 },
  3574. {"cpi", 0166641,NOOPERAND, VERB | I8080 | Z80 },
  3575. {"cpir", 0166661,NOOPERAND, VERB | Z80 },
  3576. {"cpl", 057, NOOPERAND, VERB | Z80 },
  3577. {"cpo", 0344, CALL8, VERB | I8080 },
  3578. {".cseg", SEG_CODE,SETSEG, VERB },
  3579. {"cz", 0314, CALL8, VERB | I8080 },
  3580. {"d", 2, REGNAME, I8080 | Z80 },
  3581. {"daa", 0047, NOOPERAND, VERB | I8080 | Z80 },
  3582. {"dad", 0, DAD, VERB | I8080 },
  3583. {"dadc", 0xed4a, ARITH16, VERB | Z80 | ZNONSTD },
  3584. {"dadx", 0xdd09, ARITH16, VERB | Z80 | ZNONSTD },
  3585. {"dady", 0xfd09, ARITH16, VERB | Z80 | ZNONSTD },
  3586. {".db", 0, DEFB, VERB },
  3587. {".dc", 0, DC, VERB },
  3588. {"dcr", 1, INRDCR, VERB | I8080 },
  3589. {"dcrx", 0xdd35, ALU_XY, VERB | Z80 | ZNONSTD },
  3590. {"dcry", 0xfd35, ALU_XY, VERB | Z80 | ZNONSTD },
  3591. {"dcx", 1, INXDCX, VERB | I8080 },
  3592. {"dcxix", 0xdd2b, NOOPERAND, VERB | Z80 | ZNONSTD },
  3593. {"dcxiy", 0xfd2b, NOOPERAND, VERB | Z80 | ZNONSTD },
  3594. {"de", 020, RP, Z80 },
  3595. {"dec", 1, INCDEC, VERB | I8080 | Z80 },
  3596. {".defb", 0, DEFB, VERB },
  3597. {".defd", 0, DEFD, VERB },
  3598. {".defl", 0, DEFL, VERB },
  3599. {".defm", 0, DEFB, VERB },
  3600. {".defs", 0, DEFS, VERB },
  3601. {".defw", 0, DEFW, VERB },
  3602. {".dephase", 0, DEPHASE, VERB },
  3603. {"di", 0363, NOOPERAND, VERB | I8080 | Z80 },
  3604. {"djnz", 020, DJNZ, VERB | Z80 },
  3605. {".ds", 0, DEFS, VERB },
  3606. {"dsbc", 0xed42, ARITH16, VERB | Z80 | ZNONSTD },
  3607. {".dseg", SEG_DATA,SETSEG, VERB },
  3608. {".dw", 0, DEFW, VERB },
  3609. {".dword", 0, DEFD, VERB },
  3610. {"e", 3, REGNAME, I8080 | Z80 },
  3611. {"ei", 0373, NOOPERAND, VERB | I8080 | Z80 },
  3612. {".eject", 1, LIST, VERB },
  3613. {".elist", 3, LIST, VERB },
  3614. {".else", 0, ELSE_TK, VERB },
  3615. {".end", 0, END, VERB },
  3616. {".endc", 0, ENDIF_TK, VERB },
  3617. {".endif", 0, ENDIF_TK, VERB },
  3618. {".endm", 0, ENDM, VERB },
  3619. {".entry", 0, PUBLIC, VERB },
  3620. {"eq", 0, '=', 0 },
  3621. {".equ", 0, EQU, VERB },
  3622. {"ex", 0, EX, VERB | Z80 },
  3623. {"exaf", 0x08, NOOPERAND, VERB | Z80 | ZNONSTD },
  3624. {".exitm", 0, EXITM, VERB },
  3625. {".ext", 0, EXTRN, VERB },
  3626. {".extern", 0, EXTRN, VERB },
  3627. {".extrn", 0, EXTRN, VERB },
  3628. {"exx", 0331, NOOPERAND, VERB | Z80 },
  3629. {".flist", 4, LIST, VERB },
  3630. {"ge", 0, GE, 0 },
  3631. {".glist", 5, LIST, VERB },
  3632. {".global", 0, PUBLIC, VERB },
  3633. {"gt", 0, GT, 0 },
  3634. {"h", 4, REGNAME, I8080 | Z80 },
  3635. {"halt", 0166, NOOPERAND, VERB | Z80 },
  3636. {"high", 0, HIGH, 0 },
  3637. {"hl", 040, HL, Z80 },
  3638. {"hlt", 0166, NOOPERAND, VERB | I8080 },
  3639. {"i", 0, MISCREG, Z80 },
  3640. {".if", 0, IF_TK, VERB | COL0 },
  3641. {"im", 0166506,IM, VERB | Z80 },
  3642. {"im0", 0xed46, NOOPERAND, VERB | Z80 | ZNONSTD },
  3643. {"im1", 0xed56, NOOPERAND, VERB | Z80 | ZNONSTD },
  3644. {"im2", 0xed5e, NOOPERAND, VERB | Z80 | ZNONSTD },
  3645. {"in", 0333, TK_IN, VERB | I8080 | Z80 },
  3646. {"inc", 0, INCDEC, VERB | Z80 },
  3647. {".incbin", 0, INCBIN, VERB },
  3648. {".include", PSINC, ARGPSEUDO, VERB },
  3649. {"ind", 0166652,NOOPERAND, VERB | Z80 },
  3650. {"indr", 0166672,NOOPERAND, VERB | Z80 },
  3651. {"ini", 0166642,NOOPERAND, VERB | Z80 },
  3652. {"inir", 0166662,NOOPERAND, VERB | Z80 },
  3653. {"inp", 0, INP, VERB | Z80 | ZNONSTD },
  3654. {"inr", 0, INRDCR, VERB | I8080 },
  3655. {"inrx", 0xdd34, ALU_XY, VERB | Z80 | ZNONSTD },
  3656. {"inry", 0xfd34, ALU_XY, VERB | Z80 | ZNONSTD },
  3657. {"inx", 0, INXDCX, VERB | I8080 },
  3658. {"inxix", 0xdd23, NOOPERAND, VERB | Z80 | ZNONSTD },
  3659. {"inxiy", 0xfd23, NOOPERAND, VERB | Z80 | ZNONSTD },
  3660. {"irp", 0, IRP, VERB },
  3661. {"irpc", 0, IRPC, VERB },
  3662. {"ix", 0156440,INDEX, Z80 },
  3663. {"ixh", 0x1DD04,IXYLH, Z80 | UNDOC },
  3664. {"ixl", 0x1DD05,IXYLH, Z80 | UNDOC },
  3665. {"iy", 0176440,INDEX, Z80 },
  3666. {"iyh", 0x1FD04,IXYLH, Z80 | UNDOC },
  3667. {"iyl", 0x1FD05,IXYLH, Z80 | UNDOC },
  3668. {"jc", 0332, JUMP8, VERB | I8080 },
  3669. {"jm", 0372, JUMP8, VERB | I8080 },
  3670. {"jmp", 0303, JP, VERB | I8080 },
  3671. {"jnc", 0322, JUMP8, VERB | I8080 },
  3672. {"jnz", 0302, JUMP8, VERB | I8080 },
  3673. {"jp", 0, JP, VERB | I8080 | Z80 },
  3674. {"jpe", 0352, JUMP8, VERB | I8080 },
  3675. {".jperror", 0, JPERROR, VERB },
  3676. {"jpo", 0342, JUMP8, VERB | I8080 },
  3677. {"jr", 040, JR, VERB | Z80 },
  3678. {"jrc", 0x38, JR_COND, VERB | Z80 | ZNONSTD },
  3679. {"jrnc", 0x30, JR_COND, VERB | Z80 | ZNONSTD },
  3680. {"jrnz", 0x20, JR_COND, VERB | Z80 | ZNONSTD },
  3681. {".jrpromote", 0, JRPROMOTE, VERB },
  3682. {"jrz", 0x28, JR_COND, VERB | Z80 | ZNONSTD },
  3683. {"jz", 0312, JUMP8, VERB | I8080 },
  3684. {"l", 5, REGNAME, I8080 | Z80 },
  3685. {"lbcd", 0xed4b, LDST16, VERB | Z80 | ZNONSTD },
  3686. {"ld", 0, LD, VERB | Z80 },
  3687. {"lda", 0, LDA, VERB | I8080 },
  3688. {"ldai", 0xed57, NOOPERAND, VERB | Z80 | ZNONSTD },
  3689. {"ldar", 0xed5f, NOOPERAND, VERB | Z80 | ZNONSTD },
  3690. {"ldax", 0, LDAX, VERB | I8080 },
  3691. {"ldd", 0166650,NOOPERAND, VERB | Z80 },
  3692. {"lddr", 0166670,NOOPERAND, VERB | Z80 },
  3693. {"lded", 0xed5b, LDST16, VERB | Z80 | ZNONSTD },
  3694. {"ldi", 0166640,NOOPERAND, VERB | Z80 },
  3695. {"ldir", 0166660,NOOPERAND, VERB | Z80 },
  3696. {"ldx", 0xdd46, LD_XY, VERB | Z80 | ZNONSTD},
  3697. {"ldy", 0xfd46, LD_XY, VERB | Z80 | ZNONSTD},
  3698. {"le", 0, LE, 0 },
  3699. {"lhld", 0, LHLD, VERB | I8080 },
  3700. {".list", 0, LIST, VERB },
  3701. {"lixd", 0xdd2a, LDST16, VERB | Z80 | ZNONSTD },
  3702. {"liyd", 0xfd2a, LDST16, VERB | Z80 | ZNONSTD },
  3703. {".local", 0, LOCAL, VERB },
  3704. {"low", 0, LOW, 0 },
  3705. {"lspd", 0xed7b, LDST16, VERB | Z80 | ZNONSTD },
  3706. {"lt", 0, LT, 0 },
  3707. {"lxi", 0, LXI, VERB | I8080 },
  3708. {"lxix", 0xdd21, LDST16, VERB | Z80 | ZNONSTD },
  3709. {"lxiy", 0xfd21, LDST16, VERB | Z80 | ZNONSTD },
  3710. {"m", 070, COND, I8080 | Z80 },
  3711. {".maclib", PSMACLIB,ARGPSEUDO, VERB },
  3712. {".macro", 0, MACRO, VERB },
  3713. {".max", 1, MINMAX, VERB },
  3714. {".min", 0, MINMAX, VERB },
  3715. {".mlist", 6, LIST, VERB },
  3716. {"mod", 0, MOD, 0 },
  3717. {"mov", 0, MOV, VERB | I8080 },
  3718. {"mvi", 0, MVI, VERB | I8080 },
  3719. {"mvix", 0xdd36, MV_XY, VERB | Z80 | ZNONSTD },
  3720. {"mviy", 0xfd36, MV_XY, VERB | Z80 | ZNONSTD },
  3721. {".name", SPNAME, SPECIAL, VERB },
  3722. {"nc", 020, SPCOND, 0 },
  3723. {"ne", 0, NE, 0 },
  3724. {"neg", 0166504,NOOPERAND, VERB | Z80 },
  3725. {".nolist", -1, LIST, VERB },
  3726. {"nop", 0, NOOPERAND, VERB | I8080 | Z80 },
  3727. {"not", 0, NOT, 0 },
  3728. {"nul", 0, NUL, 0 },
  3729. {"nv", 040, COND, Z80 },
  3730. {"nz", 0, SPCOND, Z80 },
  3731. {"ocf", 0, OCF, 0 },
  3732. {"or", 6, OR, VERB | Z80 | TERM },
  3733. {"ora", 6, LOGICAL, VERB | I8080 },
  3734. {".org", 0, ORG, VERB },
  3735. {"ori", 0366, ALUI8, VERB | I8080 },
  3736. {"orx", 0xddb6, ALU_XY, VERB | Z80 | ZNONSTD },
  3737. {"ory", 0xfdb6, ALU_XY, VERB | Z80 | ZNONSTD },
  3738. {"otdr", 0166673,NOOPERAND, VERB | Z80 },
  3739. {"otir", 0166663,NOOPERAND, VERB | Z80 },
  3740. {"out", 0323, TK_OUT, VERB | I8080 | Z80 },
  3741. {"outd", 0166653,NOOPERAND, VERB | Z80 },
  3742. {"outdr", 0166673,NOOPERAND, VERB | Z80 | ZNONSTD },
  3743. {"outi", 0166643,NOOPERAND, VERB | Z80 },
  3744. {"outir", 0166663,NOOPERAND, VERB | Z80 | ZNONSTD },
  3745. {"outp", 0, OUTP, VERB | Z80 | ZNONSTD },
  3746. {"p", 060, COND, Z80 },
  3747. {".page", 1, LIST, VERB },
  3748. {"pchl", 0351, NOOPERAND, VERB | I8080 },
  3749. {"pcix", 0xdde9, NOOPERAND, VERB | Z80 | ZNONSTD },
  3750. {"pciy", 0xfde9, NOOPERAND, VERB | Z80 | ZNONSTD },
  3751. {"pe", 050, COND, Z80 },
  3752. {"pfix", 0xdd, NOOPERAND, VERB | Z80 | UNDOC },
  3753. {"pfiy", 0xfd, NOOPERAND, VERB | Z80 | UNDOC },
  3754. {".phase", 0, PHASE, VERB },
  3755. {"po", 040, COND, Z80 },
  3756. {"pop", 0301, PUSHPOP, VERB | I8080 | Z80 },
  3757. {"popix", 0xdde1, NOOPERAND, VERB | Z80 | ZNONSTD },
  3758. {"popiy", 0xfde1, NOOPERAND, VERB | Z80 | ZNONSTD },
  3759. {"pragma", SPPRAGMA,SPECIAL, VERB },
  3760. {"psw", 060, PSW, I8080 },
  3761. {".public", 0, PUBLIC, VERB },
  3762. {"push", 0305, PUSHPOP, VERB | I8080 | Z80 },
  3763. {"pushix", 0xdde5, NOOPERAND, VERB | Z80 | ZNONSTD },
  3764. {"pushiy", 0xfde5, NOOPERAND, VERB | Z80 | ZNONSTD },
  3765. {"r", 010, MISCREG, Z80 },
  3766. {"ral", 027, NOOPERAND, VERB | I8080 },
  3767. {"ralr", 2, SHIFT, VERB | Z80 | ZNONSTD },
  3768. {"ralx", 0xdd16, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3769. {"raly", 0xfd16, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3770. {"rar", 037, NOOPERAND, VERB | I8080 },
  3771. {"rarr", 3, SHIFT, VERB | Z80 | ZNONSTD },
  3772. {"rarx", 0xdd1e, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3773. {"rary", 0xfd1e, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3774. {"rc", 0330, NOOPERAND, VERB | I8080 },
  3775. {".read", PSINC, ARGPSEUDO, VERB },
  3776. {"rept", 0, REPT, VERB },
  3777. {"res", 0145600,BIT, VERB | Z80 },
  3778. {"resx", 0xdd86, BIT_XY, VERB | Z80 | ZNONSTD },
  3779. {"resy", 0xfd86, BIT_XY, VERB | Z80 | ZNONSTD },
  3780. {"ret", 0311, RET, VERB | I8080 | Z80 },
  3781. {"reti", 0166515,NOOPERAND, VERB | Z80 },
  3782. {"retn", 0166505,NOOPERAND, VERB | Z80 },
  3783. {"rl", 2, SHIFT, VERB | Z80 },
  3784. {"rla", 027, NOOPERAND, VERB | Z80 },
  3785. {"rlc", 0, SHIFT, VERB | I8080 | Z80 },
  3786. {"rlca", 07, NOOPERAND, VERB | Z80 },
  3787. {"rlcr", 0, SHIFT, VERB | I8080 | Z80 | ZNONSTD },
  3788. {"rlcx", 0xdd06, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3789. {"rlcy", 0xfd06, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3790. {"rld", 0166557,NOOPERAND, VERB | Z80 },
  3791. {"rm", 0370, NOOPERAND, VERB | I8080 },
  3792. {".rmem", 0, DEFS, VERB },
  3793. {"rnc", 0320, NOOPERAND, VERB | I8080 },
  3794. {"rnz", 0300, NOOPERAND, VERB | I8080 },
  3795. {"rp", 0360, NOOPERAND, VERB | I8080 },
  3796. {"rpe", 0350, NOOPERAND, VERB | I8080 },
  3797. {"rpo", 0340, NOOPERAND, VERB | I8080 },
  3798. {"rr", 3, SHIFT, VERB | Z80 },
  3799. {"rra", 037, NOOPERAND, VERB | Z80 },
  3800. {"rrc", 1, SHIFT, VERB | I8080 | Z80 },
  3801. {"rrca", 017, NOOPERAND, VERB | Z80 },
  3802. {"rrcr", 1, SHIFT, VERB | Z80 | ZNONSTD },
  3803. {"rrcx", 0xdd0e, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3804. {"rrcy", 0xfd0e, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3805. {"rrd", 0166547,NOOPERAND, VERB | Z80 },
  3806. {"rst", 0307, RST, VERB | I8080 | Z80 },
  3807. {".rsym", PSRSYM, ARGPSEUDO, VERB },
  3808. {"rz", 0310, NOOPERAND, VERB | I8080 },
  3809. {"sbb", 3, ARITHC, VERB | I8080 },
  3810. {"sbc", 3, ARITHC, VERB | Z80 },
  3811. {"sbcd", 0xed43, LDST16, VERB | Z80 | ZNONSTD },
  3812. {"sbcx", 0xdd9e, ALU_XY, VERB | Z80 | ZNONSTD },
  3813. {"sbcy", 0xfd9e, ALU_XY, VERB | Z80 | ZNONSTD },
  3814. {"sbi", 0336, ALUI8, VERB | I8080 },
  3815. {"scf", 067, NOOPERAND, VERB | Z80 },
  3816. {"sded", 0xed53, LDST16, VERB | Z80 | ZNONSTD },
  3817. {"set", 0145700,BIT, VERB | Z80 },
  3818. {"setb", 0145700,BIT, VERB | Z80 | ZNONSTD },
  3819. {".setocf", 0, SETOCF, VERB },
  3820. {".sett", 0, TSTATE, VERB },
  3821. {"setx", 0xddc6, BIT_XY, VERB | Z80 | ZNONSTD },
  3822. {"sety", 0xfdc6, BIT_XY, VERB | Z80 | ZNONSTD },
  3823. {"shl", 0, SHL, TERM },
  3824. {"shld", 0, SHLD, VERB | I8080 },
  3825. {"shr", 0, SHR, TERM },
  3826. {"sixd", 0xdd22, LDST16, VERB | Z80 | ZNONSTD },
  3827. {"siyd", 0xfd22, LDST16, VERB | Z80 | ZNONSTD },
  3828. {"sl1", 6, SHIFT, VERB | Z80 | UNDOC },
  3829. {"sla", 4, SHIFT, VERB | Z80 },
  3830. {"slar", 4, SHIFT, VERB | Z80 | ZNONSTD },
  3831. {"slax", 0xdd26, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3832. {"slay", 0xfd26, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3833. {"sll", 6, SHIFT, VERB | Z80 },
  3834. {"sp", 060, SP, I8080 | Z80 },
  3835. {".space", 2, LIST, VERB },
  3836. {"sphl", 0371, NOOPERAND, VERB | I8080 },
  3837. {"spix", 0xddf9, NOOPERAND, VERB | Z80 | ZNONSTD },
  3838. {"spiy", 0xfdf9, NOOPERAND, VERB | Z80 | ZNONSTD },
  3839. {"sra", 5, SHIFT, VERB | Z80 },
  3840. {"srar", 5, SHIFT, VERB | Z80 | ZNONSTD },
  3841. {"srax", 0xdd2e, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3842. {"sray", 0xfd2e, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3843. {"srl", 7, SHIFT, VERB | Z80 },
  3844. {"srlr", 7, SHIFT, VERB | Z80 | ZNONSTD },
  3845. {"srlx", 0xdd3e, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3846. {"srly", 0xfd3e, SHIFT_XY, VERB | Z80 | ZNONSTD },
  3847. {"sspd", 0xed73, LDST16, VERB | Z80 | ZNONSTD },
  3848. {"sta", 0, STA, VERB | I8080 },
  3849. {"stai", 0xed47, NOOPERAND, VERB | Z80 | ZNONSTD },
  3850. {"star", 0xed4f, NOOPERAND, VERB | Z80 | ZNONSTD },
  3851. {"stax", 0, STAX, VERB | I8080 },
  3852. {"stc", 067, NOOPERAND, VERB | I8080 },
  3853. {"stx", 0xdd70, ST_XY, VERB | Z80 | ZNONSTD},
  3854. {"sty", 0xfd70, ST_XY, VERB | Z80 | ZNONSTD},
  3855. {"sub", 2, LOGICAL, VERB | I8080 | Z80 },
  3856. {".subttl", SPSBTL, SPECIAL, VERB },
  3857. {"subx", 0xdd96, ALU_XY, VERB | Z80 | ZNONSTD },
  3858. {"suby", 0xfd96, ALU_XY, VERB | Z80 | ZNONSTD },
  3859. {"sui", 0326, ALUI8, VERB | I8080 },
  3860. {"t", 0, T, 0 },
  3861. {".text", 0, DEFB, VERB },
  3862. {"tihi", 0, TIHI, 0 },
  3863. {"tilo", 0, TILO, 0 },
  3864. {".title", SPTITL, SPECIAL, VERB },
  3865. {".tstate", 0, TSTATE, VERB },
  3866. {"v", 050, COND, Z80 },
  3867. {".word", 0, DEFW, VERB },
  3868. {".wsym", PSWSYM, ARGPSEUDO, VERB },
  3869. {"xchg", 0353, NOOPERAND, VERB | I8080 },
  3870. {"xor", 5, XOR, VERB | Z80 | TERM },
  3871. {"xorx", 0xddae, ALU_XY, VERB | Z80 | ZNONSTD },
  3872. {"xory", 0xfdae, ALU_XY, VERB | Z80 | ZNONSTD },
  3873. {"xra", 5, LOGICAL, VERB | I8080 },
  3874. {"xri", 0356, ALUI8, VERB | I8080 },
  3875. {"xthl", 0343, NOOPERAND, VERB | I8080 },
  3876. {"xtix", 0xdde3, NOOPERAND, VERB | Z80 | ZNONSTD },
  3877. {"xtiy", 0xfde3, NOOPERAND, VERB | Z80 | ZNONSTD },
  3878. {"z", 010, SPCOND, Z80 },
  3879. {".z80", 1, INSTSET, VERB },
  3880. };
  3881. /*
  3882. * user-defined items are tabulated in the following table.
  3883. */
  3884. struct item itemtab[ITEMTABLESIZE];
  3885. struct item *itemmax = itemtab+ITEMTABLESIZE;
  3886. /*
  3887. * lexical analyser, called by yyparse.
  3888. */
  3889. int yylex()
  3890. {
  3891. int c;
  3892. char *p;
  3893. int radix;
  3894. int sep;
  3895. char *d0, *dn;
  3896. int exclude, include, overflow;
  3897. if (arg_flag) {
  3898. yylval.cval = arg_state.arg;
  3899. c = getarg(&arg_state);
  3900. if (c == '\0' || c == '\n' || c == ';')
  3901. c = skipline(c);
  3902. return c;
  3903. }
  3904. if (raw == 2) {
  3905. while (charclass[c = nextchar()] == SPACE)
  3906. ;
  3907. *tempbuf = c == '\n' || c == '\0';
  3908. peekc = skipline(c);
  3909. raw = 0;
  3910. return RAWTOKEN;
  3911. }
  3912. else if (raw) {
  3913. int skip = 1;
  3914. p = tempbuf;
  3915. while ((c = nextchar()) != '\n' && c) {
  3916. if (p >= tempmax) {
  3917. *p = '\0';
  3918. printf("was parsing '%s'\n", tempbuf);
  3919. error(symlong);
  3920. }
  3921. if (!skip || charclass[c] != SPACE) {
  3922. *p++ = c;
  3923. skip = 0;
  3924. }
  3925. }
  3926. if (c == 0)
  3927. peekc = c;
  3928. *p-- = '\0';
  3929. while (p >= tempbuf && charclass[*p] == SPACE)
  3930. *p-- = '\0';
  3931. raw = 0;
  3932. return RAWTOKEN;
  3933. }
  3934. for (;;) switch(charclass[c = nextchar()]) {
  3935. case F_END:
  3936. if (!expptr)
  3937. return 0;
  3938. if (est[MSTR].param) {
  3939. int ch;
  3940. est[REPNUM].value++;
  3941. ch = est[MSTR].param[est[REPNUM].value];
  3942. if (ch) {
  3943. est[0].param[0] = ch;
  3944. floc = est[MSTART].value;
  3945. mfseek(mfile, (long)floc, 0);
  3946. est[TEMPNUM].value = exp_number++;
  3947. }
  3948. else {
  3949. free(est[MSTR].param);
  3950. est[MSTR].param = 0;
  3951. popsi();
  3952. }
  3953. }
  3954. else if (est[REPNUM].value < 0) {
  3955. int arg;
  3956. do {
  3957. switch (getarg(est[MARGP].ap)) {
  3958. case ARG:
  3959. arg = 1;
  3960. break;
  3961. case ',':
  3962. arg = 0;
  3963. break;
  3964. default:
  3965. arg = 2;
  3966. break;
  3967. }
  3968. } while (!arg);
  3969. if (arg == 1) {
  3970. floc = est[MSTART].value;
  3971. mfseek(mfile, (long)floc, 0);
  3972. est[TEMPNUM].value = exp_number++;
  3973. }
  3974. else {
  3975. // XXX - memory leak
  3976. est[0].param = NULL;
  3977. free(est[MARGP].ap);
  3978. popsi();
  3979. }
  3980. }
  3981. else if (est[REPNUM].value-- > 0) {
  3982. floc = est[MSTART].value;
  3983. mfseek(mfile, (long)floc, 0);
  3984. est[TEMPNUM].value = exp_number++;
  3985. }
  3986. else
  3987. popsi();
  3988. continue;
  3989. case SPACE:
  3990. while (charclass[c = nextchar()] == SPACE)
  3991. ;
  3992. peekc = c;
  3993. logcol++;
  3994. break;
  3995. case LETTER:
  3996. case STARTER:
  3997. case DIGIT:
  3998. case DOLLAR:
  3999. spectok:
  4000. firstcol = getcol() == 1;
  4001. radix = -1; // might be a number
  4002. p = tempbuf;
  4003. do {
  4004. if (p >= tempmax) {
  4005. *tempmax = '\0';
  4006. printf("was parsing '%s'\n", tempbuf);
  4007. error(symlong);
  4008. }
  4009. *p = (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
  4010. if (mras && *p == '?') {
  4011. char *q;
  4012. radix = 0; // can't be a number even if it looks like it
  4013. if (expptr)
  4014. q = getmraslocal();
  4015. else
  4016. for (q = modstr; *q == '@'; q++)
  4017. ;
  4018. if (*q) {
  4019. strcpy(p, q);
  4020. p = strchr(p, '\0') - 1;
  4021. }
  4022. else
  4023. *p = '?';
  4024. }
  4025. p++;
  4026. c = nextchar();
  4027. } while (charclass[c]==LETTER || charclass[c]==DIGIT ||
  4028. charclass[c]==STARTER || charclass[c]==DOLLAR);
  4029. *p = '\0';
  4030. // When parsing macro parameters we use a custom symbol table.
  4031. // And, heck, almost anything goes.
  4032. if (param_parse) {
  4033. struct item *param = item_lookup(tempbuf, paramtab, PARAMTABSIZE);
  4034. peekc = c;
  4035. if (param->i_token) {
  4036. sprintf(detail, "%s error. Macro parameter '%s' repeated",
  4037. errname[fflag], tempbuf);
  4038. errwarn(fflag, detail);
  4039. }
  4040. param->i_token = MPARM;
  4041. param->i_string = malloc(strlen(tempbuf) + 1);
  4042. strcpy(param->i_string, tempbuf);
  4043. yylval.itemptr = param;
  4044. return param->i_token;
  4045. }
  4046. // Special case for AF'
  4047. if (c == '\'' && strcmp(tempbuf, "af") == 0)
  4048. return AFp;
  4049. peekc = c;
  4050. // Pass off '?' (XXX but, technically, should only be done in expression context)
  4051. if (strcmp(tempbuf, "?") == 0)
  4052. return '?';
  4053. // Pass off '$'
  4054. if (strcmp(tempbuf, "$") == 0)
  4055. return '$';
  4056. // Look ahead at what we have.
  4057. while (charclass[c] == SPACE)
  4058. c = nextchar();
  4059. peekc = c;
  4060. //printf("%d %s\n", logcol, tempbuf);
  4061. // If logcol == 0 then if c == ':' we're a label for sure.
  4062. // If logcol == 1 if c == ':' we're a label, change logcol
  4063. // otherwise we're op or pseudo
  4064. // If logcol == 0 and c == '\n' or ';' then we're alone so
  4065. // we give tokenization a chance otherwise label
  4066. // If logcol >= 2 we're in the arguments
  4067. //
  4068. // There is quite a lot of unrealized scope for error
  4069. // detection and helpful warnings.
  4070. // Default to any tokenization.
  4071. exclude = 0;
  4072. include = 0;
  4073. if (logcol >= 2) {
  4074. // Arguments allow mnemonics and psuedo-ops
  4075. exclude = VERB;
  4076. include = TERM;
  4077. }
  4078. else if (logcol == 0 && c != ';' && c != '\n') {
  4079. exclude = ~TERM;
  4080. include = COL0;
  4081. }
  4082. else if (logcol == 1 && c == ':') {
  4083. exclude = ~TERM;
  4084. logcol = 0;
  4085. }
  4086. logcol++;
  4087. // Look for possible numbers.
  4088. // 0x<hex> $<hex> <hex>h <octal>o <octal>q <binary>b
  4089. // <decimal> <decimal>d
  4090. // Suffix formats must start with 0-9.
  4091. if (radix) {
  4092. if (tempbuf[0] == '0' && tempbuf[1] == 'x' && tempbuf[2]) {
  4093. radix = 16;
  4094. d0 = tempbuf + 2;
  4095. dn = p;
  4096. } else if (tempbuf[0] == '$') {
  4097. radix = 16;
  4098. d0 = tempbuf + 1;
  4099. dn = p;
  4100. }
  4101. else if (tempbuf[0] >= '0' && tempbuf[0] <= '9') {
  4102. d0 = tempbuf;
  4103. dn = p - 1;
  4104. switch (*dn) {
  4105. case 'o':
  4106. case 'q':
  4107. radix = 8;
  4108. break;
  4109. case 'd':
  4110. radix = 10;
  4111. break;
  4112. case 'h':
  4113. radix = 16;
  4114. break;
  4115. case 'b':
  4116. radix = 2;
  4117. break;
  4118. default:
  4119. radix = 10;
  4120. dn++;
  4121. }
  4122. }
  4123. }
  4124. // We may have a number on our hands.
  4125. if (radix > 0) {
  4126. overflow = 0;
  4127. yylval.ival = 0;
  4128. for (; d0 < dn; d0++) {
  4129. unsigned int ovchk = (unsigned int)yylval.ival;
  4130. c = *d0 - (*d0 > '9' ? ('a' - 10) : '0');
  4131. if (c < 0 || c >= radix) {
  4132. radix = 0;
  4133. break;
  4134. }
  4135. if (ovchk * radix / radix != ovchk)
  4136. overflow = 1;
  4137. yylval.ival *= radix;
  4138. yylval.ival += c;
  4139. }
  4140. }
  4141. // If we're in the first logical column and the token starts with
  4142. // '$' then we'll force it to be a label even though it could be
  4143. // a $hex constant. This will allow $FCB as a label.
  4144. // Thus we must also allow symbol lookup a chance to override number
  4145. // parsing if we start with a '$'.
  4146. if (tempbuf[0] == '$') {
  4147. if (logcol == 1 || locate(tempbuf)->i_token) {
  4148. if (radix > 0) {
  4149. sprintf(detail, "warning: $hex constant '%s' interpreted as symbol", tempbuf);
  4150. errwarn(warn_hex, detail);
  4151. }
  4152. radix = 0;
  4153. }
  4154. }
  4155. if (radix > 0) {
  4156. // Might be line skipping time, though.
  4157. if (*ifptr)
  4158. return skipline(c);
  4159. if (overflow) {
  4160. err[iflag]++;
  4161. yylval.ival = 0;
  4162. }
  4163. return NUMBER;
  4164. }
  4165. // Too late to do '$' concatenation of numbers. But zmac
  4166. // didn't allow for that previously at any rate.
  4167. if (zcompat) {
  4168. char *q = tempbuf;
  4169. // Normal zmac operation requires we ignore $ in identifiers
  4170. for (p = q; *p; p++)
  4171. if (*p != '$')
  4172. *q++ = *p;
  4173. *q = '\0';
  4174. p = q;
  4175. }
  4176. // GWP - boy, this should be a warning or error
  4177. if (p - tempbuf > MAXSYMBOLSIZE) {
  4178. p = tempbuf + MAXSYMBOLSIZE;
  4179. *p = '\0';
  4180. }
  4181. return tokenofitem(UNDECLARED, exclude, include);
  4182. default:
  4183. if (*ifptr)
  4184. return(skipline(c));
  4185. if (mras && getcol() == 1 && c == '*')
  4186. goto spectok;
  4187. switch(c) {
  4188. int corig;
  4189. case ':':
  4190. if (logcol == 1) {
  4191. // Make sure "label:ret", "label: ret",
  4192. // "label: :ret", "label: : ret" work out OK.
  4193. // But stop fooling around once we've done the VERB
  4194. peekc = nextchar();
  4195. if (charclass[peekc] == SPACE)
  4196. logcol--;
  4197. }
  4198. return c;
  4199. case ';':
  4200. return(skipline(c));
  4201. case '\'':
  4202. case '"':
  4203. sep = c;
  4204. p = tempbuf;
  4205. p[1] = 0;
  4206. do switch(c = nextchar()) {
  4207. case '\0':
  4208. case '\n':
  4209. err[bflag]++;
  4210. goto retstring;
  4211. default:
  4212. if (c == sep && (c = nextchar()) != sep) {
  4213. retstring:
  4214. peekc = c;
  4215. *p = '\0';
  4216. switch (p - tempbuf) {
  4217. case 2:
  4218. p = tempbuf;
  4219. yylval.ival = *p++ & 255;
  4220. yylval.ival |= (*p & 255) << 8;
  4221. return TWOCHAR;
  4222. case 1:
  4223. p = tempbuf;
  4224. yylval.ival = *p++;
  4225. return ONECHAR;
  4226. case 0:
  4227. if (!full_exprs) {
  4228. yylval.ival = 0;
  4229. return NUMBER;
  4230. }
  4231. // fall through
  4232. default:
  4233. yylval.cval = tempbuf;
  4234. return STRING;
  4235. }
  4236. }
  4237. *p++ = c;
  4238. } while (p < tempmax);
  4239. /*
  4240. * if we break out here, our string is longer than
  4241. * our input line
  4242. */
  4243. error("string buffer overflow");
  4244. case '<':
  4245. corig = c;
  4246. switch (c = nextchar ()) {
  4247. case '=':
  4248. return LE;
  4249. case '<':
  4250. return SHL;
  4251. case '>':
  4252. return NE;
  4253. default:
  4254. peekc = c;
  4255. return corig;
  4256. }
  4257. /* break; suppress "unreachable" warning for tcc */
  4258. case '>':
  4259. corig = c;
  4260. switch (c = nextchar ()) {
  4261. case '=':
  4262. return GE;
  4263. case '>':
  4264. return SHR;
  4265. default:
  4266. peekc = c;
  4267. return corig;
  4268. }
  4269. /* break; suppress "unreachable" warning for tcc */
  4270. case '!':
  4271. corig = c;
  4272. switch (c = nextchar ()) {
  4273. case '=':
  4274. return NE;
  4275. default:
  4276. peekc = c;
  4277. return corig;
  4278. }
  4279. /* break; suppress "unreachable" warning for tcc */
  4280. case '=':
  4281. corig = c;
  4282. switch (c = nextchar ()) {
  4283. case '=':
  4284. return '=';
  4285. default:
  4286. peekc = c;
  4287. return corig;
  4288. }
  4289. /* break; suppress "unreachable" warning for tcc */
  4290. case '&':
  4291. corig = c;
  4292. if ((c = nextchar()) == '&')
  4293. return ANDAND;
  4294. else {
  4295. peekc = c;
  4296. return corig;
  4297. }
  4298. /* break; suppress "unreachable" warning for tcc */
  4299. case '|':
  4300. corig = c;
  4301. if ((c = nextchar()) == '|')
  4302. return OROR;
  4303. else {
  4304. peekc = c;
  4305. return corig;
  4306. }
  4307. /* break; suppress "unreachable" warning for tcc */
  4308. default:
  4309. return(c);
  4310. }
  4311. }
  4312. }
  4313. // Verify keytab is in alphabetical order.
  4314. int check_keytab()
  4315. {
  4316. int i;
  4317. char *prev;
  4318. for (i = 0; i < sizeof(keytab) / sizeof(keytab[0]); i++) {
  4319. char *next = keytab[i].i_string;
  4320. next += *next == '.';
  4321. if (i != 0) {
  4322. if (strcmp(prev, next) >= 0) {
  4323. printf("keytab error: %s >= %s\n", prev, next);
  4324. return 0;
  4325. }
  4326. }
  4327. prev = next;
  4328. }
  4329. printf("keytab OK\n");
  4330. return 1;
  4331. }
  4332. struct item *keyword(char *name)
  4333. {
  4334. int r, l, u;
  4335. struct item *ip;
  4336. /*
  4337. * binary search
  4338. */
  4339. l = 0;
  4340. u = (sizeof keytab/sizeof keytab[0])-1;
  4341. while (l <= u) {
  4342. char *key;
  4343. i = (l+u)/2;
  4344. ip = &keytab[i];
  4345. key = ip->i_string;
  4346. r = strcmp(name + (name[0] == '.'), key + (key[0] == '.'));
  4347. if (r == 0) {
  4348. // Do not allow ".foo" to match "foo"
  4349. if (name[0] == '.' && key[0] != '.')
  4350. break;
  4351. return ip;
  4352. }
  4353. if (r < 0)
  4354. u = i-1;
  4355. else
  4356. l = i+1;
  4357. }
  4358. return 0;
  4359. }
  4360. // Find 'name' in an item table. Returns an empty slot if not found.
  4361. // Uses case-independent comparisions which are largely wasted as
  4362. // there is only 1 case where 'name' has not already been lowercased.
  4363. struct item *item_lookup(char *name, struct item *table, int table_size)
  4364. {
  4365. struct item *ip;
  4366. /*
  4367. * hash into item table
  4368. */
  4369. int hash = 0;
  4370. char *p = name;
  4371. while (*p) {
  4372. char ch = *p++;
  4373. if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A';
  4374. hash += ch;
  4375. }
  4376. hash %= table_size;
  4377. ip = &table[hash];
  4378. for (;;) {
  4379. if (ip->i_token == 0)
  4380. break;
  4381. if (ci_strcmp(name, ip->i_string) == 0)
  4382. break;
  4383. if (++ip >= table + table_size)
  4384. ip = table;
  4385. }
  4386. return ip;
  4387. }
  4388. struct item *locate(char *name)
  4389. {
  4390. return item_lookup(name, itemtab, ITEMTABLESIZE);
  4391. }
  4392. /*
  4393. * return the token associated with the string pointed to by
  4394. * tempbuf. if no token is associated with the string, associate
  4395. * deftoken with the string and return deftoken.
  4396. * in either case, cause yylval to point to the relevant
  4397. * symbol table entry.
  4398. *
  4399. * Only keys not matching the keyexclude will be returned allowing
  4400. * context-dependent tokenization. Unless they match keyinclude.
  4401. */
  4402. int tokenofitem(int deftoken, int keyexclude, int keyinclude)
  4403. {
  4404. struct item *ip;
  4405. int i;
  4406. #ifdef T_DEBUG
  4407. fputs("'tokenofitem entry' ", stderr) ;
  4408. fputs(tempbuf, stderr) ;
  4409. #endif
  4410. // Allow macros to override built-ins
  4411. // Maybe shouldn't be done for identifiers that will undergo
  4412. // '.' and '_' expansion.
  4413. ip = locate(tempbuf);
  4414. if (ip->i_token == MNAME)
  4415. goto found;
  4416. if (full_exprs)
  4417. keyexclude = ~TERM;
  4418. ip = keyword(tempbuf);
  4419. if (ip) {
  4420. if (ip->i_uses & keyinclude)
  4421. goto found;
  4422. if (!(ip->i_uses & keyexclude))
  4423. goto found;
  4424. }
  4425. // This is really my own thing rather than old zmac, but zmac
  4426. // didn't support it and it does depend on '$' crushing a bit.
  4427. if (zcompat) {
  4428. // '_' prefixed labels are local to the file
  4429. if (tempbuf[0] == '_') {
  4430. strcat(tempbuf, "$");
  4431. strcat(tempbuf, basename(src_name[now_in]));
  4432. }
  4433. // '.' prefixed labels are local between labels
  4434. if (tempbuf[0] == '.') {
  4435. char *p = tempbuf;
  4436. while (*p) p++;
  4437. sprintf(p, "$%d", llseq);
  4438. }
  4439. }
  4440. ip = locate(tempbuf);
  4441. if (ip->i_token)
  4442. goto found;
  4443. if (!deftoken) {
  4444. i = 0 ;
  4445. goto token_done ;
  4446. }
  4447. if (++nitems > ITEMTABLESIZE-20)
  4448. error("item table overflow");
  4449. ip->i_string = malloc(strlen(tempbuf)+1);
  4450. ip->i_token = deftoken;
  4451. ip->i_uses = 0;
  4452. strcpy(ip->i_string, tempbuf);
  4453. found:
  4454. if (*ifptr) {
  4455. if (ip->i_token == ENDIF_TK) {
  4456. i = ENDIF_TK;
  4457. goto token_done ;
  4458. }
  4459. if (ip->i_token == ELSE_TK) {
  4460. /* We must only honour the ELSE if it is not
  4461. in a nested failed IF/ELSE */
  4462. char forbid = 0;
  4463. char *ifstackptr;
  4464. for (ifstackptr = ifstack; ifstackptr != ifptr; ++ifstackptr) {
  4465. if (*ifstackptr) {
  4466. forbid = 1;
  4467. break;
  4468. }
  4469. }
  4470. if (!forbid) {
  4471. i = ELSE_TK;
  4472. goto token_done;
  4473. }
  4474. }
  4475. if (ip->i_token == IF_TK) {
  4476. if (ifptr >= ifstmax)
  4477. error("Too many ifs");
  4478. else *++ifptr = 1;
  4479. }
  4480. i = skipline(' ');
  4481. goto token_done ;
  4482. }
  4483. yylval.itemptr = ip;
  4484. i = ip->i_token;
  4485. token_done:
  4486. #ifdef T_DEBUG
  4487. fputs("\t'tokenofitem exit'\n", stderr) ;
  4488. #endif
  4489. return(i) ;
  4490. }
  4491. void itemcpy(struct item *dst, struct item *src)
  4492. {
  4493. if (dst && src) {
  4494. dst->i_string = src->i_string;
  4495. dst->i_value = src->i_value;
  4496. dst->i_token = src->i_token;
  4497. dst->i_uses = src->i_uses;
  4498. dst->i_scope = src->i_scope;
  4499. dst->i_chain = src->i_chain;
  4500. }
  4501. }
  4502. /*
  4503. * interchange two entries in the item table -- used by custom_qsort
  4504. */
  4505. void interchange(int i, int j)
  4506. {
  4507. struct item temp;
  4508. itemcpy(&temp, itemtab + i);
  4509. itemcpy(itemtab + i, itemtab + j);
  4510. itemcpy(itemtab + j, &temp);
  4511. }
  4512. /*
  4513. * quick sort -- used by compactsymtab to sort the symbol table
  4514. */
  4515. void custom_qsort(int m, int n)
  4516. {
  4517. int i, j;
  4518. if (m < n) {
  4519. i = m;
  4520. j = n+1;
  4521. for (;;) {
  4522. do i++; while(strcmp(itemtab[i].i_string,
  4523. itemtab[m].i_string) < 0);
  4524. do j--; while(strcmp(itemtab[j].i_string,
  4525. itemtab[m].i_string) > 0);
  4526. if (i < j) interchange(i, j); else break;
  4527. }
  4528. interchange(m, j);
  4529. custom_qsort(m, j-1);
  4530. custom_qsort(j+1, n);
  4531. }
  4532. }
  4533. int getcol()
  4534. {
  4535. return inpptr - inpbuf;
  4536. }
  4537. /*
  4538. * get the next character
  4539. */
  4540. int nextchar()
  4541. {
  4542. int c, ch;
  4543. unsigned char *p;
  4544. char *getlocal();
  4545. if (peekc != -1) {
  4546. c = peekc;
  4547. peekc = -1;
  4548. return c;
  4549. }
  4550. if (inpptr) {
  4551. // Double nul indicates EOF for macros
  4552. if (expptr && inpptr[0] == '\0' && inpptr[1] == '\0') {
  4553. inpptr = 0;
  4554. return 0;
  4555. }
  4556. if (getcol() == 0) {
  4557. void analyze_inpbuf(void);
  4558. if (!expptr)
  4559. linein[now_in]++;
  4560. analyze_inpbuf();
  4561. }
  4562. c = *inpptr++;
  4563. addtoline(c);
  4564. if (*inpptr == '\0')
  4565. inpptr = 0;
  4566. return c;
  4567. }
  4568. inpptr = inpbuf;
  4569. logcol = 0;
  4570. p = inpbuf;
  4571. // XXX - should check for input line overflow!
  4572. // If invoking a macro then pull the next line from it.
  4573. if (expptr) {
  4574. for (;;) {
  4575. ch = getm();
  4576. if (ch == '\1') { /* expand argument */
  4577. ch = getm() - 'A';
  4578. if (ch >= 0 && ch < PARMMAX && est[ch].param) {
  4579. strcpy((char *)p, est[ch].param);
  4580. p = (unsigned char *)strchr((char *)p, '\0');
  4581. }
  4582. }
  4583. else if (ch == '\2') { /* local symbol */
  4584. ch = getm() - 'A';
  4585. if (ch >= 0 && ch < PARMMAX && est[ch].param)
  4586. strcpy((char *)p, est[ch].param);
  4587. else
  4588. strcpy((char *)p, getlocal(ch, est[TEMPNUM].value));
  4589. p = (unsigned char *)strchr((char *)p, '\0');
  4590. }
  4591. else {
  4592. if (ch == 0)
  4593. break;
  4594. *p++ = ch;
  4595. if (ch == '\n')
  4596. break;
  4597. }
  4598. }
  4599. *p = '\0';
  4600. p[1] = ch;
  4601. }
  4602. else {
  4603. if (nextline_peek != -1) {
  4604. *p++ = nextline_peek;
  4605. nextline_peek = -1;
  4606. }
  4607. for (;;) {
  4608. ch = getc(now_file);
  4609. if (ch == '\r') {
  4610. nextline_peek = getc(now_file);
  4611. if (nextline_peek == '\n')
  4612. nextline_peek = -1;
  4613. else if (nextline_peek == EOF) {
  4614. *p++ = '\n';
  4615. nextline_peek = -1;
  4616. ch = EOF;
  4617. break;
  4618. }
  4619. ch = '\n';
  4620. }
  4621. if (ch == EOF)
  4622. break;
  4623. *p++ = ch;
  4624. if (ch == '\n')
  4625. break;
  4626. }
  4627. *p = '\0';
  4628. /* if EOF, check for include file */
  4629. if (ch == EOF) {
  4630. if (now_in) {
  4631. fclose(fin[now_in]) ;
  4632. free(src_name[now_in]);
  4633. now_file = fin[--now_in];
  4634. }
  4635. else if (p == inpbuf)
  4636. return 0;
  4637. if (linein[now_in] < 0) {
  4638. lstoff = 1;
  4639. linein[now_in] = -linein[now_in];
  4640. } else {
  4641. lstoff = 0 ;
  4642. }
  4643. if (outpass) {
  4644. if (iflist()) {
  4645. lineout();
  4646. fprintf(fout, "**** %s ****\n", src_name[now_in]) ;
  4647. }
  4648. if (bopt)
  4649. fprintf(fbds, "%04x %04x f %s\n", dollarsign, emit_addr, src_name[now_in]);
  4650. }
  4651. if (p != inpbuf) {
  4652. *p++='\n';
  4653. *p = '\0';
  4654. }
  4655. else
  4656. inpptr = 0;
  4657. }
  4658. }
  4659. return nextchar();
  4660. }
  4661. char *skipspace(char *p)
  4662. {
  4663. while (charclass[*p] == SPACE)
  4664. p++;
  4665. return p;
  4666. }
  4667. // Look at inpbuf and try to determine what logical column we are starting
  4668. // at. We could put all of the work in here and keep yylex simple but for
  4669. // now we share the load.
  4670. void analyze_inpbuf(void)
  4671. {
  4672. int cc;
  4673. char *p, *q, save;
  4674. char *word1, *word2;
  4675. struct item *ip, *word1item;
  4676. int triplecase = 1;
  4677. // No need to do this when pulling in data for a macro. In fact,
  4678. // in can be harmful to undef a macro.
  4679. if (inmlex)
  4680. return;
  4681. // Default if we find nothing to override
  4682. logcol = 0;
  4683. // One case to check is when you start with whitespace yet there are
  4684. // 3 columns. If so then we change logcol to -1 to compensate.
  4685. // If the 2nd column is a VERB.
  4686. // If we start with whitespace then we can give up on triple word case.
  4687. p = (char *)inpbuf;
  4688. if (charclass[*p] != SPACE)
  4689. triplecase = 0;
  4690. p = skipspace(p);
  4691. word1 = p;
  4692. // Now skip over a token or abort if we don't find one
  4693. cc = charclass[*p];
  4694. if (cc != LETTER && cc != STARTER && cc != DIGIT && cc != DOLLAR)
  4695. return;
  4696. for (;;) {
  4697. cc = charclass[*p];
  4698. if (cc == LETTER || cc == STARTER || cc == DIGIT || cc == DOLLAR)
  4699. p++;
  4700. else
  4701. break;
  4702. }
  4703. // We could skip space-separated colons now, but if we see a colon
  4704. // both issues have been decided to do that because it is easier.
  4705. if (*p == ':')
  4706. return;
  4707. save = *p;
  4708. *p = '\0';
  4709. word1item = locate(word1);
  4710. *p = save;
  4711. p = skipspace(p);
  4712. // Another token to skip past.
  4713. // But we need to examine it to see if it is a verb.
  4714. cc = charclass[*p];
  4715. if (cc != LETTER && cc != STARTER && cc != DIGIT && cc != DOLLAR)
  4716. return;
  4717. q = p;
  4718. word2 = p;
  4719. for (;;) {
  4720. cc = charclass[*p];
  4721. if (cc == LETTER || cc == STARTER || cc == DIGIT || cc == DOLLAR)
  4722. p++;
  4723. else
  4724. break;
  4725. }
  4726. // Now we have a second word we can check for the "name macro" case.
  4727. // Unless we're skipping.
  4728. save = *p;
  4729. *p = '\0';
  4730. if (ci_strcmp(word2, "macro") == 0 && word1item->i_token && !*ifptr)
  4731. word1item->i_token = UNDECLARED;
  4732. *p = save;
  4733. if (!triplecase)
  4734. return;
  4735. // Must have space to skip over
  4736. if (charclass[*p] != SPACE)
  4737. return;
  4738. // This 2nd token must be a verb.
  4739. cc = *p;
  4740. *p = '\0';
  4741. ip = keyword(q);
  4742. *p = cc;
  4743. if (!ip || !(ip->i_uses & VERB))
  4744. return;
  4745. // Now skip over space. If there's anything but a comment or end
  4746. // of the line then we've may have 3 logical columns.
  4747. // "ld a, 5" can throw that off, but we've done the verb check.
  4748. p = skipspace(p);
  4749. if (*p != ';' && *p != '\n' && *p != '\0')
  4750. logcol--;
  4751. }
  4752. /*
  4753. * skip to rest of the line -- comments and if skipped lines
  4754. */
  4755. int skipline(int ac)
  4756. {
  4757. int c;
  4758. c = ac;
  4759. while (c != '\n' && c != '\0')
  4760. c = nextchar();
  4761. return('\n');
  4762. }
  4763. void add_incpath(char *dir)
  4764. {
  4765. char *p;
  4766. if (incpath_cnt >= MAXINCPATH) {
  4767. fprintf(stderr, "Sorry, can only handle %d include paths\n", MAXINCPATH);
  4768. exit(1);
  4769. }
  4770. p = malloc(strlen(dir) + 1);
  4771. strcpy(p, dir);
  4772. incpath[incpath_cnt++] = dir;
  4773. }
  4774. FILE *open_incpath(char *filename, char *mode)
  4775. {
  4776. char quote;
  4777. int i;
  4778. char path[1024];
  4779. FILE *fp;
  4780. // Due to the way parsing works the string can be specified
  4781. // without quotes or will allow quotes but include them. Instead
  4782. // of fooling with the parsing I just strip the quotes. I think
  4783. // you can still include a file that starts with a single or double
  4784. // quote by quoting it, but that's an awful thing to do to yourself.
  4785. quote = *filename;
  4786. if (quote == '"' || quote == '\'') {
  4787. strcpy(filename, filename + 1);
  4788. if (strrchr(filename, quote))
  4789. *strrchr(filename, quote) = '\0';
  4790. }
  4791. // First look for included file in same directory as source file.
  4792. strcpy(path, src_name[now_in]);
  4793. *basename(path) = '\0';
  4794. strcat(path, filename);
  4795. fp = fopen(path, mode);
  4796. if (fp) {
  4797. if (note_depend && outpass)
  4798. printf("%s\n", path);
  4799. return fp;
  4800. }
  4801. for (i = 0; i < incpath_cnt; i++) {
  4802. sprintf(path, "%s/%s", incpath[i], filename);
  4803. fp = fopen(path, mode);
  4804. if (fp) {
  4805. if (note_depend && outpass)
  4806. printf("%s\n", path);
  4807. return fp;
  4808. }
  4809. }
  4810. if (note_depend && outpass)
  4811. printf("%s\n", filename);
  4812. return fopen(filename, mode);
  4813. }
  4814. void version()
  4815. {
  4816. fprintf(stderr, "zmac version " VERSION "\n");
  4817. }
  4818. //
  4819. // Print out a usage message and exit.
  4820. //
  4821. void usage(char *msg, char *param)
  4822. {
  4823. fprintf(stderr, msg, param);
  4824. fprintf(stderr, "\n");
  4825. version();
  4826. fprintf(stderr, "usage: zmac [-8bcefghijJlLmnopstz] [-I dir] file[.z]\n");
  4827. fprintf(stderr, "other opts: --rel --mras --zmac --dep --help --doc --version\n");
  4828. fprintf(stderr, " zmac -h for more detail about options.\n");
  4829. exit(1);
  4830. }
  4831. void help()
  4832. {
  4833. version();
  4834. fprintf(stderr, "\t--version show version number\n");
  4835. fprintf(stderr, "\t--help\tshow this help message\n");
  4836. fprintf(stderr, "\t-8\tuse 8080 interpretation of mnemonics\n");
  4837. fprintf(stderr, "\t-b\tno binary (.hex,.cmd,.cas, etc.) output\n");
  4838. fprintf(stderr, "\t-c\tno cycle counts in listing\n");
  4839. fprintf(stderr, "\t-e\terror list only\n");
  4840. fprintf(stderr, "\t-f\tprint if skipped lines\n");
  4841. fprintf(stderr, "\t-g\tdo not list extra code\n");
  4842. fprintf(stderr, "\t-h\tshow this information about options and quit\n");
  4843. fprintf(stderr, "\t-i\tdo not list include files\n");
  4844. fprintf(stderr, "\t-I dir\tadd 'dir' to include file search path\n");
  4845. fprintf(stderr, "\t-j\tpromote relative jumps to absolute as needed\n");
  4846. fprintf(stderr, "\t-J\twarn when a jump could be relative\n");
  4847. fprintf(stderr, "\t-l\tno list\n");
  4848. fprintf(stderr, "\t-L\tforce listing of everything\n");
  4849. fprintf(stderr, "\t-m\tprint macro expansions\n");
  4850. fprintf(stderr, "\t-n\tput line numbers off\n");
  4851. fprintf(stderr, "\t-o\tlist to standard output\n");
  4852. fprintf(stderr, "\t-p\tput out four \\n's for eject\n");
  4853. fprintf(stderr, "\t-s\tdon't produce a symbol list\n");
  4854. fprintf(stderr, "\t-t\toutput error count instead of list of errors\n");
  4855. fprintf(stderr, "\t-z\tuse Z-80 interpretation of mnemonics\n");
  4856. fprintf(stderr, "\t--dep\tlist files included\n");
  4857. fprintf(stderr, "\t--mras\tlimited MRAS/EDAS compatibility\n");
  4858. fprintf(stderr, "\t--rel\toutput .rel file only\n");
  4859. fprintf(stderr, "\t--zmac\tcompatibility with original zmac\n");
  4860. fprintf(stderr, "\t--doc\toutput documentation as HTML file\n");
  4861. exit(0);
  4862. }
  4863. int main(int argc, char *argv[])
  4864. {
  4865. struct item *ip;
  4866. int i;
  4867. int files;
  4868. #ifdef DBUG
  4869. extern yydebug;
  4870. #endif
  4871. fout = stdout ;
  4872. fin[0] = stdin ;
  4873. now_file = stdin ;
  4874. files = 0;
  4875. // Special flag for unit testing.
  4876. if (argc > 1 && strcmp(argv[1], "--test") == 0)
  4877. exit(!check_keytab());
  4878. for (i=1; i<argc; i++) {
  4879. int skip = 0;
  4880. if (strcmp(argv[i], "--mras") == 0) {
  4881. mras = 1;
  4882. continue;
  4883. }
  4884. if (strcmp(argv[i], "--rel") == 0) {
  4885. relopt = 1;
  4886. bopt = 0;
  4887. continue;
  4888. }
  4889. if (strcmp(argv[i], "--zmac") == 0) {
  4890. zcompat = 1;
  4891. continue;
  4892. }
  4893. if (strcmp(argv[i], "--dep") == 0) {
  4894. note_depend = 1;
  4895. continue;
  4896. }
  4897. if (strcmp(argv[i], "--help") == 0) {
  4898. help();
  4899. continue;
  4900. }
  4901. if (strcmp(argv[i], "--doc") == 0) {
  4902. extern void doc(void);
  4903. doc();
  4904. exit(0);
  4905. continue; // not reached
  4906. }
  4907. if (strcmp(argv[i], "--version") == 0) {
  4908. version();
  4909. exit(0);
  4910. continue; // not reached
  4911. }
  4912. if (*argv[i] == '-') while (*++argv[i]) {
  4913. switch(*argv[i]) {
  4914. case '8': /* Equivalent to .8080 */
  4915. default_z80 = 0;
  4916. continue;
  4917. case 'b': /* no binary */
  4918. bopt = 0;
  4919. continue;
  4920. case 'c': /* no cycle counts in listing */
  4921. copt-- ;
  4922. continue;
  4923. #ifdef DBUG
  4924. case 'd': /* debug */
  4925. yydebug++;
  4926. continue;
  4927. #endif
  4928. case 'e': /* error list only */
  4929. eopt = 0;
  4930. edef = 0;
  4931. continue;
  4932. case 'f': /* print if skipped lines */
  4933. fopt++;
  4934. fdef++;
  4935. continue;
  4936. case 'g': /* do not list extra code */
  4937. gopt = 0;
  4938. gdef = 0;
  4939. continue;
  4940. case 'h':
  4941. help();
  4942. continue;
  4943. case 'i': /* do not list include files */
  4944. iopt = 1 ;
  4945. continue ;
  4946. case 'I':
  4947. if (argv[i][1])
  4948. add_incpath(argv[i] + 1);
  4949. else {
  4950. i++;
  4951. if (i < argc)
  4952. add_incpath(argv[i]);
  4953. else
  4954. usage("missing argument to -I option", 0);
  4955. }
  4956. skip = 1;
  4957. break;
  4958. case 'l': /* no list */
  4959. lopt++;
  4960. continue;
  4961. case 'L': /* force listing of everything */
  4962. lston++;
  4963. continue;
  4964. case 'j': // promote relative jumps to absolute as needed
  4965. default_jopt = 1;
  4966. continue;
  4967. case 'J': // error when JR instructions could replace JP
  4968. default_JPopt = 1;
  4969. continue;
  4970. case 'm': /* print macro expansions */
  4971. mdef++;
  4972. mopt++;
  4973. continue;
  4974. case 'n': /* put line numbers off */
  4975. nopt-- ;
  4976. continue;
  4977. case 'o': /* list to standard output */
  4978. oopt++;
  4979. continue;
  4980. case 'p': /* put out four \n's for eject */
  4981. popt-- ;
  4982. continue;
  4983. case 'P': // GWP - printer style output (headers, page separation, etc.)
  4984. printer_output = 1;
  4985. continue;
  4986. case 's': /* don't produce a symbol list */
  4987. sopt++;
  4988. continue;
  4989. case 't': /* output only number of errors */
  4990. topt = 0;
  4991. continue;
  4992. case 'z': /* Equivalent to .z80 */
  4993. default_z80 = 1;
  4994. continue;
  4995. default: /* error */
  4996. usage("Unknown option", 0);
  4997. }
  4998. if (skip)
  4999. break;
  5000. }
  5001. else if (files++ == 0) {
  5002. sourcef = argv[i];
  5003. strcpy(src, sourcef);
  5004. if ((now_file = fopen(src, "r")) == NULL) {
  5005. if (!*getsuffix(src))
  5006. suffix(src, ".z");
  5007. if ((now_file = fopen(src, "r")) == NULL)
  5008. usage("Cannot open source file '%s'", src);
  5009. }
  5010. now_in = 0;
  5011. fin[now_in] = now_file ;
  5012. src_name[now_in] = src ;
  5013. } else if (files)
  5014. usage("Too many arguments", 0);
  5015. }
  5016. if (files == 0)
  5017. usage("No source file", 0);
  5018. {
  5019. char outdir[1025];
  5020. outpath(outdir, sourcef, 0);
  5021. #ifdef WIN32
  5022. _mkdir(outdir);
  5023. #else
  5024. mkdir(outdir, 0777);
  5025. #endif
  5026. }
  5027. if (bopt) {
  5028. outpath(bds, sourcef, ".bds");
  5029. fbds = fopen(bds, "w");
  5030. if (fbds == NULL)
  5031. error("Cannot create .bds file");
  5032. fprintf(fbds, "binary-debuggable-source\n");
  5033. fprintf(fbds, "%04x %04x f %s\n", dollarsign, emit_addr, src_name[now_in]);
  5034. outpath(oth, sourcef, ".cmd");
  5035. fcmd = fopen(oth, "wb");
  5036. if (fcmd == NULL)
  5037. error("Cannot create .cmd file");
  5038. outpath(oth, sourcef, ".cas");
  5039. fcas = fopen(oth, "wb");
  5040. if (fcas == NULL)
  5041. error("Cannot create .cas file");
  5042. outpath(oth, sourcef, ".lcas");
  5043. flcas = fopen(oth, "wb");
  5044. if (flcas == NULL)
  5045. error("Cannot create .lcas file");
  5046. // Tape header
  5047. for (i = 0; i < 255; i++) {
  5048. fputc(0, flcas);
  5049. fputc(0x55, fcas);
  5050. }
  5051. fputc(0xA5, flcas);
  5052. fputc(0x7F, fcas);
  5053. casname(oth, sourcef);
  5054. putcas(0x55);
  5055. for (i = 0; i < 6; i++)
  5056. putcas(oth[i]);
  5057. outpath(oth, sourcef, ".cim");
  5058. fcim = fopen(oth, "wb");
  5059. if (fcim == NULL)
  5060. error("Cannot create .cim file");
  5061. outpath(oth, sourcef, ".ams");
  5062. fams = fopen(oth, "wb");
  5063. if (fams == NULL)
  5064. error("Cannot create .ams file");
  5065. outpath(bin, sourcef, ".hex");
  5066. #ifdef MSDOS
  5067. if (( fbuf = fopen(bin, "wb")) == NULL)
  5068. #else
  5069. if (( fbuf = fopen(bin, "w")) == NULL)
  5070. #endif
  5071. error("Cannot create .hex file");
  5072. }
  5073. else if (relopt) {
  5074. outpath(oth, sourcef, ".rel");
  5075. frel = fopen(oth, "wb");
  5076. if (frel == NULL)
  5077. error("Cannot create .rel file");
  5078. strncpy(progname, basename(sourcef), sizeof progname);
  5079. progname[sizeof progname - 1] = '\0';
  5080. }
  5081. if (!lopt && !oopt) {
  5082. outpath(listf, sourcef, ".lst");
  5083. if ((fout = fopen(listf, "w")) == NULL)
  5084. error("Cannot create list file");
  5085. } else
  5086. fout = stdout ;
  5087. outpath(mtmp, sourcef, ".tmp");
  5088. #ifdef MSDOS
  5089. mfile = mfopen(mtmp,"w+b") ;
  5090. #else
  5091. mfile = mfopen(mtmp,"w+") ;
  5092. #endif
  5093. if (mfile == NULL) {
  5094. error("Cannot create temp file");
  5095. }
  5096. /*unlink(mtmp);*/
  5097. /*
  5098. * get the time
  5099. */
  5100. time(&now);
  5101. timp = ctime(&now);
  5102. timp[16] = 0;
  5103. timp[24] = 0;
  5104. title = sourcef;
  5105. /*
  5106. * pass 1
  5107. */
  5108. #ifdef DEBUG
  5109. fputs("DEBUG-pass 1\n", stderr) ;
  5110. #endif
  5111. clear();
  5112. setvars();
  5113. outpass = 0;
  5114. yyparse();
  5115. // GWP - errors should stop us, but the listing is very useful.
  5116. pass2++;
  5117. for (npass = 2; npass < MAXPASS; npass++) {
  5118. if (passfail || npass == MAXPASS - 1)
  5119. outpass = 1;
  5120. if (outpass) {
  5121. putrelcmd(RELCMD_PROGNAME);
  5122. putrelname(progname);
  5123. }
  5124. ip = itemtab;
  5125. ip--;
  5126. while (++ip < itemmax) {
  5127. // Output list of public labels. m80 will let
  5128. // equates and aseg values be public so we do, too.
  5129. if (outpass && ip->i_token && (ip->i_scope & SCOPE_PUBLIC)) {
  5130. putrelcmd(RELCMD_PUBLIC);
  5131. putrelname(ip->i_string);
  5132. }
  5133. /* reset use count */
  5134. ip->i_uses = 0 ;
  5135. /* set macro names, equated and defined names */
  5136. switch (ip->i_token) {
  5137. case MNAME:
  5138. ip->i_token = UNDECLARED;
  5139. break;
  5140. case EQUATED:
  5141. ip->i_token = WASEQUATED;
  5142. break;
  5143. case DEFLED:
  5144. if (zcompat)
  5145. ip->i_token = UNDECLARED;
  5146. break;
  5147. }
  5148. }
  5149. if (outpass) {
  5150. // m80 outputs data size as an absolute value, but
  5151. // code size as code segment relative. Odd, but
  5152. // I'll follow suit.
  5153. putrelcmd(RELCMD_DATASIZE);
  5154. putrelsegref(SEG_ABS, seg_size[SEG_DATA]);
  5155. putrelcmd(RELCMD_CODESIZE);
  5156. putrelsegref(SEG_CODE, seg_size[SEG_CODE]);
  5157. }
  5158. // In case we hit 'end' inside an included file
  5159. while (now_in > 0) {
  5160. fclose(fin[now_in]);
  5161. free(src_name[now_in]);
  5162. now_file = fin[--now_in];
  5163. }
  5164. setvars();
  5165. fseek(now_file, (long)0, 0);
  5166. #ifdef DEBUG
  5167. fprintf(stderr, "DEBUG- pass %d\n", npass) ;
  5168. #endif
  5169. yyparse();
  5170. if (outpass || passfail)
  5171. break;
  5172. if (!passretry)
  5173. outpass = 1;
  5174. }
  5175. if (bopt) {
  5176. flushbin();
  5177. flushoth();
  5178. putc(':', fbuf);
  5179. if (xeq_flag) {
  5180. puthex(0, fbuf);
  5181. puthex(xeq >> 8, fbuf);
  5182. puthex(xeq, fbuf);
  5183. puthex(1, fbuf);
  5184. puthex(255-(xeq >> 8)-xeq, fbuf);
  5185. fprintf(fcmd, "%c%c%c%c", 2, 2, xeq, xeq >> 8);
  5186. fflush(fcmd);
  5187. putcas(0x78);
  5188. putcas(xeq);
  5189. putcas(xeq >> 8);
  5190. } else
  5191. for (i = 0; i < 10; i++)
  5192. putc('0', fbuf);
  5193. putc('\n', fbuf);
  5194. fflush(fbuf);
  5195. // "Play Cas" seems to require trailing zeros to work
  5196. // properly. And we need to output at least one zero byte
  5197. // to flush out the final high speed bits.
  5198. for (i = 0; i < 6; i++)
  5199. putcas(0);
  5200. }
  5201. if (relopt) {
  5202. struct item *ip;
  5203. // Output external symbols and value of public symbols
  5204. for (ip = itemtab; ip < itemmax; ip++) {
  5205. if (ip->i_token == UNDECLARED && (ip->i_scope & SCOPE_EXTERNAL)) {
  5206. putrelcmd(RELCMD_EXTCHAIN);
  5207. // Chain value will have top two bits set appropriately
  5208. putrelextaddr(ip->i_chain);
  5209. putrelname(ip->i_string);
  5210. }
  5211. if (ip->i_scope & SCOPE_PUBLIC)
  5212. {
  5213. putrelcmd(RELCMD_PUBVALUE);
  5214. putrelsegref(ip->i_scope, ip->i_value);
  5215. putrelname(ip->i_string);
  5216. }
  5217. }
  5218. // End module, entry address if any
  5219. putrelcmd(RELCMD_ENDMOD);
  5220. putrelextaddr(rel_main);
  5221. flushrel(); // byte alignment expected after end module
  5222. // End .rel file
  5223. putrelcmd(RELCMD_ENDPROG);
  5224. flushrel();
  5225. }
  5226. if (xeq_flag == 0) {
  5227. #if WIN32
  5228. CONSOLE_SCREEN_BUFFER_INFO inf;
  5229. HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  5230. GetConsoleScreenBufferInfo(hOut, &inf);
  5231. SetConsoleTextAttribute(hOut, FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
  5232. #endif
  5233. fprintf(stderr, "Warning: no entry address (forgot \"end label\")\n");
  5234. fflush(stderr);
  5235. #if WIN32
  5236. SetConsoleTextAttribute(hOut, inf.wAttributes);
  5237. #endif
  5238. }
  5239. else if (bopt) {
  5240. fprintf(fbds, "%04x e\n", xeq);
  5241. }
  5242. if (bopt) {
  5243. int low = 0;
  5244. int high = sizeof(memory) - 1;
  5245. int chk;
  5246. int filelen;
  5247. char leafname[] = "FILENAMEBIN";
  5248. while (low < sizeof(memory) && (memflag[low] & (MEM_INST | MEM_DATA)) == 0)
  5249. low++;
  5250. while (high >= 0 && (memflag[high] & (MEM_INST | MEM_DATA)) == 0)
  5251. high--;
  5252. if (high >= low)
  5253. fwrite(memory + low, high + 1 - low, 1, fcim);
  5254. // AMSDOS binary file output (A for Amstrad, code from zmac 1.3)
  5255. filelen = (high + 1) - low;
  5256. chk = 0;
  5257. putc(0, fams);
  5258. for (i = 0; i < 11; i++) {
  5259. putc(leafname[i], fams);
  5260. chk += leafname[i];
  5261. }
  5262. for (i = 0; i < 6; i++)
  5263. putc(0, fams);
  5264. putc(2, fams); // Unprotected binary
  5265. chk += 2;
  5266. putc(0, fams);
  5267. putc(0, fams);
  5268. putc(low & 0xff, fams);
  5269. chk += low & 0xff;
  5270. putc(low >> 8, fams);
  5271. chk += low >> 8;
  5272. putc(0, fams);
  5273. putc(filelen & 0xff, fams);
  5274. chk += filelen & 0xff;
  5275. putc(filelen >> 8, fams);
  5276. chk += filelen >> 8;
  5277. putc(xeq & 0xff, fams);
  5278. chk += xeq & 0xff;
  5279. putc(xeq >> 8, fams);
  5280. chk += xeq >> 8;
  5281. for (i = 28; i < 64; i++)
  5282. putc(0, fams);
  5283. putc(filelen & 0xff, fams);
  5284. chk += filelen & 0xff;
  5285. putc(filelen >> 8, fams);
  5286. chk += filelen >> 8;
  5287. putc(0, fams); // this would be used if filelen > 64K
  5288. putc(chk & 0xff, fams);
  5289. putc(chk >> 8, fams);
  5290. for (i = 69; i < 128; i++)
  5291. putc(0, fams);
  5292. if (filelen > 0)
  5293. fwrite(memory + low, filelen, 1, fams);
  5294. if (filelen & 0x7f)
  5295. putc(0x1a, fams); // CP/M EOF character
  5296. }
  5297. if (bopt) {
  5298. struct item *tp;
  5299. for (tp = itemtab; tp < itemmax; tp++) {
  5300. if (tp->i_token == LABEL)
  5301. fprintf(fbds, "%04x a %s\n", tp->i_value, tp->i_string);
  5302. else if (tp->i_token == EQUATED)
  5303. fprintf(fbds, "%04x v %s\n", tp->i_value, tp->i_string);
  5304. }
  5305. }
  5306. if (!lopt)
  5307. fflush(fout);
  5308. if (writesyms)
  5309. outsymtab(writesyms);
  5310. compactsymtab();
  5311. if (eopt)
  5312. erreport();
  5313. if (!lopt && !sopt)
  5314. putsymtab();
  5315. if (!lopt) {
  5316. eject();
  5317. fflush(fout);
  5318. }
  5319. // GWP - some things (like balance errors in macro definitions) do
  5320. // not show up until you use them. So just in case we print an error
  5321. // count here as not to confuse the programmer who is unlikely to check
  5322. // the listing for errors if none are shown in the command window.
  5323. if (counterr() > 0)
  5324. fprintf(stderr, "%d errors (see listing if no diagnostics appeared here)\n", counterr());
  5325. if (countwarn() > 0)
  5326. fprintf(stderr, "%d warnings (see listing if no diagnostics appeared here)\n", countwarn());
  5327. exit(counterr() > 0);
  5328. }
  5329. void equate(char *id, int value)
  5330. {
  5331. struct item *it;
  5332. it = locate(id);
  5333. if (!it->i_token) {
  5334. nitems++;
  5335. it->i_value = value;
  5336. it->i_token = EQUATED;
  5337. it->i_scope = SCOPE_BUILTIN;
  5338. it->i_uses = 0;
  5339. it->i_string = malloc(strlen(id)+1);
  5340. strcpy(it->i_string, id);
  5341. }
  5342. }
  5343. /*
  5344. * set some data values before each pass
  5345. */
  5346. void setvars()
  5347. {
  5348. int i;
  5349. peekc = -1;
  5350. inpptr = 0;
  5351. nextline_peek = -1;
  5352. raw = 0;
  5353. linein[now_in] = linecnt = 0;
  5354. exp_number = 0;
  5355. emitptr = emitbuf;
  5356. lineptr = linebuf;
  5357. ifptr = ifstack;
  5358. *ifptr = 0;
  5359. dollarsign = 0;
  5360. emit_addr = 0;
  5361. olddollar = 0;
  5362. oldothdollar = 0;
  5363. phaseflag = 0;
  5364. for (i=0; i<FLAGS; i++) err[i] = 0;
  5365. tstates = 0;
  5366. ocf = 0;
  5367. llseq = 0;
  5368. passfail = 0;
  5369. passretry = 0;
  5370. njrpromo = 0;
  5371. jopt = default_jopt;
  5372. JPopt = default_JPopt;
  5373. strcpy(modstr, "@@@@");
  5374. segment = SEG_CODE;
  5375. memset(seg_pos, 0, sizeof(seg_pos));
  5376. memset(seg_size, 0, sizeof(seg_size));
  5377. segchange = 0;
  5378. z80 = default_z80;
  5379. outrec = 0;
  5380. param_parse = 0;
  5381. arg_reset();
  5382. mfptr = 0;
  5383. mfseek(mfile, mfptr, 0);
  5384. // These are slighly harmful, but not too bad. Only
  5385. // absolutely necessary for MAC compatibility. But there's
  5386. // some use in having them available always.
  5387. equate("b", 0);
  5388. equate("c", 1);
  5389. equate("d", 2);
  5390. equate("e", 3);
  5391. equate("h", 4);
  5392. equate("l", 5);
  5393. equate("m", 6);
  5394. equate("a", 7);
  5395. equate("sp", 6);
  5396. equate("psw", 6);
  5397. // There are a large number of symbols to add to support
  5398. // "LXI H,MOV" and the like.
  5399. }
  5400. //
  5401. // Clear out cycle counts and memory.
  5402. //
  5403. void clear()
  5404. {
  5405. int i;
  5406. for (i = 0; i < sizeof(memory) / sizeof(memory[0]); i++)
  5407. {
  5408. memory[i] = 0;
  5409. memflag[i] = 0;
  5410. tstatesum[i] = 0;
  5411. }
  5412. }
  5413. void setmem(int addr, int value, int type)
  5414. {
  5415. value &= 0xff;
  5416. memory[addr] = value;
  5417. memflag[addr] |= type;
  5418. }
  5419. /*
  5420. * print out an error message and die
  5421. */
  5422. void error(char *as)
  5423. {
  5424. *linemax = 0;
  5425. fprintf(fout, "%s\n", linebuf);
  5426. fflush(fout);
  5427. fprintf(stderr, "%s\n", as) ;
  5428. exit(1);
  5429. }
  5430. /*
  5431. * Compact the symbol table, removing unused, UNDECLARED entries,
  5432. * macros and built-in identifiers.
  5433. */
  5434. void compactsymtab()
  5435. {
  5436. struct item *tp, *fp;
  5437. if (!nitems)
  5438. return;
  5439. tp = itemtab;
  5440. tp--;
  5441. for (fp = itemtab; fp<itemmax; fp++) {
  5442. if (fp->i_token == UNDECLARED && !(fp->i_scope & SCOPE_EXTERNAL)) {
  5443. nitems--;
  5444. continue;
  5445. }
  5446. if (fp->i_token == 0)
  5447. continue;
  5448. // Don't list macros or internally defined symbols
  5449. if (fp->i_token == MNAME || (fp->i_scope & SCOPE_BUILTIN)) {
  5450. nitems--;
  5451. continue;
  5452. }
  5453. tp++;
  5454. if (tp != fp) {
  5455. tp->i_string = fp->i_string;
  5456. tp->i_value = fp->i_value;
  5457. tp->i_token = fp->i_token;
  5458. tp->i_uses = fp->i_uses;
  5459. tp->i_scope = fp->i_scope;
  5460. tp->i_chain = fp->i_chain;
  5461. }
  5462. }
  5463. tp++;
  5464. tp->i_string = "{"; /* } */
  5465. /* sort the table */
  5466. custom_qsort(0, nitems-1);
  5467. }
  5468. /*
  5469. * output the symbol table
  5470. */
  5471. void putsymtab()
  5472. {
  5473. int i, j, k, t, rows;
  5474. char c, c1, seg = ' ';
  5475. int numcol = printer_output ? 4 : 1;
  5476. struct item *tp;
  5477. if (!nitems)
  5478. return;
  5479. title = "** Symbol Table **";
  5480. rows = (nitems+numcol-1) / numcol;
  5481. if (rows+5+line > 60)
  5482. eject();
  5483. lineout();
  5484. fprintf(fout,"\n\n\nSymbol Table:\n\n") ;
  5485. line += 4;
  5486. for (i=0; i<rows; i++) {
  5487. for(j=0; j<numcol; j++) {
  5488. k = rows*j+i;
  5489. if (k < nitems) {
  5490. tp = &itemtab[k];
  5491. t = tp->i_token;
  5492. c = ' ' ;
  5493. if (t == EQUATED || t == DEFLED)
  5494. c = '=' ;
  5495. if (tp->i_uses == 0)
  5496. c1 = '+' ;
  5497. else
  5498. c1 = ' ' ;
  5499. // GWP - decided I don't care about uses
  5500. // even if it were accurate.
  5501. // TODO: Should use maxsymbol size in there,
  5502. // but makes output harder to read.
  5503. fprintf(fout, "%-15s%c", tp->i_string, c);
  5504. if (relopt)
  5505. seg = SEGCHAR(tp->i_scope & SCOPE_SEGMASK);
  5506. if (tp->i_value >> 16)
  5507. fprintf(fout, "%8x%c", tp->i_value, seg);
  5508. else
  5509. fprintf(fout, "%4x%c ", tp->i_value & 0xffff, seg);
  5510. if (tp->i_scope & SCOPE_EXTERNAL)
  5511. fprintf(fout, " (extern)");
  5512. if (tp->i_scope & SCOPE_PUBLIC)
  5513. fprintf(fout, " (public)");
  5514. }
  5515. }
  5516. lineout();
  5517. putc('\n', fout);
  5518. }
  5519. }
  5520. /*
  5521. * put out error report
  5522. */
  5523. void erreport()
  5524. {
  5525. int i, numerr, numwarn;
  5526. if (line > 49) eject();
  5527. lineout();
  5528. numerr = 0;
  5529. for (i=0; i<FIRSTWARN; i++) numerr += keeperr[i];
  5530. numwarn = 0;
  5531. for (i = FIRSTWARN; i < FLAGS; i++) numwarn += keeperr[i];
  5532. if (numerr || numwarn) {
  5533. fputs("\n\n\nError + Warning report:\n\n", fout);
  5534. fprintf(fout, "%6d errors\n", numerr);
  5535. fprintf(fout, "%6d warnings\n", numwarn);
  5536. line += 6;
  5537. } else {
  5538. fputs("\n\n\nStatistics:\n", fout);
  5539. line += 3;
  5540. }
  5541. for (i=0; i<FLAGS; i++)
  5542. if (keeperr[i]) {
  5543. lineout();
  5544. fprintf(fout, "%6d %c -- %s %s\n",
  5545. keeperr[i], errlet[i], errname[i],
  5546. i < FIRSTWARN ? "error" : "warnings");
  5547. }
  5548. if (line > 52) eject();
  5549. lineout();
  5550. fprintf(fout, "\n%6d\tpasses\n", npass);
  5551. fprintf(fout, "%6d\tjr promotions\n", njrpromo);
  5552. fprintf(fout, "%6d\tsymbols\n", nitems);
  5553. fprintf(fout, "%6d\tbytes\n", nbytes);
  5554. line += 4;
  5555. if (mfptr) {
  5556. if (line > 53) eject();
  5557. lineout();
  5558. fprintf(fout, "\n%6d\tmacro calls\n", exp_number);
  5559. fprintf(fout, "%6d\tmacro bytes\n", mfptr);
  5560. fprintf(fout, "%6d\tinvented symbols\n", invented/2);
  5561. line += 3;
  5562. }
  5563. }
  5564. /*
  5565. * count errors (GWP - added to set exit code)
  5566. */
  5567. int counterr()
  5568. {
  5569. int i, numerr = 0;
  5570. for (i=0; i<FIRSTWARN; i++) numerr += keeperr[i];
  5571. return numerr;
  5572. }
  5573. // Count warnings
  5574. int countwarn()
  5575. {
  5576. int i, numwarn = 0;
  5577. for (i = FIRSTWARN; i < FLAGS; i++)
  5578. numwarn += keeperr[i];
  5579. return numwarn;
  5580. }
  5581. char *mlook;
  5582. int nextmac()
  5583. {
  5584. int ch;
  5585. if (mlook) {
  5586. if (*mlook) {
  5587. ch = *mlook++;
  5588. addtoline(ch);
  5589. }
  5590. else
  5591. mlook = 0;
  5592. }
  5593. if (!mlook)
  5594. ch = nextchar();
  5595. return ch;
  5596. }
  5597. /*
  5598. * lexical analyser for macro definition
  5599. */
  5600. void mlex(char *look)
  5601. {
  5602. char *p;
  5603. int c;
  5604. int t;
  5605. int quote = 0, ampdrop = 0;
  5606. struct item *param, *key;
  5607. char symbuf[TEMPBUFSIZE];
  5608. char *symbufmax = symbuf+TEMPBUFSIZE-1;
  5609. /*
  5610. * move text onto macro file, changing formal parameters
  5611. */
  5612. #ifdef M_DEBUG
  5613. fprintf(stderr,"enter 'mlex' at %d\n", mfptr) ;
  5614. #endif
  5615. inmlex++;
  5616. mlook = look;
  5617. c = nextmac();
  5618. for (;;) {
  5619. int octo = 0, amp = 0, caret = 0;
  5620. if (c == '#' || c == '&' || c == '^') {
  5621. int esc = c;
  5622. c = nextmac();
  5623. if (charclass[c] != STARTER && charclass[c] != LETTER) {
  5624. if (esc != '&' || !ampdrop)
  5625. putm(esc);
  5626. ampdrop = 0;
  5627. continue;
  5628. }
  5629. if (esc == '#')
  5630. octo = 1;
  5631. else if (esc == '&')
  5632. amp = 1;
  5633. else
  5634. caret = 1;
  5635. }
  5636. switch(charclass[c]) {
  5637. case DIGIT:
  5638. while (numpart[c]) {
  5639. putm(c);
  5640. c = nextmac();
  5641. }
  5642. continue;
  5643. case STARTER:
  5644. case LETTER:
  5645. t = 0;
  5646. p = symbuf;
  5647. do {
  5648. if (p >= symbufmax) {
  5649. *symbufmax = '\0';
  5650. printf("was parsing '%s' in macro definition\n", tempbuf);
  5651. error(symlong);
  5652. }
  5653. *p++ = c;
  5654. if (t < MAXSYMBOLSIZE)
  5655. tempbuf[t++] = (c >= 'A' && c <= 'Z') ?
  5656. c+'a'-'A' : c;
  5657. c = nextmac();
  5658. } while (charclass[c]==LETTER || charclass[c]==DIGIT || charclass[c]==STARTER);
  5659. tempbuf[t] = 0;
  5660. *p++ = '\0';
  5661. p = symbuf;
  5662. key = keyword(tempbuf);
  5663. t = key ? key->i_token : 0;
  5664. param = item_lookup(tempbuf, paramtab, PARAMTABSIZE);
  5665. // Accept almost anything as a parameter. But a few
  5666. // keywords will just screw things up royally.
  5667. if (t != ENDM && t != REPT && t != IRPC && t != IRP && t != MACRO)
  5668. t = param->i_token;
  5669. // Caret escaping kills all expansion
  5670. // And interpretation of ENDM, etc. For better or worse.
  5671. if (caret)
  5672. t = 0;
  5673. if (t == MPARM) {
  5674. int pfx = octo || amp || c == '&';
  5675. // # prefix only allowed if declared that way
  5676. if (octo != param->i_scope)
  5677. t = 0;
  5678. else
  5679. octo = 0;
  5680. // Expansion in quoted strings only with prefix character.
  5681. if (quote && !pfx && !zcompat)
  5682. t = 0;
  5683. amp = 0; // parameter substitution, eat '&'
  5684. }
  5685. else if (t && quote)
  5686. t = 0;
  5687. if (ampdrop)
  5688. amp = 0;
  5689. ampdrop = c == '&' && t == MPARM;
  5690. if (octo) putm('#');
  5691. if (amp) putm('&');
  5692. if (t != MPARM) {
  5693. for (p = symbuf; *p; p++)
  5694. putm(*p);
  5695. }
  5696. else {
  5697. if (*(param->i_string) == '?' || param->i_chain)
  5698. putm('\2');
  5699. else
  5700. putm('\1');
  5701. putm(param->i_value + 'A');
  5702. }
  5703. if (t == ENDM) {
  5704. if (--inmlex == 0)
  5705. goto done;
  5706. }
  5707. else if (t == REPT || t == IRPC || t == IRP || t == MACRO) {
  5708. inmlex++;
  5709. }
  5710. continue;
  5711. case F_END:
  5712. errwarn(warn_general, "macro definition went until end of file");
  5713. if (expptr) {
  5714. popsi();
  5715. c = nextmac();
  5716. continue;
  5717. }
  5718. goto done;
  5719. default:
  5720. switch (c) {
  5721. case '\n':
  5722. quote = 0;
  5723. list1();
  5724. break;
  5725. case ';':
  5726. if (!quote) {
  5727. while (c != '\n' && c != 0) {
  5728. putm(c);
  5729. c = nextmac();
  5730. }
  5731. continue;
  5732. }
  5733. break;
  5734. case '\'':
  5735. case '"':
  5736. if (c == quote)
  5737. quote = 0;
  5738. else
  5739. quote = c;
  5740. break;
  5741. default:
  5742. break;
  5743. }
  5744. if (c != '\1' && c != '`') putm(c);
  5745. c = nextmac();
  5746. }
  5747. }
  5748. /*
  5749. * finish off the file entry
  5750. */
  5751. done:
  5752. while(c != EOF && c != '\n' && c != '\0') c = nextmac();
  5753. inmlex++;
  5754. list1();
  5755. inmlex--;
  5756. // WHY two newlines??
  5757. // putm('\n');
  5758. putm('\n');
  5759. putm(0);
  5760. // TODO - here's where we could save parameter names for MRAS
  5761. for (c = 0; c < PARAMTABSIZE; c++) {
  5762. if (paramtab[c].i_token == MPARM) {
  5763. free(paramtab[c].i_string);
  5764. paramtab[c].i_string = NULL;
  5765. paramtab[c].i_token = 0;
  5766. }
  5767. }
  5768. inmlex = 0;
  5769. #ifdef M_DEBUG
  5770. fprintf(stderr,"exit 'mlex' at %d\n", mfptr) ;
  5771. #endif
  5772. }
  5773. int str_getch(struct argparse *ap)
  5774. {
  5775. int ch = ap->user_peek;
  5776. if (ch >= 0) {
  5777. ap->user_peek = -1;
  5778. return ch;
  5779. }
  5780. if (!ap->user_ptr || ap->user_ptr[ap->user_int] == '\0')
  5781. return '\0';
  5782. return ap->user_ptr[ap->user_int++];
  5783. }
  5784. int arg_getch(struct argparse *ap)
  5785. {
  5786. (void)ap; // suppress warning
  5787. return nextchar();
  5788. }
  5789. void arg_start()
  5790. {
  5791. arg_reset();
  5792. arg_flag = 1;
  5793. }
  5794. void arg_reset()
  5795. {
  5796. arg_flag = 0;
  5797. arg_state.arg = tempbuf;
  5798. arg_state.argsize = sizeof tempbuf;
  5799. arg_state.peek = &peekc;
  5800. arg_state.getch = arg_getch;
  5801. arg_state.macarg = 0;
  5802. arg_state.user_ptr = 0;
  5803. arg_state.user_int = 0;
  5804. arg_state.didarg = 0;
  5805. arg_state.numarg = 0;
  5806. }
  5807. /*
  5808. * lexical analyser for the arguments of a macro call
  5809. */
  5810. int getarg(struct argparse *ap)
  5811. {
  5812. int c;
  5813. char *p;
  5814. int quote;
  5815. int depth;
  5816. *ap->arg = 0;
  5817. while (charclass[c = ap->getch(ap)] == SPACE);
  5818. switch(c) {
  5819. case '\0':
  5820. if (!ap->user_ptr)
  5821. popsi(); // a seemingly unlikely case?
  5822. case '\n':
  5823. case ';':
  5824. if (!ap->didarg && ap->numarg) {
  5825. *ap->peek = c;
  5826. ap->didarg = 1;
  5827. ap->numarg++;
  5828. return ARG;
  5829. }
  5830. ap->didarg = 0;
  5831. ap->numarg = 0;
  5832. return c;
  5833. case ',':
  5834. if (!ap->didarg) {
  5835. ap->didarg = 1;
  5836. *ap->peek = c;
  5837. ap->numarg++;
  5838. return ARG;
  5839. }
  5840. ap->didarg = 0;
  5841. return c;
  5842. case '\'':
  5843. case '\"':
  5844. quote = c;
  5845. p = ap->arg;
  5846. if (!zcompat)
  5847. *p++ = c;
  5848. do {
  5849. c = ap->getch(ap);
  5850. if (c == '\0' || c == '\n') {
  5851. *ap->peek = c;
  5852. *p = 0;
  5853. err[bflag]++;
  5854. ap->didarg = 1;
  5855. ap->numarg++;
  5856. return ARG;
  5857. }
  5858. else if (c == quote) {
  5859. if ((c = ap->getch(ap)) != quote) {
  5860. if (!zcompat)
  5861. *p++ = quote;
  5862. *ap->peek = c;
  5863. *p = '\0';
  5864. ap->didarg = 1;
  5865. ap->numarg++;
  5866. return ARG;
  5867. }
  5868. }
  5869. else
  5870. *p++ = c;
  5871. } while (p < ap->arg + ap->argsize - 1);
  5872. ap->arg[ap->argsize - 1] = '\0';
  5873. printf("was parsing macro argument '%s'\n", ap->arg);
  5874. error(symlong);
  5875. return 0; // not reached
  5876. case '<':
  5877. depth = 1;
  5878. p = ap->arg;
  5879. do {
  5880. c = ap->getch(ap);
  5881. if (c == '\0' || c == '\n') {
  5882. *ap->peek = c;
  5883. *p = 0;
  5884. err[bflag]++;
  5885. ap->didarg = 1;
  5886. ap->numarg++;
  5887. return ARG;
  5888. }
  5889. if (c == '>') {
  5890. depth--;
  5891. if (depth == 0) {
  5892. *p = '\0';
  5893. ap->didarg = 1;
  5894. ap->numarg++;
  5895. return ARG;
  5896. }
  5897. }
  5898. else if (c == '<')
  5899. depth++;
  5900. *p++ = c;
  5901. } while (p < ap->arg + ap->argsize - 1);
  5902. ap->arg[ap->argsize - 1] = '\0';
  5903. printf("was parsing macro argument '%s'\n", ap->arg);
  5904. error(symlong);
  5905. return 0; // not reached
  5906. default: /* unquoted string */
  5907. if (c == '%' && ap->macarg) {
  5908. ap->didarg = 1;
  5909. ap->numarg++;
  5910. return c;
  5911. }
  5912. p = ap->arg;
  5913. *ap->peek = c;
  5914. do {
  5915. c = ap->getch(ap);
  5916. switch(c) {
  5917. case '\0':
  5918. case '\n':
  5919. case '\t':
  5920. case ' ':
  5921. case ',':
  5922. *ap->peek = c;
  5923. *p = '\0';
  5924. ap->didarg = 1;
  5925. ap->numarg++;
  5926. return ARG;
  5927. case '^':
  5928. c = ap->getch(ap);
  5929. switch (c) {
  5930. case ',':
  5931. case '^':
  5932. case ' ':
  5933. case '\t':
  5934. *p++ = c;
  5935. break;
  5936. default:
  5937. *p++ = '^';
  5938. *ap->peek = c;
  5939. break;
  5940. }
  5941. break;
  5942. default:
  5943. *p++ = c;
  5944. }
  5945. } while (p < ap->arg + ap->argsize - 1);
  5946. ap->arg[ap->argsize - 1] = '\0';
  5947. printf("was parsing macro argument '%s'\n", ap->arg);
  5948. error("macro argument too long");
  5949. return 0; // not reached
  5950. }
  5951. }
  5952. /*
  5953. * add a suffix to a string
  5954. */
  5955. void suffix(char *str, char *suff)
  5956. {
  5957. strcpy(getsuffix(str), suff);
  5958. }
  5959. char *basename(char *filename)
  5960. {
  5961. char *base, *p;
  5962. base = filename;
  5963. for (p = filename; *p; p++) {
  5964. if (*p == '/' || *p == '\\') {
  5965. base = p + 1;
  5966. }
  5967. }
  5968. return base;
  5969. }
  5970. char *getsuffix(char *str)
  5971. {
  5972. char *suffix = 0;
  5973. str = basename(str);
  5974. for (; *str; str++) {
  5975. if (*str == '.')
  5976. suffix = str;
  5977. }
  5978. return suffix ? suffix : str;
  5979. }
  5980. // Construct output file given input path.
  5981. // Essentially files for "file.z" are sent to "zout/file.suffix".
  5982. // And for "dir/file.z" they are "zout/file.suffix"
  5983. void outpath(char *out, char *src, char *suff)
  5984. {
  5985. strcpy(out, "zout");
  5986. if (!suff)
  5987. return;
  5988. strcat(out, "/");
  5989. strcat(out, basename(src));
  5990. suffix(out, suff);
  5991. }
  5992. /*
  5993. * put out a byte to the macro file, keeping the offset
  5994. */
  5995. void putm(int c)
  5996. {
  5997. mfseek(mfile, mfptr, 0);
  5998. mfptr++;
  5999. mfputc(c, mfile);
  6000. }
  6001. /*
  6002. * get a byte from the macro file
  6003. */
  6004. int getm()
  6005. {
  6006. int ch;
  6007. mfseek(mfile, floc, 0);
  6008. floc++;
  6009. ch = mfgetc(mfile);
  6010. if (ch == EOF) {
  6011. ch = 0;
  6012. fprintf(stderr, "bad macro read\n");
  6013. }
  6014. return ch;
  6015. }
  6016. /*
  6017. * pop standard input
  6018. */
  6019. void popsi()
  6020. {
  6021. int i;
  6022. for (i=0; i<PARMMAX; i++) {
  6023. if (est[i].param) free(est[i].param);
  6024. }
  6025. floc = est[FLOC].value;
  6026. ifptr = est[MIF].param;
  6027. free(est);
  6028. expptr--;
  6029. est = expptr ? expstack[expptr-1] : 0;
  6030. mfseek(mfile, (long)floc, 0);
  6031. if (lineptr > linebuf) lineptr--;
  6032. }
  6033. /*
  6034. * return a unique name for a local symbol
  6035. * c is the parameter number, n is the macro number.
  6036. */
  6037. char *getlocal(int c, int n)
  6038. {
  6039. static char local_label[10];
  6040. invented++;
  6041. if (c >= 26)
  6042. c += 'a' - '0';
  6043. sprintf(local_label, "?%c%04d", c+'a', n) ;
  6044. return(local_label);
  6045. }
  6046. char *getmraslocal()
  6047. {
  6048. static char mras_local[32];
  6049. char *p = mras_local + sizeof mras_local - 1;
  6050. int n = est[TEMPNUM].value;
  6051. *p = '\0';
  6052. for (; n > 0; n /= 26)
  6053. *--p = 'A' + n % 26;
  6054. return p;
  6055. }
  6056. /*
  6057. * read in a symbol table
  6058. */
  6059. void insymtab(char *name)
  6060. {
  6061. struct stab *t;
  6062. int s, i;
  6063. FILE *sfile;
  6064. t = (struct stab *) tempbuf;
  6065. if (!(sfile = fopen(name, "rb")))
  6066. return;
  6067. fread((char *)t, 1, sizeof *t, sfile);
  6068. if (t->t_value != SYMMAJIC)
  6069. return;
  6070. s = t->t_token;
  6071. for (i=0; i<s; i++) {
  6072. fread((char *)t, 1, sizeof *t, sfile);
  6073. if (tokenofitem(UNDECLARED, 0, 0) != UNDECLARED)
  6074. continue;
  6075. yylval.itemptr->i_token = t->t_token;
  6076. yylval.itemptr->i_value = t->t_value;
  6077. if (t->t_token == MACRO)
  6078. yylval.itemptr->i_value += mfptr;
  6079. }
  6080. while ((s = fread(tempbuf, 1, TEMPBUFSIZE, sfile)) > 0) {
  6081. mfptr += s;
  6082. mfwrite(tempbuf, 1, s, mfile) ;
  6083. }
  6084. fclose(sfile);
  6085. }
  6086. /*
  6087. * write out symbol table
  6088. */
  6089. void outsymtab(char *name)
  6090. {
  6091. struct stab *t;
  6092. struct item *ip;
  6093. int i;
  6094. FILE *sfile;
  6095. t = (struct stab *) tempbuf;
  6096. if (!(sfile = fopen(name, "wb")))
  6097. return;
  6098. for (ip=itemtab; ip<itemmax; ip++) {
  6099. if (ip->i_token == UNDECLARED) {
  6100. ip->i_token = 0;
  6101. nitems--;
  6102. }
  6103. }
  6104. copyname(title, (char *)t);
  6105. t->t_value = SYMMAJIC;
  6106. t->t_token = nitems;
  6107. fwrite((char *)t, 1, sizeof *t, sfile);
  6108. for (ip=itemtab; ip<itemmax; ip++) {
  6109. if (ip->i_token != 0) {
  6110. t->t_token = ip->i_token;
  6111. t->t_value = ip->i_value;
  6112. copyname(ip->i_string, (char *)t);
  6113. fwrite((char *)t, 1, sizeof *t, sfile);
  6114. }
  6115. }
  6116. mfseek(mfile, (long)0, 0);
  6117. while((i = mfread(tempbuf, 1, TEMPBUFSIZE, mfile) ) > 0)
  6118. fwrite(tempbuf, 1, i, sfile);
  6119. fclose(sfile);
  6120. }
  6121. /*
  6122. * copy a name into the symbol file
  6123. */
  6124. void copyname(char *st1, char *st2)
  6125. {
  6126. char *s1, *s2;
  6127. int i;
  6128. i = (MAXSYMBOLSIZE+2) & ~01;
  6129. s1 = st1;
  6130. s2 = st2;
  6131. while((*s2++ = *s1++)) i--; /* -Wall-ishness :-) -RJM */
  6132. while(--i > 0) *s2++ = '\0';
  6133. }
  6134. /* get the next source file */
  6135. void next_source(char *sp)
  6136. {
  6137. if(now_in == NEST_IN -1)
  6138. error("Too many nested includes") ;
  6139. if ((now_file = open_incpath(sp, "r")) == NULL) {
  6140. char ebuf[1024] ;
  6141. sprintf(ebuf,"Can't open include file: %s", sp) ;
  6142. error(ebuf) ;
  6143. }
  6144. if (outpass && iflist()) {
  6145. lineout() ;
  6146. fprintf(fout, "**** %s ****\n",sp) ;
  6147. }
  6148. if (outpass && bopt)
  6149. fprintf(fbds, "%04x %04x f %s\n", dollarsign, emit_addr, sp);
  6150. /* save the list control flag with the current line number */
  6151. if (lstoff)
  6152. linein[now_in] = - linein[now_in] ;
  6153. /* no list if include files are turned off */
  6154. lstoff |= iopt ;
  6155. /* save the new file descriptor. */
  6156. fin[++now_in] = now_file ;
  6157. /* start with line 0 */
  6158. linein[now_in] = 0 ;
  6159. /* save away the file name */
  6160. src_name[now_in] = malloc(strlen(sp)+1) ;
  6161. strcpy(src_name[now_in],sp) ;
  6162. }
  6163. int phaseaddr(int addr)
  6164. {
  6165. if (!phaseflag)
  6166. return addr;
  6167. if (addr < phbegin || addr > dollarsign) {
  6168. err[vflag]++;
  6169. if (pass2)
  6170. fprintf(stderr, "$%04x outside current phase area\n", addr);
  6171. return 0;
  6172. }
  6173. return phdollar + (addr - phbegin);
  6174. }
  6175. // Include contents of named file as binary data.
  6176. void incbin(char *filename)
  6177. {
  6178. FILE *fp = open_incpath(filename, "rb");
  6179. int ch;
  6180. int start = dollarsign;
  6181. int last = start;
  6182. int bds_count;
  6183. if (!fp) {
  6184. char ebuf[1024];
  6185. sprintf(ebuf, "Can't binary include file: %s", filename);
  6186. error(ebuf);
  6187. return;
  6188. }
  6189. addtoline('\0');
  6190. if (outpass && bopt)
  6191. fprintf(fbds, "%04x %04x s %s", dollarsign, emit_addr, linebuf);
  6192. // Avoid emit() because it has a small buffer and it'll spam the listing.
  6193. bds_count = 0;
  6194. while ((ch = fgetc(fp)) != EOF) {
  6195. if (outpass && bopt) {
  6196. if (bds_count == 0)
  6197. fprintf(fbds, "%04x %04x d ", dollarsign, emit_addr);
  6198. fprintf(fbds, "%02x", ch);
  6199. bds_count++;
  6200. if (bds_count == 16) {
  6201. fprintf(fbds, "\n");
  6202. bds_count = 0;
  6203. }
  6204. }
  6205. if (segment == SEG_CODE)
  6206. setmem(emit_addr, ch, MEM_DATA);
  6207. emit_addr++;
  6208. emit_addr &= 0xffff;
  6209. last = dollarsign;
  6210. dollarsign++;
  6211. dollarsign &= 0xffff;
  6212. putbin(ch);
  6213. putrel(ch);
  6214. putout(ch);
  6215. }
  6216. if (outpass && bopt && bds_count)
  6217. fprintf(fbds, "\n");
  6218. fclose(fp);
  6219. // Do our own list() work as we emit bytes manually.
  6220. if (outpass && iflist()) {
  6221. lineout();
  6222. if (nopt)
  6223. fprintf(fout, "%4d:", linein[now_in]);
  6224. if (copt)
  6225. fprintf(fout, nopt ? "%5s-" : "%4s-", "");
  6226. if (nopt || copt)
  6227. fprintf(fout, "\t");
  6228. puthex(start >> 8, fout);
  6229. puthex(start, fout);
  6230. if (relopt)
  6231. fputc(SEGCHAR(segment), fout);
  6232. fprintf(fout, " .. ");
  6233. puthex(last >> 8, fout);
  6234. puthex(last, fout);
  6235. if (relopt)
  6236. fputc(SEGCHAR(segment), fout);
  6237. putc('\t', fout);
  6238. fputs(linebuf, fout);
  6239. lineptr = linebuf;
  6240. }
  6241. }
  6242. void dc(int count, int value)
  6243. {
  6244. int start = dollarsign;
  6245. int bds_count;
  6246. addtoline('\0');
  6247. if (outpass && bopt)
  6248. fprintf(fbds, "%04x %04x s %s", dollarsign, emit_addr, linebuf);
  6249. // Avoid emit() because it has a small buffer and it'll spam the listing.
  6250. bds_count = 0;
  6251. while (count-- > 0) {
  6252. if (outpass && bopt) {
  6253. if (bds_count == 0)
  6254. fprintf(fbds, "%04x %04x d ", dollarsign, emit_addr);
  6255. fprintf(fbds, "%02x", value);
  6256. bds_count++;
  6257. if (bds_count == 16) {
  6258. fprintf(fbds, "\n");
  6259. bds_count = 0;
  6260. }
  6261. }
  6262. if (segment == SEG_CODE)
  6263. setmem(emit_addr, value, MEM_DATA);
  6264. emit_addr++;
  6265. emit_addr &= 0xffff;
  6266. dollarsign++;
  6267. dollarsign &= 0xffff;
  6268. putbin(value);
  6269. putrel(value);
  6270. putout(value);
  6271. }
  6272. if (outpass && bopt && bds_count)
  6273. fprintf(fbds, "\n");
  6274. // Do our own list() work as we emit bytes manually.
  6275. if (outpass && iflist()) {
  6276. lineout();
  6277. if (nopt)
  6278. fprintf(fout, "%4d:", linein[now_in]);
  6279. if (copt)
  6280. fprintf(fout, nopt ? "%5s-" : "%4s-", "");
  6281. if (nopt || copt)
  6282. fprintf(fout, "\t");
  6283. puthex(start >> 8, fout);
  6284. puthex(start, fout);
  6285. if (relopt) {
  6286. fputc(SEGCHAR(segment), fout);
  6287. fprintf(fout, "..");
  6288. }
  6289. else
  6290. fprintf(fout, " .. ");
  6291. puthex((dollarsign - 1) >> 8, fout);
  6292. puthex((dollarsign - 1), fout);
  6293. if (relopt)
  6294. fputc(SEGCHAR(segment), fout);
  6295. putc(' ', fout);
  6296. puthex(value, fout);
  6297. putc('\t', fout);
  6298. fputs(linebuf, fout);
  6299. lsterr2(1);
  6300. lineptr = linebuf;
  6301. }
  6302. else
  6303. lsterr1();
  6304. }
  6305. #define OUTREC_SEG outbuf[outrec]
  6306. #define OUTREC_ADDR ((outbuf[outrec + 1] << 8) | outbuf[outrec + 2])
  6307. #define OUTREC_LEN outbuf[outrec + 3]
  6308. #define OUTREC_DATA outbuf[outrec + 4 + outlen]
  6309. #define OUTREC_SIZEOF 5
  6310. void new_outrec(void)
  6311. {
  6312. OUTREC_LEN = outlen;
  6313. outrec += OUTREC_SIZEOF + outlen;
  6314. outlen = 0;
  6315. OUTREC_SEG = segment;
  6316. outbuf[outrec + 1] = seg_pos[segment] >> 8;
  6317. outbuf[outrec + 2] = seg_pos[segment];
  6318. }
  6319. void putout(int value)
  6320. {
  6321. int addr = (OUTREC_ADDR + outlen) & 0xffff;
  6322. if (OUTREC_SEG != segment || addr != seg_pos[segment])
  6323. new_outrec();
  6324. if (pass2 && OUTREC_DATA != value && !passfail) {
  6325. char segname[2];
  6326. if (relopt)
  6327. sprintf(segname, "%c", SEGCHAR(segment));
  6328. else
  6329. segname[0] = '\0';
  6330. sprintf(detail, "%s error - $%04x%s changed from $%02x to $%02x",
  6331. errname[pflag], addr, segname, OUTREC_DATA, value);
  6332. errwarn(pflag, detail);
  6333. if (!outpass)
  6334. passretry = 1;
  6335. }
  6336. OUTREC_DATA = value;
  6337. outlen++;
  6338. if (outlen >= 256)
  6339. new_outrec();
  6340. advance_segment(1);
  6341. }
  6342. void advance_segment(int step)
  6343. {
  6344. int top = seg_pos[segment] += step;
  6345. seg_pos[segment] &= 0xffff;
  6346. if (top >= 0x10000)
  6347. top = 0xffff;
  6348. if (top > seg_size[segment])
  6349. seg_size[segment] = top;
  6350. }
  6351. void expr_reloc_check(struct expr *ex)
  6352. {
  6353. if (!relopt) return;
  6354. if (ex->e_scope & (SCOPE_EXTERNAL | SCOPE_NORELOC))
  6355. err[rflag]++;
  6356. }
  6357. void expr_number_check(struct expr *ex)
  6358. {
  6359. if (!relopt) return;
  6360. expr_reloc_check(ex);
  6361. if (ex->e_scope & SCOPE_SEGMASK)
  6362. err[rflag]++;
  6363. }
  6364. void expr_scope_same(struct expr *ex1, struct expr *ex2)
  6365. {
  6366. if (!relopt) return;
  6367. if ((ex1->e_scope & SCOPE_SEGMASK) != (ex2->e_scope & SCOPE_SEGMASK))
  6368. err[rflag]++;
  6369. }
  6370. void expr_word_check(struct expr *ex)
  6371. {
  6372. if (ex->e_value < -32768 || ex->e_value > 65535) {
  6373. err[vflag]++;
  6374. }
  6375. }
  6376. int is_number(struct expr *ex)
  6377. {
  6378. return ex && (ex->e_scope & ~SCOPE_PUBLIC) == 0;
  6379. }
  6380. int is_external(struct expr *ex)
  6381. {
  6382. return ex && (ex->e_scope & SCOPE_EXTERNAL) && !ex->e_left && !ex->e_right &&
  6383. ex->e_item;
  6384. }
  6385. struct expr *expr_alloc(void)
  6386. {
  6387. struct expr *ex = malloc(sizeof *ex);
  6388. ex->e_value = 0;
  6389. ex->e_scope = 0;
  6390. ex->e_token = 0;
  6391. ex->e_item = 0;
  6392. ex->e_left = 0;
  6393. ex->e_right = 0;
  6394. return ex;
  6395. }
  6396. struct expr *expr_num(int value)
  6397. {
  6398. struct expr *ex = expr_alloc();
  6399. ex->e_value = value;
  6400. ex->e_token = '0';
  6401. return ex;
  6402. }
  6403. // Expression consruction for operators that subtract/compare.
  6404. // They produce a valid result if operating on numbers in the same segment.
  6405. struct expr *expr_op_sc(struct expr *left, int token, struct expr *right, int value)
  6406. {
  6407. struct expr *ex = expr_op(left, token, right, value);
  6408. if (!(ex->e_scope & SCOPE_EXTERNAL) &&
  6409. ((left->e_scope ^ right->e_scope) & SCOPE_SEGMASK) == 0)
  6410. {
  6411. // Result relocatable and a simple number
  6412. ex->e_scope &= ~(SCOPE_NORELOC | SCOPE_SEGMASK);
  6413. }
  6414. return ex;
  6415. }
  6416. struct expr *expr_op(struct expr *left, int token, struct expr *right, int value)
  6417. {
  6418. struct expr *ex = expr_alloc();
  6419. ex->e_value = value;
  6420. ex->e_token = token;
  6421. ex->e_left = left;
  6422. ex->e_right = right;
  6423. // Combining two numbers will be fine as long as they're not
  6424. // flagged as external or already not relocatable. In which case
  6425. // it is up to the particular operator to allow the value
  6426. // to become valid.
  6427. ex->e_scope = left->e_scope;
  6428. if (left->e_scope & SCOPE_SEGMASK)
  6429. ex->e_scope |= SCOPE_NORELOC;
  6430. if (right) {
  6431. ex->e_scope |= right->e_scope;
  6432. if (right->e_scope & SCOPE_SEGMASK)
  6433. ex->e_scope |= SCOPE_NORELOC;
  6434. }
  6435. return ex;
  6436. }
  6437. void expr_free(struct expr *ex)
  6438. {
  6439. if (!ex)
  6440. return;
  6441. expr_free(ex->e_left);
  6442. expr_free(ex->e_right);
  6443. free(ex);
  6444. }
  6445. int synth_op(struct expr *ex, int gen)
  6446. {
  6447. if (ex->e_token == '&' && is_number(ex->e_right) &&
  6448. ex->e_right->e_value == 255)
  6449. {
  6450. if (gen) {
  6451. extend_link(ex->e_left);
  6452. putrelop(RELOP_LOW);
  6453. return 1;
  6454. }
  6455. return can_extend_link(ex->e_left);
  6456. }
  6457. return 0;
  6458. }
  6459. int link_op(struct expr *ex)
  6460. {
  6461. if (!ex)
  6462. return 0;
  6463. switch (ex->e_token) {
  6464. case HIGH: return RELOP_HIGH;
  6465. case LOW: return RELOP_LOW;
  6466. case '~': return RELOP_NOT;
  6467. case '-': return !ex->e_right ? RELOP_NEG : RELOP_SUB;
  6468. case '+': return RELOP_ADD;
  6469. case '*': return RELOP_MUL;
  6470. case '/': return RELOP_DIV;
  6471. case '%': return RELOP_MOD;
  6472. default: return 0;
  6473. }
  6474. }
  6475. int can_extend_link(struct expr *ex)
  6476. {
  6477. if (!ex)
  6478. return 1;
  6479. // If we have a value available then we're good.
  6480. if (!(ex->e_scope & SCOPE_NORELOC))
  6481. return 1;
  6482. // Might be able to synthesize the operation.
  6483. if (synth_op(ex, 0))
  6484. return 1;
  6485. // Otherwise, the operator must be supported and the children
  6486. // must be linkable.
  6487. return link_op(ex) && can_extend_link(ex->e_left) && can_extend_link(ex->e_right);
  6488. }
  6489. void extend_link(struct expr *ex)
  6490. {
  6491. int op;
  6492. if (!ex)
  6493. return;
  6494. if (synth_op(ex, 1))
  6495. return;
  6496. extend_link(ex->e_left);
  6497. extend_link(ex->e_right);
  6498. op = link_op(ex);
  6499. if (op) {
  6500. putrelop(op);
  6501. return;
  6502. }
  6503. putrelcmd(RELCMD_EXTLINK);
  6504. if (is_external(ex)) {
  6505. char *str = ex->e_item->i_string;
  6506. int len = strlen(str);
  6507. if (len > 6)
  6508. len = 6;
  6509. putrelbits(3, 1 + len);
  6510. putrelbits(8, 'B');
  6511. while (len-- > 0) {
  6512. int ch = *str++;
  6513. if (ch >= 'a' && ch <= 'z')
  6514. ch -= 'a' - 'A';
  6515. putrelbits(8, ch);
  6516. }
  6517. }
  6518. else {
  6519. putrelbits(3, 4);
  6520. putrelbits(8, 'C');
  6521. putrelbits(8, ex->e_scope & SCOPE_SEGMASK);
  6522. putrelbits(8, ex->e_value);
  6523. putrelbits(8, ex->e_value >> 8);
  6524. }
  6525. }
  6526. void putrelop(int op)
  6527. {
  6528. putrelcmd(RELCMD_EXTLINK);
  6529. putrelbits(3, 2);
  6530. putrelbits(8, 'A');
  6531. putrelbits(8, op);
  6532. }