@L}5 _$% l0$)$$Hȱ$ UhL" `e$$%`$%`  R@P!( L(1   Y I`  d  Ld M * @  $ % CC$$)%1 Udߥ$9%: !0 S$% DD˙`  }J)Lr  /* global defs for CC65 */ #define NULL 0 /* added by jrd. don't generate arg counts here */ #define NOARGC /* ... and ge}nerate entries with fixed arg counts */ #define FIXARGC #ifdef M6502 #define EOL 155 #define TABCHAR 127 #else #define EOL '}\n' #define TABCHAR '\t' #endif /* #define CRITIC 0x42 #define SDMCTL 0x22F #define DMACTL 0xD400 #define CH 0x2FC #defi}ne MEMLO 0x2E7 */ #define HTABSZ 128 #define MACARGSZ 64 #define MAXFILES 3 #define MAXTYPELEN 30 #define N_IFDEF 5 /* #d}efine LITLAB 1 */ extern int litlab; /* current one */ extern int litspace; /* total string space used */ #ifdef M6502 / }* native compiler */ /* #define GSPACE 7000 */ /* #define GSPACE 2200 -- now it's dynamically allocated */ #define LSPACE }256 #define HTSTART 0x0500 #define MASTART 0x0480 #define MHTSTART 0x0600 #define OUTQSZ 500 /* declare some vars to be }on page 0. see ccpage0.m65 */ #define CCPAGE0 1 #else /* cross-compiler... */ #define GSPACE 10000 #define LSPACE 4800 # }define OUTQSZ 8000 #define printmsg printf #endif /* * storage classes */ #define SC_STATIC 0x00 #define SC_STACK 0x01 }#define SC_STORAGE 0x02 #define SC_ONSTACK 0x03 #define SC_INMEM 0x02 #define SC_DEFINED 0x04 #define SC_EXTERN 0x08 #define }SC_ENUM 0x10 #define SC_DEFAULT 0x40 #define SC_STRUCT 0x80 #define SC_SFLD 0x80 #define SC_STAG 0x81 /* data types */ }#define T_END '\0' #define T_CHAR 0x11 #define T_INT 0x12 #define T_SHORT 0x13 #define T_LONG 0x14 #define T_ENUM 0x15 }#define T_UCHAR 0x19 #define T_UINT 0x1A #define T_FLOAT 0x25 #define T_DOUBLE 0x26 #define T_FUNC 0x07 #define T_UNSIGNE}D 0x08 #define T_INTEGER 0x10 #define T_REAL 0x20 #define T_POINTER 0x40 #define T_PTR 0x49 #define T_ARRAY 0x4A #define T}_STRUCT 0x80 #define T_UNION 0xC0 #define T_SMASK 0x3F #define E_MGLOBAL 0x80 #define E_MLOCAL 0x40 #define E_MCONST 0x20 }#define E_MEXPR 0x10 #define E_MEOFFS 0x11 #define E_MCTYPE 0x07 #define E_TCONST 0 #define E_TGLAB 1 #define E_TLIT 2 #de}fine E_TLOFFS 3 /* jrd added these defs as values for the e_test field of a struct expent. The idea is that internals of} the expr parsers will set the e_test slot of a struct expent to one of these values. 0 means no specific test info, d}o it the old way. */ /* expr has already set cond codes apropos result value */ #define E_CC 1 /* if expr has NOT se}t CC, force a test-style access */ #define E_TEST 2 /* expr has left a logical value (1 or 0) in AX */ #define E_LOGL 4 } /* flip this bit to invert sense of test */ #define E_XINV 8 #define NAMESIZE 9 #define NAMEMAX 8 #define wqtabsz 128} #define wqsiz 6 #define wqmax wq+wqtabsz-wqsiz #define wqsym 0 #define wqsp 1 #define wqloop 2 #define wqlab 3 #define} wqinc 4 #define wqstat 5 #define litabsz 512 #define litmax litabsz-1 #ifdef M6502 #define linesize 100 #else #define l}inesize 200 #endif #define linemax linesize-1 #define mpmax linemax struct hashent { struct hashent * h_ptr; char h_}glb; char h_loc; char * h_gtptr; char * h_ltptr; struct hashent * h_link; int h_gdata; int h_ldata; char h_name}[1]; }; /* not used anymore?... struct kw { char * t_sym; char t_value; char t_next; }; */ /* used by newp}re.c and newcmd.c. sort of like op_alist... */ struct tok_elt { char * toknam; int toknbr; }; struct expent { /* th}is used to be just an int. jrd split it into two bytes, in order to have an extra field for tests without taking up } any more space ... int e_flags; */ unsigned char e_flags; unsigned char e_test; char * e_tptr; int e_con!}st; }; struct filent { #ifdef old_cruft int f_iocb; #else FILE * f_iocb; #endif char * f_name; int f_ln; }; extern"} char litq[]; extern char macltab[256]; extern int wq[wqtabsz]; extern struct hashent * lvtab[128]; extern char outq[OUTQ#}SZ]; #ifdef M6502 #define htab ((struct hashent ** ) HTSTART) #define macarg ((char ** ) MASTART) #define machtab ((char$} ** ) MHTSTART) #else extern struct hashent * htab[HTABSZ]; extern char * macarg[MACARGSZ]; extern char * machtab[HTABSZ]%}; #endif extern int absdecl; /* extern int critic; */ extern int glblbl; /* extern char glbspace[GSPACE]; */ extern char *&} gblspace; /* global heap */ extern char * gblend; /* gblspace limit */ extern struct hashent * glvptr; extern char * gsptr'}; extern int hashval; extern int i_ifdef; extern char locspace[LSPACE]; extern int lovptr; extern char * lsptr; extern char m(}acdef; /* T if any defines defined */ extern char * outqi; extern int outqsz; /* extern int ret_addr; */ extern char s_ifdef)}[N_IFDEF]; extern int tbllen; extern char * tblptr; extern char * type_char; extern char * type_int; extern char * type_ifunc*}; extern int * wqptr; extern char * line; extern char * mline; extern int litptr; extern char * lptr; extern char * mptr; ex+}tern int nxtlab, oursp, argstk, ncmp, errcnt, eof, glbflag; extern struct filent filetab[MAXFILES]; extern int ifile; ,} /* #ifdef M6502 extern int inp; extern int output; #else */ extern FILE * inp; extern FILE * output; /* #endif */ extern in-}t ln; extern char * fin; #ifdef M6502 extern char fname[20]; #else extern char fname[80]; #endif extern int curtok; extern .}int curval; extern int nxttok; extern int nxtval; extern char optimize; /* optimize flag */ extern char verbose; /* verbose /}flag */ extern int n_funargs; /* n args in function def */ extern int asm_kludge; /* kludge for #asm processing */ extern cha0}r * incl_dir; /* dir for include files */ /* extern char get_test; /* flag for getmem */ #ifndef M6502 extern char source; 1}/* put source in m65 file as comments */ #endif char * Gmalloc(); char * Lmalloc(); #ifdef M6502 /* use jrd's hand-coded ti2}ny printf */ #define printf tprintf #endif #ifndef M6502 #define dbgprintf(foo,bar) {} #endif /* this struct added by jrd, 3}used in unified code-generation stuff. see exp1, exp2, exp3. */ struct op_alist { int tok; /* token representing op 4}*/ int (* gen)(); /* generator function that goes with it */ }; /* end of global file for cc */ /* token representing op d /* cclex.h - token definitions */ #define CEOF 0 /* #define ASM 40 */ #define CASE 41 #define DEFAULT 42 #defin6}e BREAK 43 #define CONTINUE 44 #define ELSE 45 /* what the fuck's this? #define ENTRY 46 */ #define DO 30 #define 7}FOR 31 #define GOTO 32 #define IF 33 #define RETURN 34 #define SWITCH 35 #define WHILE 36 #define SIZEOF 100 #8}define IDENT 50 #define SEMI 51 /* * primary operators */ #define LBRACK 52 #define LPAREN 53 #define DOT 54 #de9}fine PREF 55 #define LCURLY 56 #define RBRACK 57 #define COMP 58 #define INC 59 #define PASGN 60 #define PLUS 61 #:}define COMMA 62 #define DEC 63 #define SASGN 64 #define RCURLY 65 #define MINUS 66 #define MASGN 67 #define STAR 68 #d;}efine DASGN 69 #define DIV 70 #define DAMP 71 #define AASGN 72 #define AMP 73 #define NE 74 #define BANG 75 #define DB<}AR 76 #define OASGN 77 #define BAR 78 #define EQ 79 #define ASGN 80 #define SLASGN 81 #define ASL 82 /* * inequaliti=}es */ #define LE 83 #define LT 84 #define GE 85 #define GT 86 #define SRASGN 87 #define ASR 88 #define XOASGN >}89 #define XOR 90 #define MOASGN 91 #define MOD 92 #define QUEST 93 #define COLON 94 #define RPAREN 95 #define SCONST ?}96 #define ICONST 97 #define CCONST 98 #define FCONST 99 #define CHAR 20 #define INT 21 #define DOUBLE 22 #define@} FLOAT 23 #define LONG 24 #define UNSIGNED 25 #define SHORT 26 #define STRUCT 27 #define UNION 28 #define VOID 29A} #define ENUM 101 #define FNAME 102 #define LINENO 103 #ifndef M6502 #define AUTO 10 #endif #define EXTERN B}11 #define REGISTER 12 #define STATIC 13 /* never used? #define TYPEDEF 14 */ #define ERROR (-1) ine EXTERN q; ; misc hand-coded things ; .globl _abtchk ; no-op for now _abtchk: rts ; ; bzero(ptr, nbytes) ; .globl _bzD}ero _bzero: jsr popax ; get nbytes sta tmp1 stx tmp2 jsr popax ; get ptr sta ptr1 stx ptr1+1 lda #0 bz1: E}ldx tmp2 ; get nbytes^ beq bz3 ; zero, try lo ldy #0 bz2: sta (ptr1),y ; zap a byte iny bne bz2 inc ptr1+1 ; F}bump ptr^ dec tmp2 ; dec nbytes^ bne bz1 ; around again bz3: ldy tmp1 beq bz5 ldy #0 bz4: sta (ptr1),y ; zap G}a byte iny cpy tmp1 ; done? bne bz4 bz5: rts ; ; our own isalpha routine, cloned from the library one, accepts H} ; underbars too ; .globl _is_alpha _is_alpha: jsr popax ; get the char cmp #'_' ; underbar? beq yup cmp #'A' I} bcc nope ; if less than 'A', return 0 cmp #'Z+1 bcc yup cmp #'a bcc nope cmp #'z+1 bcs nope yup: lda #1 rtJ}s nope: lda #0 rts A', return 0 cmp #'Z+1 bcc yup cmp #'a bcc nope cmp #'z+1 bcs nope yup: lda #1 rt; ; defs for some popular vars on page 0 for CC65. doing things this ; way reduces code volume, and increases speed slight L}ly. ; ; #define CCPAGE0 in ccg.h to make this happen. assemble cc65 modules ; with this file, as "ra65 -o foo.obj ccpag M}e0.m65 foo.m65" ; ; update this file if global.m65 changes!! ; _curtok = $98 _curval = $9A _nxttok = $9C _nxtval = $9E N} _absdecl = $A0 _glblbl = $A2 _gsptr = $A4 _hashval = $A6 _lovptr = $A8 _lsptr = $AA _macdef = $AC _outqi = $AE _out O}qsz = $B0 _tbllen = $B2 _tblptr = $B4 _wqptr = $B6 _litptr = $B8 _lptr = $BA _mptr = $BC _oursp = $C0 _argstk = $ P}C2 ; ; defs for things in global.m65. keep them in sync!!! ; ptr1 = $8C ptr2 = $8E ptr3 = $90 tmp1 = $92 tmp2 = $9 Q}3 tmp3 = $94 tmp4 = $95 ; ; temps usable in hand-bummed compiler routines ; ptr4 = $C4 ; ; that's all for now... ; R} tmp3 = $94 tmp4 = $95 ; ; temps usable in hand-bummed compiler routines ; ptr4 = $C4 ; ; that's all for now... ;  Nov 18 00:29:36 1989 (Jrd at local) * Version 1.1 released. * make8 Put base address back at #x2600. Teach how tT}o make cc65-src.arc. * main.c (main) Teach arg parser about -I, for include dir. Nov 17 20:45:02 1989 (Jrd at locaU}l) * main.c (ptype) Teach this about T_UCHAR and T_UINT. * symtab.c (SizeOf) Include T_UCHAR in case. * main.c (gettyV}pe) Return T_UCHAR for unsigned char. * glb.c (parseinit) Use char_t_p. Include unsigned char and int types in case. *W} code-gen.c (getmem) Use char_t_p. Nov 17 09:58:38 1989 (unknown at local) * code-gen.c Add new fun lda_helper, tX}o generate signed/unsigned loads correctly. * Start exp version 1.1. at local) * code-gen.c Add new fun lda_helper, tJ/* Code generator routines for CC65. These are called by various parts of the compiler to generate primitive operationZ}s. */ #include #include "cc65.h" #define UNSIGNED_FIX /* output a string */ #ifdef not_M6502 /* defined in xobj.[}m65 */ #else static char xxc; ot(str) char * str; { while (xxc = *str) { outchar(xxc); ++str; } } #end\}if #ifdef M6502 /* defined in xobj.m65 */ #else nl() { outchar('\n'); } #endif /* output a string, add a newline */ #ifd]}ef M6502 /* defined in xobj.m65 */ #else ol(str) { ot(str); nl(); } #endif #ifdef M6502 /* defined in xobj.m65 */ #else^} oljsr(str) char * str; { ot("\tjsr\t"); ol(str); } #endif oljsrpop(str) char * str; { oljsr(str); popsp(); } /* h_}elper for konst1 */ olstrdnl(str, num) char * str; int num; { ot(str); outdecnl(num); } static char lda[] = "\tlda\t#"; `}static char ldx[] = "\tldx\t#"; #ifdef M6502 extern int xxint; extern char xxhi, xxlo; #asm _xxint: _xxlo: .byte 0 _xxhi: .a}byte 0 #endasm #else static char xxhi, xxlo; #endif /* load konst into AX in such a way as to set cond codes correctly */ olb}xxxhi() { olstrdnl(ldx, xxhi); } olxxxlo() { olstrdnl(lda, xxlo); } konst1(k) int k; { #ifdef M6502 xxint = k; #else c} xxhi = k >> 8; xxlo = k & 0xFF; #endif if (xxhi == xxlo) { olxxxlo(); ol("\ttax"); } else if (xxhd}i) { olxxxlo(); olxxxhi(); } else { olxxxhi(); olxxxlo(); /* this loses some; generatese} spurious negative... */ } } konst3(k) int k; { #ifdef M6502 flushout(); /* keep output buf from filling up */ #endif}f olstrdnl("\tldy\t#", k); } char efn[] = {'e', 'n', 't', 'e', 'r', 'f', 'u', 'n'}; char efn_n = ' '; char efn_0 = 0; stag}rtfun(name) char * name; { #ifndef M6502 if (n_funargs == -1) printf("Internal error! no argcount?\n"); #endif outgblh}c(name); /* print a global name with colon */ if (findmac("FIXARGC")) efn_n = n_funargs + '0'; else efn_n = 0; i}oljsr(efn); } /* util function */ int char_t_p(tptr) char * tptr; { return ((tptr[0] & ~T_UNSIGNED) == T_CHAR); } /* Fetcj}h a static memory cell into the primary register */ getmem(lbl, tptr, test_p) /* jrd added test_p */ char * lbl; char * tptr;k} char test_p; { if (char_t_p(tptr)) { /* load X with a 0. later deal with sgn ext */ /* if (test_p) /* only loadl} 0 in X if not testing */ { ol("\tldx\t#0"); } ot("\tlda\t"); /* load A from the label */ outgblnl(m}lbl); } else /* loading word-sized thing */ { ot("\tlda\t"); outgblnl(lbl); if (test_p) n} ot("\tora\t"); else { ot("\tldx\t"); } outgbl(lbl); ol("+1"); } } /* and ao}nother... */ static konst3s(offs) int offs; { konst3(offs - oursp); } #ifdef UNSIGNED_FIX /* this is another helper fup}n for generating the right variant of ldaxxx frob. given a typespec and an extension, generate "lda" followed by q} for signed char, 'u' for unsigned char, or 'x' for fixnum */ lda_helper(typestring, ext) unsigned char * typer}string; char * ext; { ot("\tjsr\tlda"); if (char_t_p(typestring)) /* some kind of char-sized thing? */ { if (tys}pestring[0] & T_UNSIGNED) outchar('u'); /* call unsigned variant */ } else outchar('x'); /* call word-sized varit}ant */ ol(ext); } #endif /* getladr( offs ) Fetch the address of the specified symbol into the primary register */ gu}etladr(offs) int offs; { konst3s(offs); /* load Y with offset value */ oljsr("locysp"); /* and compute location of SP@(v}Y) */ } /* getloc( offs, tptr ) Fetch specified local object (local var). */ getloc(offs, tptr) int offs; char * tptr; {w} konst3s(offs); /* load Y with offset value */ #ifdef old_way if (tptr[0] == T_CHAR) oljsr("ldaysp"); /* load a bytx}e from SP@(Y) */ else oljsr("ldaxysp"); /* load a word from SP@(Y) */ #else #ifdef UNSIGNED_FIX lda_helper(tptr, "ysy}p"); #else oljsr((char_t_p(tptr) ? "ldaysp" : "ldaxysp")); #endif #endif } /* putloc( offs, tptr ) Put data into localz} object. */ putloc(offs, tptr) int offs; char * tptr; { konst3s(offs); /* load Y with offset value */ #ifdef old_way if {}(tptr[0] == T_CHAR) oljsr("staysp"); /* load a byte from SP@(Y) */ else oljsr("staxysp"); /* load a word from SP@|}(Y) */ #else oljsr((char_t_p(tptr) ? "staysp" : "staxysp")); #endif } /* Store the primary register into the specified }} static memory cell */ putmem(lab, tptr) char * lab; char * tptr; { ot("\tsta\t"); outgblnl(lab); if (!char_t_p(tptr))~} { ot("\tstx\t"); outgbl(lab); ol("+1"); } } /* putstk( tptr ) Store the specified object type} in the primary register at the address on the top of the stack */ putstk(lval) struct expent * lval; { if ((lval->e_flag}s == E_MEOFFS) && /* some kind of structure */ (lval->e_const != 0)) /* and not first slot... */ { konst3(lva}l->e_const); /* load Y with structure offset */ #ifdef old_way if (lval->e_tptr[0] == T_CHAR) oljsr("staspidx"); /* st}ore A at ((SP))+Y */ else oljsr("staxspidx"); /* store AX at ((SP))+Y */ #else oljsr((char_t_p(lval->e_tptr) ? "}staspidx" : "staxspidx")); #endif } else { #ifdef old_way if (lval->e_tptr[0] == T_CHAR) oljsr("staspp"); /*} store A at ((SP)) */ else oljsr("staxspp"); /* store AX at ((SP)) */ #else oljsr((char_t_p(lval->e_tptr) ? "sta}spp" : "staxspp")); #endif } popsp(); } /* indirect( lval ) Fetch the specified object type indirect through the } primary register into the primary register */ indirect(lval) struct expent * lval; { if ((lval->e_flags == E_MEOFFS) && /*} some kind of structure */ (lval->e_const != 0)) /* and not slot 0 */ { konst3(lval->e_const); /* load Y with} offset */ #ifdef old_way if (lval->e_tptr[0] == T_CHAR) oljsr("ldaidx"); /* load A from AX@(Y) */ else oljsr("}ldaxidx"); /* load AX from AX@(Y) */ #else #ifdef UNSIGNED_FIX lda_helper(lval->e_tptr, "idx"); #else oljsr((char}_t_p(lval->e_tptr) ? "ldaidx" : "ldaxidx")); #endif #endif } else { #ifdef old_way if (lval->e_tptr[0] == T_C}HAR) oljsr("ldai"); /* load A from AX@ */ else oljsr("ldaxi"); /* load AX from AX@ */ #else #ifdef UNSIGNED_FIX } lda_helper(lval->e_tptr, "i"); #else oljsr((char_t_p(lval->e_tptr) ? "ldai" : "ldaxi")); #endif #endif } } /* } swap() Swap the primary and secondary registers */ #if 0 /* not used? */ #ifdef M6502 /* defined in xobj.m65 */ #else swa}p() { oljsr("swaptos"); } #endif #endif /* save() Copy AX to hold register. */ #ifdef M6502 /* defined in xobj.m65 */} #else save() { oljsr("saveax"); } #endif /* rstr() Copy hold register to P. */ #ifdef M6502 /* defined in xobj.m65 *}/ #else rstr() { oljsr("restax"); } #endif /* immed() Print partial instruction to get an immediate value into the }primary register. */ immed() { ot("\tldax\t#"); } /* added by jrd. force a test to set cond codes right */ #ifdef M6502 /}* defined in xobj.m65 */ #else tst() { oljsr("tstax"); } #endif /* push() Push the primary register onto the stack */} push() { oljsr("pushax"); pushsp(); } push1() { /* what's the difference? */ #ifndef M6502 ol(";; push1"); #endif p}ush(); } /* Swap the primary register and the top of the stack */ #ifdef M6502 /* defined in xobj.m65 */ #else swapstk() { } oljsr("swapstk"); } #endif /* Call the specified subroutine name */ call(lbl, narg) /* int lbl; -- not any more */ char *} lbl; int narg; { if (!findmac("NOARGC")) /* don't generate argc if suppressed */ konst3(narg >> 1); /* want n args, n}ot nbytes args */ ot("\tjsr\t"); outgblnl(lbl); oursp = oursp + narg; /* callee pops args */ #ifdef M6502 flushout(}); /* keep output buf from filling up */ #endif } /* Return from subroutine */ ret() { ol("\tjmp\texitfun"); } /* Per}form subroutine call to value on top of stack. This really calls value in AX */ callstk(narg) int narg; { if (!findmac("}NOARGC")) /* don't generate argc if suppressed */ konst3(narg >> 1); /* load Y with arg count */ oljsr("callax"); /* }do the call */ oursp = oursp + narg; /* callee pops args */ /* popsp(); /* pop subr addr */ #ifdef M6502 flushout(); } /* keep output buf from filling up */ #endif } /* Jump to specified internal label number */ jump(label) int label; { ot}("\tjmp\t"); outlabnl(label); } /* output case-jump preample */ #ifdef M6502 /* defined in xobj.m65 */ #else casejump() { } oljsr("casejump"); } #endif /* truejump -- jump to lable if p nz */ truejump(label, invert) int label; int invert; /*} jrd added this */ { #ifndef M6502 ol(";;; truejump"); #endif if (invert) falsejump(label, 0); else { ot(}"\tlbne\t"); outlabnl(label); } } /* falsejump -- jump to lable if AX is zero */ falsejump(label, invert) int la}bel; int invert; /* jrd added this */ { #ifndef M6502 ol(";;; falsejump"); #endif if (invert) truejump(label, 0); e}lse { ot("\tlbeq\t"); outlabnl(label); } } /* cmpjump -- compare p to constant and jump not-equal to} label */ /* cmpjump(constant, label) int constant; int label; { ol(";;; cmpjump"); } */ /* Modify the stack pointer to }the new value indicated */ otx(str) char * str; { ot("\tjsr\t"); ot(str); ot("sp"); } mod_internal(k, verb1, verb2) }int k; char * verb1, * verb2; { if (k <= 8) { otx(verb1); outchar(k + '0'); } else { konst3}(k); otx(verb2); } nl(); } modstk(newsp) int newsp; { int k; if ((k = (newsp - oursp)) > 0) { mod_i}nternal(k, "inc", "addy"); } else if (k < 0) { mod_internal(-k, "dec", "suby"); } return (newsp); } /*} Double the primary register */ #ifdef M6502 /* defined in xobj.m65 */ #else doublereg() { oljsr("aslax"); } #endif /* }Add the primary and secondary registers (results in primary) */ #ifdef M6502 /* defined in xobj.m65 */ #else add() { /* } oljsr("addtos"); popsp(); /* zzz is this still right??? */ oljsrpop("addtos"); } #endif /* Subtract the primary r}egister from the secondary (results in primary) */ #ifdef M6502 /* defined in xobj.m65 */ #else sub() { /* oljsr("subtos}"); popsp(); */ oljsrpop("subtos"); } #endif /* Multiply the primary and secondary registers (results in primary }*/ #ifdef M6502 /* defined in xobj.m65 */ #else mult() { /* oljsr("multos"); popsp(); */ oljsrpop("multos"); } #endif } /* Divide the secondary register by the primary (quotient in primary, remainder in secondary) */ #ifdef M6502 /* defin}ed in xobj.m65 */ #else div() { /* oljsr("divtos"); popsp(); */ oljsrpop("divtos"); } #endif /* Compute remainder (}mod) of secondary register divided by the primary (remainder in primary, quotient in secondary) */ #ifdef M6502 /* defined }in xobj.m65 */ #else mod() { /* oljsr("modtos"); popsp(); */ oljsrpop("modtos"); } #endif /* Inclusive 'or' the pr}imary and the secondary registers (results in primary) */ #ifdef M6502 /* defined in xobj.m65 */ #else or() { /* oljsr(}"ortos"); popsp(); */ oljsrpop("ortos"); } #endif /* Exclusive 'or' the primary and seconday registers (results in} primary) */ #ifdef M6502 /* defined in xobj.m65 */ #else xor() { /* oljsr("xortos"); popsp(); */ oljsrpop("xortos"); }} #endif /* 'And' the primary and secondary registers (results in primary) */ #ifdef M6502 /* defined in xobj.m65 */} #else and() { /* oljsr("andtos"); popsp(); */ oljsrpop("andtos"); } #endif /* Arithmetic shift right the secondary} register number of times in primary (results in primary) */ #ifdef M6502 /* defined in xobj.m65 */ #else asr() { /* ol}jsr("asrtos"); popsp(); */ oljsrpop("asrtos"); } #endif /* Arithmetic left shift the secondary register number of }times in primary (results in primary) */ #ifdef M6502 /* defined in xobj.m65 */ #else asl() { /* oljsr("asltos"); popsp(}); */ oljsrpop("asltos"); } #endif /* Form two's complement of primary register */ #ifdef M6502 /* defined in xobj.m65 */} #else neg() { oljsr("negax"); } #endif /* Form logical complement of primary register */ #ifdef M6502 /* defined in xobj}.m65 */ #else lneg() { oljsr("lnegax"); } #endif /* Form one's complement of primary register */ #ifdef M6502 /* defined }in xobj.m65 */ #else com() { oljsr("complax"); } #endif /* Increment the primary register by one */ #ifdef M6502 /* defin}ed in xobj.m65 */ #else inc() { oljsr("incax1"); } #endif /* Decrement the primary register by one */ #ifdef M6502 /* def}ined in xobj.m65 */ #else dec() { oljsr("decax1"); } #endif /* Following are the conditional operators They compare} the secondary register against the primary and put a literal 1 in the primary if the condition is true, otherwise they} clear the primary register */ /* Test for equal */ #ifdef M6502 /* defined in xobj.m65 */ #else eq() { /* oljsr("toseqax}"); popsp(); */ oljsrpop("toseqax"); } #endif /* zero-p */ #ifdef M6502 /* defined in xobj.m65 */ #else eq0() { /* ol}jsr("axzerop"); popsp(); ... bug??? */ oljsr("axzerop"); } #endif /* Test for not equal */ #ifdef M6502 /* defined in x}obj.m65 */ #else ne() { /* oljsr("tosneax"); popsp(); */ oljsrpop("tosneax"); } #endif /* Test for less than */ lt(un}s) int uns; /* unsigned_p */ { /* oljsr(uns ? "tosultax" : "tosltax"); popsp(); */ oljsrpop(uns ? "tosultax" : "toslt}ax"); } /* Test for less than or equal to */ le(uns) int uns; /* unsigned_p */ { /* oljsr(uns ? "tosuleax" : "tosleax"); } popsp(); */ oljsrpop(uns ? "tosuleax" : "tosleax"); } /* Test for greater than */ gt(uns) int uns; /* unsigned_p */ { /}* oljsr(uns ? "tosugtax" : "tosgtax"); popsp(); */ oljsrpop(uns ? "tosugtax" : "tosgtax"); } /* Test for greater than }or equal to */ ge(uns) int uns; /* unsigned_p */ { /* oljsr(uns ? "tosugeax" : "tosgeax"); popsp(); */ oljsrpop(uns ? }"tosugeax" : "tosgeax"); } #ifdef old_cruft ...no longer need unsigned stuff... /* Test for less than (unsigned) */ ult() { } oljsr("tosultax"); popsp(); } /* Test for less than or equal to (unsigned) */ ule() { oljsr("tosuleax"); popsp(); } } /* Test for greater than (unsigned) */ ugt() { oljsr("tosugtax"); popsp(); } /* Test for greater than or equal to (unsi}gned) */ uge() { oljsr("tosugeax"); popsp(); } #endif #ifdef busted static char dollr = '$'; static char xdig[4]; stati}c char xd0 = '\0'; #endif outdec(numbr) int numbr; { char digit[8]; int i; #ifdef busted /* use bummed assembler routine */ }/* OOps! Can't use itoa here, cause it uses the FP routines, and they trash page 5, which we use for the symbol table. pr}int it in hex. itoa(numbr, digit); */ digit[0] = '$'; for (i = 3; i >= 0; --i) { xdig[i] = (numbr & 0x0F) + '}0'; numbr >> = 4; } /* ot(digit); */ ot(&dollr); #else if (numbr < 0) { numbr = -numbr; outch}ar('-'); } digit[0] = 0; for (i = 0; numbr > 0;) { digit[i] = numbr % 10; numbr = numbr / 10; +}+i; } if (i == 0) i = 1; while (i > 0) outchar(digit[--i] + '0'); #endif } outdecnl(n) int n; { outdec(n);} nl(); } outcch(numbr) int numbr; { outdec(numbr); } outlab(lbl) int lbl; { outchar('L'); outdec(lbl); } outlabnl(}lbl) char * lbl; { outlab(lbl); nl(); } outcdf(labl) int labl; { outlab(labl); ol(":"); } outdat(n) int n; { ol("};;; outdat"); } outslt(n) int n; { /* this seems to get used for constant string values? */ outlab(litlab); /* output curr}ent lit pool labl */ outchar('+'); outdec(n); nl(); } /* reserve static storage, n bytes */ outsp(n) int n; { ot("\t}.blkb\t"); outdec(n); nl(); #ifdef M6502 flushout(); #endif } /* output a row of bytes as a constant */ outbv(bytes, n}bytes) char * bytes; int nbytes; { int bpl; while (nbytes) { flushout(); /* keep output buf from overflowing */ } nbytes -= (bpl = (nbytes > 16) ? 16 : nbytes); bytepref(); kludge1: outdec(*bytes++); if (--bpl) } { outchar(','); goto kludge1; } outchar('\n'); } } /* prefix for word-sized constant */ wordpref() { ot(}"\t.word\t"); } /* prefix for byte-sized constant */ bytepref() { ot("\t.byte\t"); } /* print a global name into the asm }file. This probly supercedes the one below... */ outgbl(name) char * name; { outchar('_'); ot(name); } outgblnl(name}) { outgbl(name); nl(); } outgblc(name) char * name; { outgbl(name); ol(":"); } /* output a global or external name} */ outgoe(sname) char * sname; { ot("\t.globl\t"); outgblnl(sname); #ifdef M6502 flushout(); #endif } #ifdef M6502 /}* defined in xobj.m65 */ #else popsp() { return (oursp += 2); } #endif #ifdef M6502 /* defined in xobj.m65 */ #else pushs}p() { return (oursp -= 2); } #endif { return (oursp += 2); } #endif #ifdef M6502 /* defined in xobj.m65 */ #else pushs' CC65 ---- This is the (c) copyright notice for RA65, LINK65, LIBR65, and other Atari 8-bit programs. Said programs a}re Copyright 1989, by John R. Dunning. All rights reserved, with the following exceptions: Anyone may copy or redistrib}ute these programs, provided that: 1: You don't charge anything for the copy. It is permissable to charge a no}minal fee for media, etc. 2: All source code and documentation for the programs is made available as part o}f the distribution. 3: This copyright notice is preserved verbatim, and included in the distribution. You} are allowed to modify these programs, and redistribute the modified versions, provided that the modifications are clearly} noted. There is NO WARRANTY with this software, it comes as is, and is distributed in the hope that it may be useful.} This copyright notice is based on the one published by the Free Software Foundation, sometimes known as the GNU project.} The idea is the same as theirs, ie the software is free, and is intended to stay that way. Everybody has the right to c}opy, modify, and redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redis}tributing it.d redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redis /* Misc cruft used by cross-compiler variant of CC65 */ #include #include "cc65.h" #include "cclex.h" FILE * }copen(file, mode) char * file; char mode; { char m[5]; FILE * p; m[0] = mode; m[1] = '\0'; if ((p = fopen(file, m)) ==} NULL) { return ((FILE *) 0); /* was -1 -- jrd */ } else { return (p); } } cclose(x) FILE * x;} { return(fclose(x)); } cprints(s) char * s; { fputs(s, stdout); } cputc(c, fp) int c; FILE * fp; { fputc(c, fp); } }clear(ptr, len) char * ptr; int len; { while (--len >= 0) *ptr++ = '\0'; } int is_alpha(c) int c; { if (((c >= 'a') }&& (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || (c == '_')) return(1); else return(0); } int isdigit(c}) int c; { if ((c >= '0') && (c <= '9')) return(1); else return(0); } int tolower(c) int c; { if ((c >= 'A') &}& (c <= 'Z')) return(c + 32); else return(c); } int toupper(c) int c; { if ((c >= 'a') && (c <= 'z')) return}(c - 32); else return(c); } else return(c); } int toupper(c) int c; { if ((c >= 'a') && (c <= 'z')) return" /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */ } This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */  /* Error reporting code */ #include #include "cclex.h" #include "cc65.h" /* Error( msg ) Print error with$} no prefix. */ Error(msg) char * msg; { PError("", msg); } /* Syntax() Flag a syntax error. */ Syntax() { Error("syn$}tax error"); } /* Illegal( msg ) Handle "illegal ..." messages. */ Illegal(msg) { PError("illegal ", msg); } /* Mis$}sing( msg ) Handle "missing ..." messages. */ Missing(msg) char * msg; { PError("missing ", msg); } /* MultDef( msg ) $} Handle "multipy defined ..." messages. */ MultDef(msg) char * msg; { PError("multiply defined ", msg); } /* Need( msg $}) Handle "need ..." messages. */ Need(msg) char * msg; { PError("need ", msg); } /* needlval() Handle "need lvalue" $}messages. */ needlval() { Need("lvalue"); } /* from here on down, we want to generate argcounts, so we undefine the mag$}ic symbol */ #undef NOARGC /* ersum() Report errors for user */ ersum() { /* see if anything left hanging... */ if %}(ncmp) Missing("closing bracket"); if (errcnt == 0) { printf("No errors.\n"); } } /* PError( pfx, msg %}) Print prefix message pfx followed by error message msg. */ PError(pfx, msg) char * msg; { #ifdef M6502 tprintf("\n%s: l%}ine %d:\n%s%s\nline:%s\n", fin, ln, pfx, msg, line); #else printf("%s, line %d : %s%s\n", fin, ln, pfx, msg); printf("lin%}e: %s\n", line); printf("curtok = %d\n", curtok); printf("nxttok = %d\n", nxttok); #endif if (++errcnt > 6) fatal("%}too many errors"); } /* fatal( msg ) Fatal error - print message and die */ fatal(msg) char * msg; { #ifdef M6502 tpri%}ntf("fatal error: %s\nline: %s\n", msg, line); exit(2); #else printf("fatal error: %s\n", msg); printf("line: %s\n", li%}ne); printf("curtok = %d\n", curtok); printf("nxttok = %d\n", nxttok); printf("Can't recover from previous errors: Goo%}d-bye!\n"); exit(2); #endif } /* Warning( msg ) Print warning message. */ Warning(msg) char * msg; { #ifdef M6502 tp%}rintf("Warning: %s\n", msg); #else printf("warning: %s\n", msg); printf("line: %s\n", line); printf("curtok = %d\n", cu% }rtok); printf("nxttok = %d\n", nxttok); #endif } g: %s\n", msg); printf("line: %s\n", line); printf("curtok = %d\n", cu$3 /* expression parser, part 1 */ #include #include "cc65.h" #include "cclex.h" extern char * lsptr; int hie0() }); int hie1(); int hie2(); int hie3(); int hie4(); int hie5(); int hie6(); int add(); int sub(); int mult(); int div(); int m) }od(); int asl(); int asr(); int and(); int xor(); int or(); int lt(); /* int ult(); */ int gt(); /* int ugt(); */ int le(); /) }* int ule(); */ int ge(); /* int uge(); */ int eq(); int ne(); /* needtok( token, msg ) Token is expected next. Print ")}missing " if not found. */ needtok(token, msg) int token; char * msg; { if (curtok == token) { gettok(); )} return; } else { Missing(msg); } } /* needcol() Colon enforcer. */ needcol() { needtok(COLON, ")}colon"); } /* getoprnd( func, lval ) Subroutine of commonly executed sequence of statements; */ getoprnd(func, lval) int)} (*func) (); struct expent * lval; { gettok(); push(); exprhs((*func) (lval), lval); } /* isconst( lval1, lval2 ) )}Test to see if both lval1 and lval2 are constant expressions. */ isconst(lval1, lval2, svptr) struct expent * lval1; struct e)}xpent * lval2; char * svptr; { if (lval1->e_flags == E_MCONST && lval2->e_flags == E_MCONST) { popsp(); out)}qi = svptr; return (1); } else { return (0); } } /* added by jrd. return T if value describes con)}stant 0 */ const0(lval) struct expent * lval; { return ((lval->e_flags == E_MCONST) && (lval->e_const == 0)); } /* expre)}ssion() P = value of expression. */ expression() { struct expent lval; #ifndef M6502 bzero(&lval, sizeof(lval)); #endif )} exprhs(expr(hie0, &lval), &lval); } /* expr( func, lval ) Expression parser; func is either hie0 or hie1. */ expr(func)}, lval) int (*func) (); struct expent * lval; { int k; char * locptr; int savsp; savsp = oursp; locptr = lsptr; /* #ifd)}ef M6502 -- jrd */ flushout(); /* #endif */ k = (*func) (lval); lsptr = locptr; #ifndef M6502 if (savsp != oursp))} { char errbuf[100]; sprintf(errbuf, "oursp [%d] != savsp [%d]", oursp, savsp); Error(errbuf); } #)}endif return (k); } /* hie0( lval ) Parse comma operator. */ hie0(lval) struct expent * lval; { int k; k = hie1(lva)}l); while (curtok == COMMA) { gettok(); k = hie1(lval); } return (k); } /* hie1( lval ) Parse fi)}rst level of expression hierarchy. */ hie1(lval) struct expent * lval; { int (*func) (); int k; k = hieQuest(lval); swit)}ch (curtok) { case RPAREN: case SEMI: return (k); case ASGN: { struct expent lval2; gettok(); )} if (k == 0) { needlval(); return (0); } if (lval->e_flags & E_MEXPR) push(); exprhs(hie1(&lval2), &lval) }2); store(lval); lval->e_flags = E_MEXPR; /* if either the source expression of the target generated condition codes, s)!}et the cond-codes bit in the returned expr */ lval->e_test |= (lval2.e_test & E_CC); return (0); } case PASGN: )"} func = add; break; case SASGN: func = sub; break; case MASGN: func = mult; break; )#} case DASGN: func = div; break; case MOASGN: func = mod; break; case SLASGN: func = )$}asl; break; case SRASGN: func = asr; break; case AASGN: func = and; break; case XOA)%}SGN: func = xor; break; case OASGN: func = or; break; default: return (k); } opeq)&}(func, lval, k); return (0); } /* opeq( func, lval, k) Process "op=" operators. */ opeq(func, lval, k) int (*func) ();)'} struct expent * lval; int k; { char * ptr; struct expent lval2; gettok(); if (k == 0) { needlval(); ret)(}urn; } if (lval->e_flags & E_MEXPR) push1(); exprhs(k, lval); push(); exprhs(hie1(&lval2), &lval2); if (fun))}c == add || func == sub) { if (lval->e_tptr[0] == T_PTR) { scale(SizeOf(lval->e_tptr + 1)); } } (*func) )*}(); store(lval); lval->e_flags = E_MEXPR; } /* hieQuest( lval ) Parse "lvalue ? exp : exp" */ hieQuest(lval) struct )+}expent * lval; { int k; k = hieOr(lval); if (curtok != QUEST) { return (k); } else { int lab),}f; int labt; gettok(); exprhs(k, lval); labf = getlabel(); falsejump(labf, 0); expressio)-}n(); labt = getlabel(); needcol(); jump(labt); outcdf(labf); expression(); outcdf(labt); ).} lval->e_flags = E_MEXPR; return (0); } } /* hieOr( lval ) Process "exp || exp". */ hieOr(lval) struct ex)/}pent * lval; { int k; k = hieAnd(lval); /* do higher-precedence exprs */ if (curtok != DBAR) /* if not ||, return */)0} { return (k); } else { int lab1; /* labl to exit expr w/ 1 */ int lab2; /* labl to exit )1}expr w/ 0 */ struct expent lval2; int loadk; /* flag if load 1 at end */ loadk = ((lval->e_test & E_LOGL))2} == 0); /* need to load 1 if not already */ exprhs(k, lval); /* get first expr */ lab2 = getlabel(); /* get inte)3}rnal label. for tests, this is the only label */ truejump(lab1 = getlabel(), 0); /* get lab and gen 1st )4}bne to it */ while (curtok == DBAR) /* while there's more expr */ { gettok(); /* skip the || */ exprhs(hieAnd(&)5}lval2), &lval2); /* get a subexpr */ loadk |= ((lval2.e_test & E_LOGL) == 0); /* need to load 1 if not already */ if (c)6}urtok == DBAR) /* if still more, ... */ { truejump(lab1, lval->e_test & E_XINV); /* bne out */ } else )7} { if (loadk) /* only generate branch around load if we're loading */ falsejump(lab2, lval->e_test & E_XINV))8}; /* else beq out */ } } outcdf(lab1); /* define lab1 */ if (loadk) /* if need a load-const 1 ... */ { )9} konst1(1); /* ... do it */ } outcdf(lab2); /* define lab2 */ lval->e_flags = E_MEXPR; return (0); ):} } } /* hieAnd( lval ) Process "exp && exp" */ hieAnd(lval) struct expent * lval; { int k; k = hie2(lval); if (cu);}rtok != DAMP) { return (k); } else { int lab; struct expent lval2; exprhs(k, lval); )<} falsejump(lab = getlabel(), 0); while (curtok == DAMP) { gettok(); exprhs(hie2(&lval2), &lval2); falsejum)=}p(lab, 0); /* zzz finish later */ } /* immed(); outdec(1); */ konst1(1); outcdf(lab); lval->e_fla)>}gs = E_MEXPR; return (0); } } /* utils used by hie2, 3, and 4. it's the guts of those 3 guys, extracted and pa)?}rameterized */ static int kcalc(tok, val1, val2) int tok, val1, val2; { #ifdef M6502 /* hand bummed version of what this com)@}piles into, to avoid extraneous pushes. */ #asm ldy #6 ; get 'tok' jsr ldaysp ; this is safe cause theyre all byte-siz)A}ed sta tmp4 ; save the value here ; common preamble ldy #4 ; offset for val1 jsr pushwysp ; push it ldy #4 ; offset fo)B}r val2 jsr ldaxysp ; load it ldy tmp4 ; get token number back cpy #78 ; BAR bne *+6 ; nope, try next jsr ortos ; d)C}o an OR jmp exitfun ; and return the value cpy #79 ; EQ bne *+6 ; nope, try next jsr toseqax ; do an == jmp exitfun)D} ; and return the value cpy #90 ; XOR bne *+6 ; nope, try next jsr xortos ; do an XOR jmp exitfun ; and return the )E}value cpy #73 ; AMP bne *+6 ; nope, try next jsr andtos ; do an AND jmp exitfun ; and return the value cpy #88 ; )F}ASR bne *+6 ; nope, try next jsr asrtos ; do an ASR jmp exitfun ; and return the value cpy #82 ; ASL bne *+6 ; nop)G}e, try next jsr asltos ; do an ASL jmp exitfun ; and return the value cpy #68 ; STAR bne *+6 ; nope, try next jsr m)H}ultos ; do a multiply jmp exitfun ; and return the value cpy #70 ; DIV bne *+6 ; nope, try next jsr divtos ; do a d)I}ivide jmp exitfun ; and return the value cpy #92 ; MOD bne *+6 ; nope, try next jsr modtos ; do a MOD jmp exitfun )J}; and return the value ; if we get here its an internal error. ignore for now jsr popax ; flush dead value on stack #endas)K}m #else switch (tok) { case BAR: return (val1 | val2); case EQ: return (val1 == val2); case XOR)L}: return (val1 ^ val2); case AMP: return (val1 & val2); case ASR: return (val1 >> val2); case A)M}SL: return (val1 << val2); case STAR: return (val1 * val2); case DIV: return (val1 / val2); cas)N}e MOD: return (val1 % val2); #ifndef M6502 default: printf("Internal error: kcalc: got token %X\n", tok); #en)O}dif } #endif } int op_assoc(tok, ops) int tok; struct op_alist * ops; { while (ops->tok && (ops->tok != tok)) ++op)P}s; return (ops->gen); } /* helper fun for various hie frobs */ int hie_internal(ops, lval, hienext) struct op_alist * ops)Q}; /* alist of ops we'll take here */ struct expent * lval; /* parent expr's lval */ int (*hienext) (); /* next higher leve)R}l parser */ { int k; k = (*hienext) (lval); if (!op_assoc(curtok, ops)) /* sufficient to test if it's there... */ )S}{ return (k); } else { struct expent lval2; char * svptr; int (*gen) (); int this_tok)T}; svptr = outqi; exprhs(k, lval); while (1) { if (gen = op_assoc((this_tok = curtok), ops)) { )U} getoprnd(hienext, &lval2); if (isconst(lval, &lval2, svptr)) { liconst(lval->e_const = kcalc(this_tok, )V}lval->e_const, lval2.e_const)); lval->e_test &= ~E_CC; /* cc not set right */ } else { (*gen) (); lval)W}->e_flags = E_MEXPR; lval->e_test |= E_CC; /* say we set cc */ } } else { if (lval->e_flags == E_MC)X}ONST) { outqi = svptr; } return (0); } } } } /* hie2( lval ) */ struct op_alist hie2_ops[] = { )Y}{BAR, or}, {0, 0} }; hie2(lval) struct expent * lval; { return (hie_internal(hie2_ops, lval, hie3)); } /* hie3( lval )Z}) */ struct op_alist hie3_ops[] = { {XOR, xor}, {0, 0} }; hie3(lval) struct expent * lval; { return (hie_internal(hie3)[}_ops, lval, hie4)); } /* hie4( lval ) */ struct op_alist hie4_ops[] = { {AMP, and}, {0, 0} }; hie4(lval) struct expen)\}t * lval; { return (hie_internal(hie4_ops, lval, hie5)); } /* hie5( lval ) */ struct op_alist hie5_ops[] = { {EQ, eq},)]} {NE, ne}, {0, 0} }; hie5(lval) struct expent * lval; { return (hie_internal(hie5_ops, lval, hie6)); } /* hie6( lva)^}l ) process greater-than type comparators */ /* helper fun for hie6. Where's FLET when you need it? */ static hie6_intern)_}al(isptr1, lval, gen) int isptr1; /* other value is ptr */ struct expent * lval; int (*gen) (); /* code generator fun */ )`}{ gettok(); push(); exprhs(hie7(lval), lval); (*gen) ((isptr1 || (lval->e_tptr[0] & T_UNSIGNED))); } hie6(lval) stru)a}ct expent * lval; { int k; k = hie7(lval); if ((curtok < LE) || (curtok > GT)) { return (k); } else )b} { struct expent lval2; int isptr1; exprhs(k, lval); isptr1 = lval->e_tptr[0] & T_UNSIGNED; l)c}val->e_test = E_LOGL | E_CC; /* say we returned a logl val, and set cc */ while (1) { switch (curtok) { c)d}ase LE: hie6_internal(isptr1, &lval2, le); break; case GE: hie6_internal(isptr1, &lval2, ge); )e} break; case LT: hie6_internal(isptr1, &lval2, lt); break; case GT: hie6_internal(isptr1, &lv)f}al2, gt); break; default: lval->e_flags = E_MEXPR; return (0); } } } } ternal(isptr1, &lv(k /* Expression parsing, part 2 */ #include #include "cc65.h" #include "cclex.h" int hie8(); int hie9(); int hi-q}MB1CC65 H B5CCLEX H BCCCMISC M65BKCCPAGE0 M65BSCHANGELO BYCODEQGENC B COPYLEFTDOCB CRUFT C BDISCLAIMH BERROR C B] EXPR1 C B5gEXPR2 C BbEXPR3 C BEXTRA M65B FUNCTIONC B5GLB C BIGLOBLVARC B'\IO C MLEXER C e10(); int increm(); int decrem(); int inc(); int dec(); /* hie7( lval ) Parse << and >>. */ extern asl(); extern asr(-r}); struct op_alist hie7_ops[] = { {ASL, asl}, {ASR, asr}, {0, 0} }; hie7(lval) struct expent * lval; { return (hie_i-s}nternal(hie7_ops, lval, hie8)); } /* hie8( lval ) Process + and - binary operators. */ hie8(lval) struct expent * lval; -t}{ int k; k = hie9(lval); if ((curtok != PLUS) && (curtok != MINUS)) { return (k); } else { s-u}truct expent lval2; char * svptr; char * tptr1; char * tptr2; svptr = outqi; exprhs(k, lval); -v} while (1) { if (curtok == PLUS) { getoprnd(hie9, &lval2); tptr1 = lval->e_tptr; tptr2 = l-w}val2.e_tptr; if ((tptr1[0] & T_POINTER) && (tptr2[0] & T_INTEGER)) { cscale(&lval2, PSizeOf(tptr1)); } -x} else if ((tptr1[0] & T_INTEGER) && (tptr2[0] & T_POINTER)) { swapstk(); scale(PSizeOf(tptr2)); lva-y}l->e_tptr = lval2.e_tptr; } if (isconst(lval, &lval2, svptr)) { liconst(lval->e_const += lval2.e_const); } -z} else { add(); lval->e_flags = E_MEXPR; } } else if (curtok == MINUS) { getoprnd(hie9, &-{}lval2); tptr1 = lval->e_tptr; tptr2 = lval2.e_tptr; if ((tptr1[0] & T_POINTER) && (tptr2[0] & T_INTEGER)-|}) { cscale(&lval2, PSizeOf(tptr1)); } sub(); if ((tptr1[0] & tptr2[0] & T_POINTER) && (strcmp(tptr1-}}, tptr2) == 0)) { k = PSizeOf(tptr1); if (k > 1) { push(); /* immed(); outdec(k); -~} */ konst1(1); div(); lval->e_flags = E_MEXPR; } lval->e_tptr = type_int; } if -}(lval->e_flags == E_MCONST && lval2.e_flags == E_MCONST) { outqi = svptr; liconst(lval->e_const -= lval2.e_const); -} } else { lval->e_flags = E_MEXPR; } } else { if (lval->e_flags == E_MCONST) { outq-}i = svptr; } else { lval->e_flags = E_MEXPR; } return (0); } } } } /* hie9( lval ) Pro-}cess * and / operators. */ extern mult(); extern div(); extern mod(); struct op_alist hie9_ops[] = { {STAR, mult}, {DIV,-} div}, {MOD, mod}, {0, 0} }; hie9(lval) struct expent * lval; { return (hie_internal(hie9_ops, lval, hie10)); } /* -}hie10( lval ) Parse unary operators. */ /* various internal functions */ static int hie10a(lval, incptr, incint) /* guts o-}f inc, dec */ struct expent * lval; int (*incptr) (); /* for inc'ing ptrs */ int (*incint) (); /* for inc'ing ints */ { int k-}; gettok(); if ((k = hie10(lval)) == 0) { needlval(); return (0); } if (lval->e_flags & E_MEXPR) -} push1(); exprhs(k, lval); if (lval->e_tptr[0] == T_PTR) { (*incptr) (SizeOf(lval->e_tptr + 1)); } else-} { (*incint) (); } store(lval); lval->e_flags = E_MEXPR; } static int hie10b(lval, k, incptr, incint) /* g-}uts of second inc, dec */ struct expent * lval; int k; int (*incptr) (); /* for inc'ing ptrs */ int (*incint) (); /* for inc'-}ing ints */ { gettok(); if (k == 0) { needlval(); return (0); } if (lval->e_flags & E_MEXPR) pu-}sh1(); exprhs(1, lval); save(); if (lval->e_tptr[0] == T_PTR) { (*incptr) (SizeOf(lval->e_tptr + 1)); } -} else { (*incint) (); } store(lval); rstr(); lval->e_flags = E_MEXPR; } static hie10c(tok, lval) /* guts-} of minus, comp */ int tok; struct expent * lval; { int k; gettok(); k = hie10(lval); if (lval->e_flags == E_MCONST)-} { lval->e_const = (tok == MINUS ? -lval->e_const : ~lval->e_const); return (0); } exprhs(k, lval); i-}f (tok == MINUS) neg(); else com(); lval->e_flags = E_MEXPR; } hie10(lval) struct expent * lval; { int k; ch-}ar * ptr; struct hashent * sadr; int type; if (curtok != IDENT) { switch (curtok) { case INC: { hi-}e10a(lval, increm, inc); return (0); } case DEC: { hie10a(lval, decrem, dec); return (0); } case MI-}NUS: case COMP: { hie10c(curtok, lval); return (0); } case BANG: { gettok(); k = hie10(lval); -}/* decode the expr */ exprhs(k, lval); /* load the value */ #ifdef busted if (lval->e_test) /* somebody doing a te-}st of this exp? */ { lval->e_test ^= E_XINV; /* flip sense of test */ } else /* normal expr */ -} { #ifdef old_cruft push(); konst1(0); eq(); #else lneg(); #endif } #else lneg(); /* sheesh */ #endi-}f lval->e_flags = E_MEXPR; /* say it's an expr */ return (0); /* expr not storable */ } case STAR: { g-}ettok(); exprhs(hie10(lval), lval); if (((ptr = lval->e_tptr)[0] & T_POINTER) == 0) { Illegal("indirection-}"); } else { if (ptr[0] == T_ARRAY) { ptr += 4; } else { ++ptr; } lval->-}e_tptr = ptr; } lval->e_flags = E_MEXPR; return (1); } case AMP: { gettok(); k = hie10(lval-}); if (k == 0) { Illegal("address"); return (0); } ptr = Lmalloc(strlen(lval->e_tptr) + 2); -}ptr[0] = T_PTR; strcpy(ptr + 1, lval->e_tptr); lval->e_tptr = ptr; return (0); } case SIZEOF: { ge-}ttok(); if ((curtok == LPAREN) && (nxttok >= 20) && (nxttok <= 29)) { char tarray1[MAXTYPELEN]; gettok(); -}type = gettype(-1, &sadr); absdecl = 1; declare(tarray1, type, sadr); needbrack(RPAREN); lval->e_const = SizeOf(tarra-}y1); } else { hie10(lval); lval->e_const = SizeOf(lval->e_tptr); } lval->e_flags = E_MCONS-}T | E_TCONST; lval->e_tptr = type_int; return (0); } default: if ((curtok == LPAREN) && (nxttok >= 20) && (n-}xttok <= 29)) { char tarray2[MAXTYPELEN]; gettok(); type = gettype(-1, &sadr); absdecl = 1;-} declare(tarray2, type, sadr); needbrack(RPAREN); k = hie10(lval); strcpy(lval->e_tptr = Lmalloc(-}strlen(tarray2) + 1), tarray2); return (k); } } /* end switch */ } /* end curtok != ident */ k = hie1-}1(lval); switch (curtok) { case INC: { hie10b(lval, k, increm, inc); return (0); } case DEC: -} { hie10b(lval, k, decrem, dec); return (0); } default: return (k); } } 0); } case DEC: ,_ /* Expression parsing, part 3 */ #include #include "cc65.h" #include "cclex.h" int hie0(); /* hie11( lval 1}) */ hie11(lval) struct expent * lval; { int k; k = primary(lval); if ((curtok < LBRACK) || (curtok > PREF)) { 1} return (k); } else { struct expent lval2; char * svptr; char * tptr; char * tptr2; 1} while (1) { if (curtok == LBRACK) { gettok(); exprhs(k, lval); svptr = outqi; push(); 1} /* TOS now contains ptr to array elements. */ exprhs(hie0(&lval2), &lval2); needbrack(RB1}RACK); if ((tptr = lval->e_tptr)[0] & T_POINTER) { if (tptr[0] == T_ARRAY) lval->e_tptr += 3; cscale(&1}lval2, SizeOf(++lval->e_tptr)); if ((lval2.e_flags == E_MCONST) && (lval2.e_const == 0)) { popsp();1} outqi = svptr; goto end_array; } } else if ((tptr2 = lval2.e_tptr)[0] & T_POINTER) { if1} (tptr2[0] == T_ARRAY) lval2.e_tptr += 3; swapstk(); scale(SizeOf(++lval2.e_tptr)); lval->e_tptr = lval2.e_1}tptr; } else { Error("cannot subscript"); } add(); end_array: lval->e_flags = E_MEXPR; 1} k = lval->e_tptr[0] != T_ARRAY; } else if (curtok == LPAREN) { gettok(); if (lval->e_tptr[0] 1}!= T_FUNC) { Illegal("function call"); } callfunction(k, lval); lval->e_test = E_CC; /* funs always ret1}urn cond codes */ lval->e_flags = E_MEXPR; ++lval->e_tptr; k = 0; } else if (curtok == DOT) 1} { k = opref(k, lval); } else if (curtok == PREF) { k = oppref(k, lval); } else retur1}n (k); } } } /* primary( lval ) This is the lowest level of the expression parser. */ int primary(lval) struct expe1}nt * lval; { int k; struct hashent * psym; char * tptr; int type; lval->e_test = 0; /* not a test at all, yet */ 1} if (curtok == IDENT) { psym = (struct hashent *) curval; gettok(); /* check local symbol tabl1}e. */ if (psym->h_loc != 0) { lval->e_tptr = tptr = psym->h_ltptr; if (psym->h_loc & SC_STACK) { #ifd1}ef oldM6502 getladr(psym->h_ldata); lval->e_flags = E_MEXPR; #else lval->e_flags = E_MLOCAL | E_TLOFFS; 1}#endif } else { lval->e_flags = E_MGLOBAL | E_TGLAB; } lval->e_const = psym->h_ldata; if ((tpt1}r[0] == T_FUNC) || (tptr[0] == T_ARRAY)) { return (0); } return (1); } /* check global sym1}bol table. */ if (psym->h_glb != 0) { if ((type = psym->h_glb) & SC_STRUCT) { Error("struct tag/f1}ld cannot be primary"); return (0); } lval->e_tptr = tptr = psym->h_gtptr; lval->e_const = psym->h_gdata; #1}ifndef M6502 /* don't do enums in the native compiler, to save space */ if (type == SC_ENUM) { lval->e_flag1}s = E_MCONST; return (0); } else #endif { lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB; } 1} if ((tptr[0] == T_FUNC) || (tptr[0] == T_ARRAY)) { return (0); } return (1); } /* IDENT 1}is either an auto-declared function or an undefined variable. */ if (curtok == LPAREN) { /* decl1}are function returning int. */ addglb(psym, type_ifunc, SC_EXTERN); lval->e_tptr = Lmalloc(3); strcpy(lval->e_tpt1}r, type_ifunc); lval->e_flags = E_MGLOBAL | E_TGLAB; lval->e_const = psym->h_gdata; return (0); } addloc(psym1}, type_int, SC_STACK, 0); lval->e_flags = E_MLOCAL | E_TLOFFS; lval->e_tptr = type_int; lval->e_const = 0; 1} Error("undefined symbol"); return (1); } /* Character and integer constants. */ if ((curtok == ICO1}NST) || (curtok == CCONST)) { lval->e_flags = E_MCONST | E_TCONST; lval->e_tptr = type_int; lval->e_con1}st = curval; gettok(); return (0); } /* Process parenthesized subexpression by calling the whole parse1}r recursively. */ if (curtok == LPAREN) { gettok(); k = hie0(lval); needbrack(RPAREN); re1}turn (k); } /* String literals. */ if (curtok == SCONST) { char tarray[6]; lval->e_flags = E_1}MCONST | E_TLIT; tarray[0] = T_ARRAY; encode(tarray + 1, strlen(litq + curval) + 1); tarray[4] = T_CHAR; 1} tarray[5] = '\0'; lval->e_tptr = Lmalloc(strlen(tarray) + 1); strcpy(lval->e_tptr, tarray); lval->e_con1}st = curval; gettok(); return (0); } /* Illegal primary. */ Error("invalid expression"); lval->e1}_flags = E_MCONST; lval->e_tptr = type_int; return (0); } /* true if val1 -> int pointer or int array and val2 not p1}tr or array. used to decide whether to shift value left 1 when indexing. */ scale(n) int n; { if (n == 2) { do1}ublereg(); } else if (n != 1) { push(); immed(); #ifndef M6502 if (n == 4) { outdecnl(2); 1}asl(); return; } else if (n == 8) { outdecnl(3); asl(); return; } #endif outdecnl(n); mult()1}; } } cscale(lval, n) struct expent * lval; int n; { /* if (lval->e_flags == E_MCONST) { lval->e_const *= n; rmvby1}te(4); lconst(E_TCONST, lval->e_const); } else { */ scale(n); /* } */ } decrem(n) int n; { #ifdef old_cruft if (n 1}<= 4) { while (n--) dec(); } else { push(); immed(); outdecnl(n); sub(); } #1}else if (n <= 2) { oljsr((n == 1) ? "decax1" : "decax2"); } else { push(); immed(); o1}utdecnl(n); sub(); } #endif } increm(n) int n; { #ifdef old_cruft if (n <= 4) { while (n--) inc(); 1} } else { push(); immed(); outdecnl(n); add(); } #else if (n <= 8) { ot("\tjsr1}\tincax"); /* use the canned incax1..8 ops */ outdecnl(n); } else { konst3(n); /* load Y with number *1}/ oljsr("indexax"); /* use indexing op */ } #endif } #ifdef old_cruft /* determine type of binary operation */1} result(lval, lval2) struct expent * lval; struct expent * lval2; { } #endif /* store( lval ) Store primary reg into this 1}reference */ store(lval) struct expent * lval; { int f; f = lval->e_flags; #ifndef M6502 if (f == 0) { fatal("1}e_flags == 0"); } #endif if (f & E_MGLOBAL) { putmem(lval->e_const, lval->e_tptr); } else if (f & E_MLO1}CAL) { putloc(lval->e_const, lval->e_tptr); } else if (f & E_MEXPR) { putstk(lval); } else 1} { #ifdef M6502 fatal("err 1"); #else fatal("trying to store into constant"); #endif } } /* exprhs( k, lv1}al ) */ exprhs(k, lval) int k; struct expent * lval; { int f; int immed(); f = lval->e_flags; if (k) /* reference 1}storable-p */ { if (f & E_MGLOBAL) /* ref to globalvar */ { /* getmem(lval->e_const, lval->e_tptr); -- jrd 1}*/ getmem(lval->e_const, lval->e_tptr, lval->e_test); } else if (f & E_MLOCAL) /* ref to localvar */ { getloc(l1}val->e_const, lval->e_tptr); } else if (f & E_MCONST) /* ref to constant */ { #ifdef M6502 fatal("err 2"); #else 1} fatal("Constant with k = 1"); #endif } else { indirect(lval); /* else must be locative */ } /* lval->e_te1}st |= E_CC; .. say we set cc (all those do...) */ } else /* reference not storable */ if (f == E_MEOFFS) 1} { push(); immed(); /* outdec(lval->e_const); */ outdecnl(lval->e_const); /* -- jrd */ add(); } else if (f1} != E_MEXPR) { lconst(f & E_MCTYPE, lval->e_const); } /* lval->e_test &= ~E_CC; /* say cc not set right */ 1} if (lval->e_test & E_TEST) /* we testing this value? */ { #ifndef M6502 /* debug... */ ol(";;; force test");1} #endif tst(); /* yes, force a test */ } } /* liconst( const ) Load primary reg with integer constant. */ lic1}onst(cnst) int cnst; { immed(); outdecnl(cnst); } /* lconst( func, ctype, const ) Load primary reg with some constant 1}value. */ lconst(ctype, cnst) int ctype; int cnst; { ctype &= E_MCTYPE; if (ctype == E_TLOFFS) { getladr(cnst);1} } else { immed(); outconst(ctype, cnst, 0); } } /* outconst(ctype, const, ischar) Output psuedo1}-op appropriate to type of constant. */ outconst(ctype, cnst, ischar) int ctype; int cnst; int ischar; { switch (ctype & E_1}MCTYPE) { case E_TCONST: /* fixnum constant */ outdecnl(cnst); return; case E_TGLAB: /* some kind o1}f global */ outgbl(cnst); nl(); return; case E_TLIT: /* a literal of some kind */ outslt(cnst); 1} return; default: #ifdef M6502 fatal("err 3"); #else printf("unknown constant: %d\n", ctype & E_MCTYPE);1} fatal("compiler error: unknown constant type"); #endif } } /* test( label ) Generate code to perform test and j1}ump if false. */ test(label) int label; { int k; struct expent lval; #ifndef M6502 bzero(&lval, sizeof(lval)); #endif ne1}edbrack(LPAREN); k = expr(hie0, &lval); /* generate code to eval the expr */ /* #ifndef M6502 */ if (lval.e_flags == E_MC1}ONST) { if (lval.e_const == 0) { jump(label); Warning("unreachable code"); } needbrack(RPAREN); 1} return; } /* #endif */ /* if the expr hasn't set condition codes, set the force-test flag */ if (!(lval.e_test 1}& E_CC)) lval.e_test |= E_TEST; exprhs(k, &lval); /* load the value as apropriate */ needbrack(RPAREN); #ifndef M6501}2 if (lval.e_test & E_XINV) ol(";;; test inverted"); #endif falsejump(label, lval.e_test & E_XINV); } /* needbrack(1} btype ) Enforce closing bracket type. */ needbrack(btype) int btype; { needtok(btype, "bracket"); } /* callfunction(ptr1}) Perform a function call. Called from hie11, this routine will either call the named function, or if the supplied ptr is 1}zero, will call the contents of P. */ callfunction(k, lval) int k; struct expent * lval; { char * dptr; struct expent lval2;1} int nargs; nargs = 0; if (lval->e_flags & E_MEXPR) { save(); } while (curtok != RPAREN) { exp1}rhs(hie1(&lval2), &lval2); push(); nargs += 2; if (curtok != COMMA) break; gettok(); } needbra1}ck(RPAREN); if (lval->e_flags & E_MEXPR) { rstr(); /* push(); not needed -- jrd. we call (AX) */ callstk(1}nargs); } else { call(lval->e_const, nargs); } } /* opref( lval ) Process . operator. */ int opref(k, 1}lval) int k; struct expent * lval; { if (!(lval->e_tptr[0] & T_STRUCT)) { Need("struct"); } if (!(lval->e_f1}lags & E_MEXPR)) { lconst(lval->e_flags & E_MCTYPE, lval->e_const); } return (structref(lval)); } /* oppref1}( k, lval ) Process -> operator. */ int oppref(k, lval) int k; struct expent * lval; { char * tptr; tptr = (char *) lval-1}>e_tptr; if ((tptr[0] != T_PTR) || !(tptr[1] & T_STRUCT)) { Need("struct pointer"); } exprhs(k, lval); re1}turn (structref(lval)); } /* structref( lval ) Process struct field after . or ->. */ int structref(lval) struct expent * 2}lval; { struct hashent * psym; gettok(); if (curtok != IDENT) { Syntax(); lval->e_tptr = type_int; 2} return (0); } psym = (struct hashent *) curval; gettok(); #ifdef M6502 /* until such time as we fix cc65 to gener2}ate fetches of unsigned chars correctly, must mask here... if (psym->h_glb != SC_SFLD) */ if ((psym->h_glb & 0xFF) != 2}SC_SFLD) #else if ((psym->h_glb & 0xFF) != SC_SFLD) #endif { Need("struct field"); lval->e_tptr = type_int;2} return (0); } lval->e_const = psym->h_gdata; lval->e_tptr = Lmalloc(strlen(psym->h_gtptr) + 1); strcpy(lval2}->e_tptr, psym->h_gtptr); lval->e_flags = E_MEOFFS; if (psym->h_gtptr[0] == T_ARRAY) { return (0); } retu2}rn (1); } /* getlabel() Get next unused label. */ getlabel() { return (++nxtlab); } { return (0); } retu0Y;#define FIXARGC ;/* stuff that should make it into the library? */ ;printmsg(str, arg) ;char * str; _printmsg: jsr ent6}erfun2 ;int arg; ;{ ; tprintf(str, arg); jsr pushwysp4 jsr pushwysp4 ;} ldy #2 jsr _tprintf ;#define NOARGC; ;6 }/* check for break key, abort if user pressed it */ ;extern char BRK; jmp exitfun ;#asm ;_BRK = $11 _BRK = $11 ;#endas6 }m ;chkbrk() ;{ ; if (BRK == 0) /* break key not pressed? */ _chkbrk: jsr enterfun0 ldx #0 lda _BRK jsr pushax 6 }; { ldax #0 jsr toseqax ; closeall(); /* close all open files */ ;;; falsejump lbeq L2 ; BRK = -1; jsr _closeall 6 } ; printmsg("Aborted!\n", 0); ldax #-1 sta _BRK ldax #L1+0 jsr pushax jsr push0 ; exit(0); jsr _printmsg jsr p6 }ush0 ; } jsr _exit ;} ;/* check for stack overflow */ ;extern int _himem; L2: jmp exitfun L1: .byte 65,98,111,1146},116,101,100,33,-101,0 ;chkstk() ;{ ; int dummy; _chkstk: jsr enterfun0 ; if (((int)&dummy - _himem) < 16) jsr dec6}sp2 ldy #0 jsr plocysp lda __himem ldx __himem+1 jsr subtos jsr pushax ; { ldax #16 jsr tosltax ; PError("!6}!", "Stack overflow"); ;;; falsejump lbeq L4 ldax #L3+0 jsr pushax ldax #L3+3 jsr pushax ; fatal("Giving up"); 6}jsr _PError ldax #L3+18 jsr pushax ; } jsr _fatal ;} L4: jsr incsp2 jmp exitfun L3: .byte 33,33,0,83,116,97,96}9,107,32,111,118,101,114,102,108,111 .byte 119,0,71,105,118,105,110,103,32,117,112,0 .globl _fatal .globl _PError .gl6}obl _chkstk .globl __himem .globl _exit .globl _closeall .globl _chkbrk .globl _BRK .globl _tprintf .globl _pri6}ntmsg kstk .globl __himem .globl _exit .globl _closeall .globl _chkbrk .globl _BRK .globl _tprintf .globl _pri4 /* C functions definitions */ #include #include "cc65.h" #include "cclex.h" extern char * Lmalloc(); extern stru:}ct hashent * decl(); extern struct hashent * declare(); #ifndef M6502 extern int outcnt; extern int stats; #endif /* Parse:} function dummy arguments. */ funargs() { n_funargs = 0; /* -- jrd */ if (curtok == RPAREN) { gettok(); :} return; } if (lovptr != 0) { fatal("err 4"); } while (1) { if (curtok == IDENT) { addlo:}c((struct hashent *) curval, NULL, SC_STACK, 0); ++n_funargs; /* -- jrd. count the arg */ gettok(); } else { :} Syntax(); } if (curtok == COMMA) { gettok(); } else if (curtok == RPAREN) { gettok(); break; } :} else { Syntax(); } } } /* declargs( ) Process argument declarations. */ declargs() { int i; char * p; :} struct hashent * psym; struct hashent * sadr; int stoff; char tarray[MAXTYPELEN]; char * tptr; int type; while:} ((curtok != LCURLY) /* && (curtok != ASM) */ ) { getsclass(1, SC_STACK); type = gettype(INT, &sadr); w:}hile (1) { absdecl = 0; if ((psym = declare(tarray, type, sadr)) != NULL) { if (psym->h_loc == 0) { :}Error("declaration of parameter not in argument list"); addloc(psym, tarray, SC_STACK, 0); } else { tptr =: } Lmalloc(strlen(tarray) + 1); strcpy(tptr, tarray); if (tptr[0] == T_ARRAY) { (tptr += 3)[0] = T_PTR; :!} } psym->h_ltptr = tptr; } } if (curtok != COMMA) break; gettok(); } if (curtok == SEMI) {:"} gettok(); } } /* Assign offsets and default undeclared arguments to int. */ tarray[0] = T_INT; tarray[1:#}] = '\0'; stoff = 2; for (i = lovptr - 1; i >= 0; --i) { psym = lvtab[i]; tptr = psym->h_ltptr; if :$}(tptr == NULL) { /* * default to "int" */ tptr = Lmalloc(2); strcpy(tptr, tarray); psym->h_ltptr = tptr;:%} } psym->h_ldata = stoff; stoff += (SizeOf(tarray) + 1) & (~1); } } /* newfunc( psym ) Parse argument d:&}eclarations and function body. */ newfunc(psym) struct hashent * psym; { #ifndef M6502 int sbyte; #endif #ifdef M6502 if :'}(verbose) { printmsg("\034\n\234%s\n", psym->h_name); } #endif psym->h_glb |= SC_DEFINED; /* this busted?? :(} outcdf(psym->h_gdata); -- jrd */ startfun(psym->h_name); /* start a function preamble */ declargs(); #ifdef old_cru:)}ft if (curtok == ASM) { struct expent lval; gettok(); /* outbyte(0); constexp(&lval); outconst(lv:*}al.e_flags, lval.e_const, 0); */ ns(); } else #endif { if (curtok != LCURLY) { Syntax(); } :+}oursp = 0; #ifndef M6502 sbyte = outcnt; #endif if (!compound()) { ret(); dumplits(); n_funargs = -1; /:,}* reset arg counter */ } #ifndef M6502 if (stats) { printf("%s: %d bytes\n", psym->h_name, outcnt - sbyte); } #en:-}dif } } /* declloc() Declare local variables. */ declloc() { int offs; int lab; int varlab; char * p; stru:.}ct hashent * psym; struct hashent * sadr; int sc; char tarray[MAXTYPELEN]; int type; offs = oursp; while (1) :/} { sc = getsclass(1, SC_STACK); if ((type = gettype(0, &sadr)) == 0) break; while (1) { absdecl = 0; :0} psym = declare(tarray, type, sadr); { int siz; if (tarray[0] != T_FUNC) siz = SizeOf(tarray); e:1}lse siz = 2; addloc(psym, tarray, sc, offs - siz); } if (tarray[0] != T_FUNC) { if (sc & SC_STA:2}CK) { offs -= SizeOf(tarray); } else if (sc == SC_STATIC) { jump(lab = getlabel()); outcdf(psym->h_l:3}data = getlabel()); outsp(SizeOf(tarray)); outcdf(lab); } } if (curtok != COMMA) break; gettok(); :4} } if (curtok == SEMI) { gettok(); } } oursp = modstk(offs); } f (curtok != COMMA) break; gettok(); 8P /* Level 0 parsing */ #include #include "cc65.h" #include "cclex.h" int hie1(); /* parseinit() */ parseinit>6}(tptr) char * tptr; { int count; int i; struct expent lval; struct hashent * p; struct hashent * q; char * str; >7} int sz; switch (tptr[0]) { case T_INT: case T_UINT: case T_CHAR: case T_UCHAR: case T_PTR: >8}constexp(&lval); /* if (tptr[0] == T_CHAR) */ if (char_t_p(tptr)) bytepref(); else wordpref(); /* o>9}utconst(lval.e_flags, lval.e_const, tptr[0] == T_CHAR); */ outconst(lval.e_flags, lval.e_const, char_t_p(tptr)); >:}break; case T_ARRAY: sz = decode(tptr + 1); if ((tptr[4] == T_CHAR) && (curtok == SCONST)) { str = &litq[>;}curval]; count = strlen(str) + 1; /* outdat(count); i = 0; while (++i <= count) outbyte(*str++); */><} outbv(str, count); litptr -= count; gettok(); } else { needbrack(LCURLY); count = 0; while (curto>=}k != RCURLY) { parseinit(tptr + 4); ++count; if (curtok != COMMA) break; gettok(); } >>} needbrack(RCURLY); } if (sz == 0) { encode(tptr + 1, count); } else if (count < sz) { outzero((sz - >?}count) * SizeOf(tptr + 4)); } else if (count > sz) { toomany(); } break; default: if (tptr[0] & T>@}_STRUCT) { needbrack(LCURLY); /* jrd hacked this */ #ifdef M6502 q = (struct hashent *) decode(tptr); /* old way *>A}/ #else q = (struct hashent *) (((int) decode(tptr)) + (int) gblspace); /* decode offset from glbspace*/ #endif p =>B} q->h_link; while (curtok != RCURLY) { if (p == NULL) { toomany(); return; } parseinit(p->h>C}_gtptr); p = p->h_link; if (curtok != COMMA) break; gettok(); } needbrack(RCURLY); while (p>D} != NULL) { outzero(SizeOf(p->h_gtptr)); p = p->h_link; } } #ifndef M6502 else { fprintf(s>E}tderr, "unknown type: %02x\n", tptr[0]); } #endif } } outzero(n) int n; { /* outdat(n); while (--n >= 0) { ou>F}tbyte(0); } */ ot("\t.blkb\t"); outdec(n); nl(); } constexp(lval) struct expent * lval; { expr(hie1, lval); if ((>G}lval->e_flags & E_MCONST) == 0) { Need("constant expression"); } } toomany() { Error("too many initializers">H}); } >e_flags & E_MCONST) == 0) { Need("constant expression"); } } toomany() { Error("too many initializers"< /* CC65 global var declarations. These are extern'ed in cc65.h */ #include #include "cc65.h" #ifndef CCPAGBJ}E0 /* only declare these of not doing page 0 stuff */ int curtok; /* current token seen by parser */ int curval; /* somethBK}ing or other, depending on curtok */ int nxttok; int nxtval; int absdecl; /* int critic; */ int glblbl; char * gsptr; int haBL}shval; int lovptr; char * lsptr; char macdef; /* T if any defines defined */ char * outqi; int outqsz; int tbllen; char * tbBM}lptr; int * wqptr; /* ptr to next entry */ int litptr; /* ptr to next entry in literal pool */ char * lptr; char * mptr; BN}/* ptrs into each */ #endif /* ccpage0 */ /* char glbspace[GSPACE]; */ char * gblspace; /* global heap */ char * gblend; /BO}* global space limit */ struct hashent * glvptr; int i_ifdef; char locspace[LSPACE]; char outq[OUTQSZ]; /* buf for asm stuffBP} being output */ /* int ret_addr; */ char s_ifdef[N_IFDEF]; int litlab; /* current lit pool labl */ int litspace = 0; /* toBQ}tal lit space used */ /* Misc storage */ int nxtlab, /* next avail label # */ /* compiler relative stk ptr */ #ifndef CCPABR}GE0 oursp, argstk, /* function arg sp */ #endif /* # open compound statements */ ncmp, /* # errors in compilation */ BS} errcnt, /* set non-zero on final input eof */ eof, /* non-zero if internal globals */ glbflag; struct filent filBT}etab[MAXFILES]; int ifile; FILE * inp; FILE * output; int ln; char * fin; char fname[80]; /* Canned typespecs */ /* chaBU}r * type_char = "\021"; unused? */ char * type_int = "\022"; char * type_ifunc = "\007\022"; char linebuf[linesize]; char * BV}line = linebuf; char mlinebuf[linesize]; char * mline = mlinebuf; char macltab[256]; int wq[wqtabsz]; /* while queue */ char BW}litq[litabsz]; struct hashent * lvtab[128]; int * kwptr; #ifdef M6502 #else struct hashent * htab[HTABSZ]; char * macarg[MABX}CARGSZ]; char * machtab[HTABSZ]; #endif char optimize = 0; /* optimize flag */ char verbose = 0; /* verbose flag */ int n_BY}funargs = 0; /* for use by funarg parser */ int asm_kludge = 0; /* see preproc, lex */ char * incl_dir = 0; /* dir for incBZ}lude files */ /* char get_test = 0; /* flag for doif etc to tell getmem to generate a test, not a load */ #ifndef M650B[}2 char source = 0; /* include source in m65 */ #endif tc to tell getmem to generate a test, not a load */ #ifndef M650@7 /* C I/O functions */ #include #ifndef M6502 /* every time I thing some C weenie someplace might have opted to doF]} something in a regular fashion, I get disappointed... */ #include #endif #include "cc65.h" #include "cclex.h" F^}#ifndef M6502 int outcnt = 0; #endif /* not used? char ascii_tab[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, F_}0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,F`} 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,Fa} 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };Fb} */ /* alpha( c ) Test if given character is alpha. */ /* not used... alpha(c) int c; { return( ascii_tab[c] & 1 ); Fc}} */ /* numeric( c ) Test if given character is numeric */ /* not used numeric(c) int c; { return( ascii_tab[c] & 2 Fd}); } */ /* an( c ) Test if given character is alphanumeric */ /* not used an(c) int c; { return( ascii_tab[c] ); } *Fe}/ /* pl( str ) Print a string followed by a carriage return. */ /* not used? pl(str) char * str; { printf("%s\n", stFf}r); } */ /* apparently, all callers of this have been redefined with defines.... ch() { #ifdef M6502 return( *lptr );Fg} #else return( *lptr & 0xFF ); #endif } */ #ifdef M6502 #asm .globl _nch _nch: ldx #0 ldy #0 lda (_lptr),y beq nch1Fh} iny lda (_lptr),y nch1: rts #endasm #else nch() { if (*lptr == '\0') { return (0); } else { #ifdef Fi}M6502 return (lptr[1]); #else return (lptr[1] & 0xFF); #endif } } #endif /* cgch() Get the current charFj}acter in the input stream and advance line pointer (unless already at end of line). */ #ifdef M6502 #asm .globl _cgch _cgcFk}h: ldx #0 ldy #0 lda (_lptr),y bne cgch1 rts cgch1: inc _lptr bne cgch2 inc _lptr+1 cgch2: cmp #0 ; return cond codFl}es rts #endasm #else cgch() { if (*lptr == '\0') { return (0); } else { #ifdef M6502 return (*lpFm}tr++); #else return (*lptr++ & 0xFF); #endif } } #endif /* gch() Get the current character in the input streaFn}m and advance line pointer (no end of line check is performed). */ #ifdef M6502 #asm .globl _gch _gch: ldx #0 lda (_lptrFo},x) inc _lptr bne gch1 inc _lptr+1 gch1: cmp #0 ; return cond codes rts #endasm #else gch() { #ifdef M6502 return (*lFp}ptr++); #else return (*lptr++ & 0xFF); #endif } #endif #ifdef M6502 #asm .globl _kill _kill: lda _line sta _lptr lda Fq}_line+1 sta _lptr+1 ldx #0 txa sta (_lptr,x) rts #endasm #else kill() { lptr = line; *lptr = '\0'; } #endif /* rFr}eadline() Get a line from the current input. Returns -1 on end of file. */ readline() { int k; int len; struct filent * pfFs}tab; while (1) { kill(); if (inp == 0) { eof = 1; return (0); } #ifdef old_cruft k = ciov(inFt}p, 5, line, linesize, -1, -1); poke(CRITIC, critic); len = dpeek(0x348 + (inp << 4)); #else k = (int) fgetsFu}(line, linesize, inp); len = strlen(line); #endif ++ln; if (k <= 0) /* eof? */ { line[len] = '\0'; cFv}close(inp); /* fclose(inp); */ if (ifile > 0) { inp = (pftab = &filetab[--ifile])->f_iocb; ln = pfFw}tab->f_ln; fin = pftab->f_name; } else { inp = 0; } } else { line[len - 1] = '\0';Fx} #ifndef M6502 if (source && (strlen(line) > 0)) { /* flushout(); this is broken... */ /* cout(';'); sout(line)Fy}; cout('\n'); */ ot(";"); ol(line); } #endif } if (len) { lptr = line; return (1); } Fz}} } /* flushout() Flush output queue */ flushout() { *outqi = '\0'; peephole(outq); outqi = outq; } /* Output cF{}har c to assembler file. Really just goes out to buffer, so the optimizer can work on it. */ #ifdef M6502 #asm .globl _ouF|}tchar _outchar: jsr popax ldy #0 sta (_outqi),y inc _outqi bne *+4 inc _outqi+1 rts #endasm #else outchar(c) char c; {F}} #ifndef M6502 ++outcnt; #endif *outqi++ = c; } #endif #ifdef old_cruft /* rmvbyte( n ) Remove n bytes from output F~}stream. */ rmvbyte(n) int n; { outqi -= n; } #endif /* out char to real output file */ cout(ch) char ch; { errno = 0; F} fputc(ch, output); if (errno != 0) { printmsg("IO error #x%x\n", errno); #ifdef M6502 closeall(); #endif F} exit(1); } } /* out string to real output file */ #ifdef M6502 #asm .globl _sout _sout: jsr popax sta ptr4 stx F}ptr4+1 sout1: ldy #0 lda (ptr4),y beq sout2 ldx #0 jsr pushax ldy #1 jsr _cout inc ptr4 bne sout1 inc ptr4+1 jmp sF}out1 sout2: rts #endasm #else sout(s) char * s; { while (*s) cout(*s++); } #endif ptr4 bne sout1 inc ptr4+1 jmp sDZ /* cclex.c - lexical analyzer for compiler */ #include #ifndef M6502 /* every time I thing some C weenie someplacJ}e might have opted to do something in a regular fashion, I get disappointed... */ #include #endif #include "cc65J}.h" #include "cclex.h" #define ch() (*lptr) int amp(); int bang(); int bar(); int caret(); int dollar(); int equal(); int iJ}dent(); int langle(); int minus(); int number(); int percent(); int plus(); int pstr(); int qstr(); int rangle(); int slash()J}; int star(); int symbol(); #ifndef M6502 int under(); #endif int unkn(); int (*stab[128]) () = { unkn, unkn, unkn, unkn, J}unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, J} unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, unkn, /* */ bang, /* ! */ qstr, /* " */ unkn, /* # */ J} dollar, /* $ */ percent, /* % */ amp, /* & */ pstr, /* 'character const' */ LPAREN, /* ( */ RPAREN, /* ) J}*/ star, /* * */ plus, /* + */ COMMA, /* , */ minus, /* - */ DOT, /* . */ slash, /* / */ number, numbeJ}r, number, number, number, /* 0 - 4 */ number, number, number, number, number, /* 5 - 9 */ COLON, SEMI, langle, /* */ QUEST, unkn, ident, ident, ident, ident, ident, ident, ident, ident, /* A - H J}*/ ident, ident, ident, ident, ident, ident, ident, ident, /* I - P */ ident, ident, ident, ident, ident, ident, ident, iJ}dent, /* Q - X */ ident, ident, LBRACK, unkn, /* \ */ RBRACK, caret, /* ^ */ #ifndef M6502 /* only include this J}in cross compiler */ under, /* _ */ #else /* save space by not treating underbars special in native compiler */ ident, #J}endif unkn, /* ` */ symbol, symbol, symbol, symbol, symbol, symbol, symbol, symbol, /* a - h */ symbol, symbol, symbol,J} symbol, symbol, symbol, symbol, symbol, /* i - p */ symbol, symbol, symbol, symbol, symbol, symbol, symbol, symbol, /* q -J} x */ symbol, symbol, LCURLY, bar, /* | */ RCURLY, COMP, unkn /* */ }; /* gettok() Make next tokeJ}n current token. And read another token from the input stream. */ static char * pp_line = ";;"; static char * old_lptr; sJ}tatic int asm_unkludge() /* return t if still kludged */ { if (asm_kludge > 0) { if (--asm_kludge == 1) /* down tJ}o 1? */ { lptr = old_lptr; /* restore old line */ doasm(); /* do the asm stuff */ kill(); } else { lptrJ} = pp_line; return (1); } } return (0); } gettok() { int (*f) (); #ifdef M6502 chkbrk(); /* check for user hiJ}tting break key */ #endif curtok = nxttok; curval = nxtval; if (asm_unkludge()) { curtok = SEMI; returnJ}; } /* * pick up next token from input stream. */ while (1) { while (ch() == 0) { if (readline() J}== 0) { nxttok = CEOF; return; } preprocess(); /* kludge added by jrd. if see a #asm directive coJ}ming up, force a semicolon token, to terminate previous stmt. This'll lose if you do it in the middle of something likJ}e a for stmt. big deal... */ if (matchstr(lptr, "#asm")) /* see a #asm dir? */ { asm_kludge = 3; /* force 2J} semicolons */ old_lptr = lptr; lptr = pp_line; break; } } if (ch() == ' ') ++lptr; eJ}lse break; } #ifdef M6502 if ((nxttok = (int) stab[ch()]) & 0xFF00) #else if ((nxttok = (int) stab[ch()]) & 0xFFFFFJ}F00) #endif { (*((int (*) ()) nxttok)) (); } else { ++lptr; } } #ifndef M6502 /* only grok speJ}cial symbols if not native compiler */ under() { char * q; char token[NAMESIZE]; symname(token); if (token[1] == '_') J} { if (strcmp(token, "__FILE__") == 0) { nxtval = litptr; q = fin; while (*q) litq[litptr++] = *q++; J} litq[litptr++] = '\0'; nxttok = SCONST; return; } else if (strcmp(token, "__LINE__") == 0) { nxttok = ICONSJ}T; nxtval = ln; return; } } nxtval = addsym(token); nxttok = IDENT; } #endif symbol() { char token[NAMESIZE]J}; symname(token); if (nxttok = Search(token)) { return; } else { nxtval = addsym(token); J} nxttok = IDENT; } } ident() { char token[NAMESIZE]; symname(token); nxtval = addsym(token); nxttok = IDENT; } /J}* util fun used by dollar(). set nxttok and bump line ptr */ rettok(tok) int tok; { nxttok = tok; ++lptr; } dollar() { J}int c; switch (c = *++lptr) { case '(': rettok(LCURLY); break; case ')': rettok(RCURLY); J} break; case '-': rettok(COMP); break; #ifdef old_cruft else if (c == '<') { gch(); nxttJ}ok = 201; } else if (c == '>') { gch(); nxttok = 202; } else if (c == '+') { gch(); nxttok = 203;J} } else if (c == '#') { gch(); nxttok = 204; } #endif default: unkn(); } } plus() { int c; sJ}witch (c = *++lptr) { case '+': rettok(INC); break; case '=': rettok(PASGN); break; dJ}efault: nxttok = PLUS; } } minus() { int c; switch (c = *++lptr) { case '-': rettok(DEC); bJ}reak; case '=': rettok(SASGN); break; case '>': rettok(PREF); break; default: nxttoJ}k = MINUS; } } star() { if (*++lptr == '=') { rettok(MASGN); } else { nxttok = STAR; } }J} slash() { if (*++lptr == '=') { rettok(DASGN); } else { nxttok = DIV; } } amp() { int c; J} switch (c = *++lptr) { case '&': rettok(DAMP); break; case '=': rettok(AASGN); break; J} default: nxttok = AMP; } } bar() { int c; switch (c = *++lptr) { case '|': rettok(DBAR); J} break; case '=': rettok(OASGN); break; default: nxttok = BAR; } } bang() { if (*++lptr == 'J}=') { rettok(NE); } else { nxttok = BANG; } } equal() { if (*++lptr == '=') { rettJ}ok(EQ); } else { nxttok = ASGN; } } langle() { int c; switch (c = *++lptr) { case '=': J}rettok(LE); break; case '<': if (*++lptr == '=') { rettok(SLASGN); } else { nxttok = ASL; } J} break; default: nxttok = LT; } } rangle() { int c; switch (c = *++lptr) { case '=': rettJ}ok(GE); break; case '>': if (*++lptr == '=') { rettok(SRASGN); } else { nxttok = ASR; } J} break; default: nxttok = GT; } } caret() { if (*++lptr == '=') { rettok(XOASGN); } else J} { nxttok = XOR; } } percent() { if (*++lptr == '=') { rettok(MOASGN); } else { nxttokJ} = MOD; } } /* issym( s ) Get symbol from input stream or return 0 if not a symbol. */ issym(s) char * s; { /* exJ}tern char ascii_tab[128]; */ if (is_alpha(ch())) { symname(s); return (1); } else { returnJ} (0); } } /* symname( s ) Get symbol from input stream or return 0 if not a symbol. */ symname(s) char * s; { /* J}extern char ascii_tab[128]; */ int k; k = 0; do { if (k != NAMEMAX) { ++k; *s++ = * lptr++; } elseJ} { ++lptr; } } while (is_alpha(ch()) || isdigit(ch())); *s = '\0'; } number() { int base; char c; int k; J}k = 0; base = 10; if (ch() == '0') { /* * gobble 0 and examin next char */ c = *++lptr; J} if (toupper(c) == 'X') { base = 16; ++lptr; /* gobble "x" */ } else { base = 8; } } while (1) J} { if (isdigit(c = toupper(ch()))) { k = k * base + (c - '0'); } else if (base == 16) { if (c >= 'A' &J}& c <= 'F') c -= 55; else /* if (c >= 'a' && c <= 'f') c -= 87; else */ break; /* not hex */ kJ} = k * base + c; } else break; /* not digit */ ++lptr; /* gobble char */ } nxtval = k; nxttok = ICJ}ONST; } /* pstr( val ) Parse a character constant. */ pstr() { int k; int c; k = 0; ++lptr; while ((c = cgch()) !J}= 39 && c != '\0') { k = ((k & 0xFF) << 8) + parsech(c); } nxtval = k; nxttok = CCONST; } /* qstr( val )J} Parse a quoted string */ qstr() { ++lptr; nxtval = litptr; nxttok = SCONST; while (ch() != '"') { if (chJ}() == 0) { Error("new-line in string constant"); break; } if (litptr >= 512) { fatal("string space exhausteJ}d"); /* while (gch() != '"') if (ch() == 0) break; return; */ } litq[litptr++]J} = parsech(gch()); } cgch(); litq[litptr++] = 0; } /* Parse a character. * converts \n into EOL, etc. */ parsech(cJ}hr) int chr; { int c; int i; int oct; /* pass through unless backslash */ if (chr != 92) return (chr); switch (c J}= ch()) { case 'b': c = 126; break; case 'f': c = 125; break; /* CLEAR */ case 'g':J} c = 253; break; /* Bell */ case 'n': c = 155; break; /* EOL */ case 't': c = 127; J} break; /* TAB */ default: if (c >= '0' && c <= '7') { /* * octal (yuk) constant *J}/ oct = c - '0'; gch(); i = 1; while (i <= 2) { if ((c = ch()) <'0' || c > '7') break; oct =J} (oct << 3) + c - '0'; gch(); ++i; } return (oct); } } cgch(); /* skip code char */ return (H}