/************************************************************** * C02 Compiler - (C) 2013 Curtis F Kaylor * * * * C02 is a simpified C-like language designed for the 6502 * * * * This Compiler generates crasm compatible assembly language * * * **************************************************************/ #include #include #include #include #include #include "common.h" //Common Code used by all Modules #include "files.h" //Open and Close Files #include "asm.h" //Write out Assembly Language #include "parse.h" //General Code Parsing #include "vars.h" //Variable Parsing, Lookup, and Allocation #include "expr.h" //Expression Parsing #include "label.h" //Label Parsing, Generation, and Lookup #include "cond.h" //Conditional Parsing #include "stmnt.h" //Statement Compiling Code #include "dclrtn.h" //Statement Compiling Code #include "include.h" //Include File Parsing /* Initilize Compiler Variables */ void init(void) { DEBUG("c02.init: Initializing Compiler Variables\n",0) concnt = 0; //Number of Constants Defined varcnt = 0; //Number of Variables in Table lblcnt = 0; //Number of Labels in stack padcnt = 0; //Number of Padding Bytes at End curcol = 0; //Current Column in Source Code curlin = 0; //Current Line in Source Code alcvar = TRUE; //Allocate Variables Flag inblck = FALSE; //Multiline Block Flag infunc = FALSE; //Inside Function Definition xstmnt[0] = 0; //Expected Statement nxtwrd[0] = 0; //Next Word (from DEFINE lookup) nxtptr = 0; //Pointer to next character in nxtwrd vrwrtn = FALSE; //Variables Written Flag rambas = 0; //RAM Base Address wrtbas = 0; //Write Base Address zpaddr = 0; //Current Zero-Page Address zpgbgn = 0; //Start of Free Zero-Page zpgend = 0xFF; //End of Free Zero-Page invasc = FALSE; //Invert ASCII Flag mskasc = FALSE; //Set High Bit Flag fcase = FALSE; //First Case Statement Flag wrtofs[0] = 0; //Write Offset xsnvar[0] = 0; //Assigned X Variable Name ysnvar[0] = 0; //Assigned Y Variable Name subcnt = 0; //Include Subdirectories strcpy(cputyp, CPUARG); //Set CPU Type to Default Value strcpy(incdir, "../include/"); } /* Parse Pointer Dereference Assignment */ void ppntr(void) { lsrtrn = FALSE; //Clear RETURN flag if (xstmnt[0]) ERROR("Expected '%s' statement\n", xstmnt, EXIT_FAILURE) prcasp(';'); } /* Reads and parses the next Word in Source File */ void pword(void) { lsrtrn = FALSE; //Clear RETURN flag getwrd(); DEBUG("c02.pword: Parsing Word '%s'\n", word) if (xstmnt[0]) { if (wordis(xstmnt)) xstmnt[0] = 0; //Clear xstmnt else ERROR("Expected '%s' statement\n", xstmnt, EXIT_FAILURE) } if (!pmodfr() && !ptype(MTNONE)) pstmnt(); //Parse Statement } /* Process a directive */ void pdrctv(void) { skpchr(); //skip '#' CCMNT('#'); getwrd(); //read directive into word DEBUG("c02.pdrctv: Processing directive '%s'\n", word) if (wordis("DEFINE")) pdefin(); //Parse Define else if (wordis("INCLUDE")) pincfl(); //Parse Include File else if (wordis("ERROR")) ERROR("Error \n", 0, EXIT_FAILURE) else if (wordis("PRAGMA")) pprgma(); else ERROR("Illegal directive %s encountered\n", word, EXIT_FAILURE) } void prolog(void) { DEBUG("c02.prolog: Writing Assembly Prolog\n", 0) if (strlen(cputyp)) asmlin(CPUOP,cputyp); setcmt("Program "); addcmt(srcnam); cmtlin(); } void epilog(void) { if (!vrwrtn) wvrtbl(); //Write Variable Table if (padcnt) { SCMNT("PADDING BYTES") sprintf(word, "$%hhX", padcnt); asmlin(STROP, word); } } /* Compile Source Code*/ void compile(void) { DEBUG("c02.compile: Starting Compilation\n", 0) prolog(); phdrfl(); //Process Header File specified on Command Line skpchr(); DEBUG("c02.compile: Parsing Code\n", 0) while (TRUE) { skpspc(); if (match(EOF)) break; //Stop Parsing (End of File) else if (match('}')) endblk(TRUE); //End Multi-Line Program Block else if (match('#')) pdrctv(); //Parse Directive else if (match('/')) skpcmt(TRUE); //Skip Comment else if (match('*')) ppntr(); //Parse Pointer else if (isalph()) pword(); //Parse Word else ERROR("Unexpected character '%c'\n", nxtchr, EXIT_FAILURE) } epilog(); } /* Display "Usage" text and exit*/ void usage(void) { printf("Usage: c02 sourcefile.c02\n"); exit(EXIT_FAILURE); } /* Parse Command Line Option */ int popt(int arg, int argc, char *argv[]) { char argstr[32]; //Argument String char opt; //Option char optarg[32]; //Option Argument strncpy (argstr, argv[arg], 31); if (strlen(argstr) != 2) ERROR("malformed option %s\n", argstr, EXIT_FAILURE) opt = toupper(argstr[1]); if (strchr("CHIS", opt)) { if (++arg >= argc) ERROR("Option -%c requires an argument\n", opt, EXIT_FAILURE) strncpy(optarg, argv[arg], 31); } DEBUG("c02.popt: Processing Command Line Option -%c\n", argstr[1]) switch (opt) { case 'D': debug = TRUE; DEBUG("c02.popt: Debug output enable\n", 0) break; case 'C': strcpy(cputyp, optarg); DEBUG("c02.popt: CPU Type set to '%s'\n", cputyp) break; case 'H': strcpy(hdrnam, optarg); DEBUG("c02.popt: Header Name set to '%s'\n", hdrnam) break; case 'I': strcpy(incdir, optarg); strcat(incdir, "/"); DEBUG("c02.popt: Include Directory set to '%s'\n", incdir) break; case 'S': strcpy(subdir[subcnt], optarg); DEBUG("c02.popt: subdir[%d] ", subcnt) DETAIL("set to '%s'\n", subdir[subcnt]) subcnt++; break; default: ERROR("Illegal option -%c\n", opt, EXIT_FAILURE) } return arg; } /* Parse Command Line Arguments * * Sets: srcnam - Source File Name (from first arg) * * outnam - Output File Name (from optional second arg) */ void pargs(int argc, char *argv[]) { int arg; srcnam[0] = 0; outnam[0] = 0; DEBUG("c02.pargs: Parsing %d arguments\n", argc) if (argc == 0) usage(); //at least one argument is required for (arg = 1; arg