diff --git a/src/.vscode/ipch/771b4d3d25e434c7/C02.ipch b/src/.vscode/ipch/771b4d3d25e434c7/C02.ipch new file mode 100644 index 0000000..f6d23ac Binary files /dev/null and b/src/.vscode/ipch/771b4d3d25e434c7/C02.ipch differ diff --git a/src/.vscode/ipch/771b4d3d25e434c7/mmap_address.bin b/src/.vscode/ipch/771b4d3d25e434c7/mmap_address.bin new file mode 100644 index 0000000..862b842 Binary files /dev/null and b/src/.vscode/ipch/771b4d3d25e434c7/mmap_address.bin differ diff --git a/src/.vscode/launch.json b/src/.vscode/launch.json new file mode 100644 index 0000000..8870f0a --- /dev/null +++ b/src/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(Windows) Launch", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/c02.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true + } + ] +} \ No newline at end of file diff --git a/src/asm.c b/src/asm.c index 41dc1bb..9c82ae6 100644 --- a/src/asm.c +++ b/src/asm.c @@ -1,36 +1,36 @@ -/************************************* - * C02 Assembly Language Routines * - *************************************/ - -#include -#include -#include -#include -#include - -#include "common.h" -#include "files.h" -#include "asm.h" - -/* Process comment */ -void prccmt(void) { - if (strlen(cmtasm)) { strcpy(asmcmt, ";"); strcat(asmcmt, cmtasm); } - else asmcmt[0] = 0; - setcmt(""); -} - -/* output a single line of assembly code */ -void asmlin(char *opcode, char *oprnd) { - if (strlen(lblasm)) strcat(lblasm, LABSFX); - prccmt(); - fprintf(outfil, ASMFMT, lblasm, opcode, oprnd, asmcmt); - if (debug) printf(ASMFMT, lblasm, opcode, oprnd, asmcmt); - lblasm[0] = 0; -} - -/* output a single comment line */ -void cmtlin(void) { - DEBUG("Writing Comment Line: %s\n", cmtasm) - fprintf(outfil, "; %s\n", cmtasm); - setcmt(""); -} +/************************************* + * C02 Assembly Language Routines * + *************************************/ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "files.h" +#include "asm.h" + +/* Process comment */ +void prccmt(void) { + if (strlen(cmtasm)) { strcpy(asmcmt, ";"); strcat(asmcmt, cmtasm); } + else asmcmt[0] = 0; + setcmt(""); +} + +/* output a single line of assembly code */ +void asmlin(char *opcode, char *oprnd) { + if (strlen(lblasm)) strcat(lblasm, LABSFX); + prccmt(); + fprintf(outfil, ASMFMT, lblasm, opcode, oprnd, asmcmt); + if (debug) printf(ASMFMT, lblasm, opcode, oprnd, asmcmt); + lblasm[0] = 0; +} + +/* output a single comment line */ +void cmtlin(void) { + DEBUG("Writing Comment Line: %s\n", cmtasm) + fprintf(outfil, "; %s\n", cmtasm); + setcmt(""); +} diff --git a/src/asm.h b/src/asm.h index eb5c10b..b482ad5 100644 --- a/src/asm.h +++ b/src/asm.h @@ -1,9 +1,9 @@ -/************************************* - * C02 Assembly Language Routines * - *************************************/ - -char lblasm[LBLLEN+2]; //Label to emit on next asm line - -void asmlin(char *opcode, char *oprnd); //Output a line of assembly code -void cmtlin(); //Output a comment lines -void prccmt(); //Process comment +/************************************* + * C02 Assembly Language Routines * + *************************************/ + +char lblasm[LBLLEN+2]; //Label to emit on next asm line + +void asmlin(char *opcode, char *oprnd); //Output a line of assembly code +void cmtlin(); //Output a comment lines +void prccmt(); //Process comment diff --git a/src/c02.c b/src/c02.c index d5ce76b..a73658f 100644 --- a/src/c02.c +++ b/src/c02.c @@ -1,203 +1,227 @@ -/************************************************************** - * 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) { - initim(); //Initialize Elapsed Time - DEBUG("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 - 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(incdir, "../include/"); -} - -/* Reads and parses the next Word in Source File */ -void pword(void) { - lsrtrn = FALSE; //Clear RETURN flag - getwrd(); - DEBUG("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("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("Writing Assembly Prolog\n", 0) - asmlin(CPUOP,CPUARG); - 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("Starting Compilation\n", 0) - prolog(); - phdrfl(); //Process Header File specified on Command Line - skpchr(); - DEBUG("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 (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("HS", opt)) { - if (++arg >= argc) ERROR("Option -%c requires an argument\n", opt, EXIT_FAILURE) - strncpy(optarg, argv[arg], 31); - } - DEBUG("Processing Command Line Option -%c\n", argstr[1]) - switch (opt) { - case 'H': - strcpy(hdrnam, optarg); - DEBUG("Header Name set to '%s'\n", hdrnam) - break; - case 'S': - strcpy(subdir[subcnt], optarg); - DEBUG("subdir[%d] ", subcnt) - DEBUG("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("Parsing %d arguments\n", argc) - if (argc == 0) usage(); //at least one argument is required - for (arg = 1; arg +#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) { + initim(); //Initialize Elapsed Time + DEBUG("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 + 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("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("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("Writing Assembly Prolog\n", 0) + 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("Starting Compilation\n", 0) + prolog(); + phdrfl(); //Process Header File specified on Command Line + skpchr(); + DEBUG("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("CHS", opt)) { + if (++arg >= argc) ERROR("Option -%c requires an argument\n", opt, EXIT_FAILURE) + strncpy(optarg, argv[arg], 31); + } + DEBUG("Processing Command Line Option -%c\n", argstr[1]) + switch (opt) { + case 'C': + strcpy(cputyp, optarg); + DEBUG("CPU Type set to '%s'\n", cputyp) + break; + case 'H': + strcpy(hdrnam, optarg); + DEBUG("Header Name set to '%s'\n", hdrnam) + break; + case 'S': + strcpy(subdir[subcnt], optarg); + DEBUG("subdir[%d] ", subcnt) + DEBUG("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("Parsing %d arguments\n", argc) + if (argc == 0) usage(); //at least one argument is required + for (arg = 1; arg -#include -#include -#include -#include -#include -#include "common.h" - -struct timespec curtim; //Current Time - -/* Error - Print Input File name & position and exit */ -void exterr(int errnum) { - fprintf(stderr, "Line %d Column %d of File %s\n", curlin, curcol, inpnam); - exit(errnum); -} - -/* Error - print "Expected" error message * - and exit with general failure code * - Args: expected - Description of what was expected */ -void expctd(char *expstr) { - fprintf(stderr, "Expected %s, but found '%c'\n", expstr, nxtchr); - exterr(EXIT_FAILURE); -} - -/* Print current position in file */ -void prtpos(void) { if (inpnam[0]) printf("(%s: %d,%d) ", inpnam, curlin, curcol); } - -/* Initialize elapsed time counter */ -void initim(void) { - timespec_get (&curtim, TIME_UTC); - bgntim = curtim.tv_sec; -} - -/* Print elapsed time */ -void prttim(void) { - timespec_get (&curtim, TIME_UTC); - printf("[%d", curtim.tv_sec - bgntim); - printf(".%06d]",curtim.tv_nsec/1000); -} - -/* Set comment to string */ -void setcmt(char *s) { strcpy(cmtasm, s); } - -/* Append string to comment */ -void addcmt(char *s) { - if (strlen(cmtasm)+strlen(s)<73) strcat(cmtasm, s); -} - -/* Append character to comment */ -void chrcmt(char c) { - if (strlen(cmtasm)>72) return; - if (cmtasm[0] == 0 && c == ' ') return; - int i = strlen(cmtasm); - cmtasm[i++] = c; - cmtasm[i] = 0; -} +/************************************* + * C02 Common Definitions & Routines * + *************************************/ + +#include +#include +#include +#include +#include +#include +#include "common.h" + +struct timespec curtim; //Current Time + +/* Error - Print Input File name & position and exit */ +void exterr(int errnum) { + fprintf(stderr, "Line %d Column %d of File %s\n", curlin, curcol, inpnam); + exit(errnum); +} + +/* Error - print "Expected" error message * + and exit with general failure code * + Args: expected - Description of what was expected */ +void expctd(char *expstr) { + fprintf(stderr, "Expected %s, but found '%c'\n", expstr, nxtchr); + exterr(EXIT_FAILURE); +} + +/* Print current position in file */ +void prtpos(void) { if (inpnam[0]) printf("(%s: %d,%d) ", inpnam, curlin, curcol); } + +/* Initialize elapsed time counter */ +void initim(void) { + timespec_get (&curtim, TIME_UTC); + bgntim = curtim.tv_sec; +} + +/* Print elapsed time */ +void prttim(void) { + timespec_get (&curtim, TIME_UTC); + printf("[%d", curtim.tv_sec - bgntim); + printf(".%06d]",curtim.tv_nsec/1000); +} + +/* Set comment to string */ +void setcmt(char *s) { strcpy(cmtasm, s); } + +/* Append string to comment */ +void addcmt(char *s) { + if (strlen(cmtasm)+strlen(s)<73) strcat(cmtasm, s); +} + +/* Append character to comment */ +void chrcmt(char c) { + if (strlen(cmtasm)>72) return; + if (cmtasm[0] == 0 && c == ' ') return; + int i = strlen(cmtasm); + cmtasm[i++] = c; + cmtasm[i] = 0; +} diff --git a/src/common.h b/src/common.h index 85ab48b..7ebee84 100644 --- a/src/common.h +++ b/src/common.h @@ -1,94 +1,98 @@ -/************************************* - * C02 Common Definitions & Routines * - *************************************/ - -#define FNAMLEN 255 //Maximum File Name Length -#define LINELEN 255 //Maximum Input/Output Line Length -#define CONLEN 6 //Maximum Constant Name Length -#define MAXCON 255 //Maximum Number of Constants -#define STCLEN 6 //Maximum Struct Name Length -#define MAXSTC 32 //Maximum Number of Stuctures -#define STMLEN 6 //Maximum Struct Member Name Length -#define MAXSTM 255 //Maximum Number of Stucture Members -#define VARLEN 6 //Maximum Variable Name Length -#define MAXVAR 255 //Maximum Number of Variables -#define MAXTRM 16 //Maximum Terms in Stack -#define DATASPC 4096 //Space to Allocate for Variable Data -#define SUBMAX 4 //Maximum Number of Sub Directories - -#define LABLEN 6 //Maximum Program Label Length -#define MAXLAB 255 //Maximum Number of Program Labels - -#define LBLLEN 6 //Maximum Label Length -#define LBLFMT "L_%04d" //Label Format -#define LABSFX ":" //Label Suffix -#define MAXLBL 15 //Maximum Number of Labels (Nesting Depth) -#define LOCPFX "." //Local Variable Prefix - -#define CPUOP "PROCESSOR" //Target CPU Pseudo-Operator -#define CPUARG "6502" //Target CPU Operand -#define ORGOP "ORG" //Origin Pseudo-Op -#define EQUOP "EQU" //Equate Pseudo-Op -#define BYTEOP "DC" //Define Byte Pseudo-Op -#define STROP "DS" //Define String Pseudo-Op -#define ALNOP "ALIGN" //Align Pseudo-Op -#define USEGOP "SEG.U" //Uninitalized Segment Pseudo-Op -#define LOCOP "SUBROUTINE" //Local Variable Boundary Pseudo-Op - -#define ASMFMT "%-7s %-3s %-12s %s\n" //Assembly Language Line printf Format - -/* Internal defines */ -#define TRUE -1 -#define FALSE 0 - -void initim(); //Initialize elapsed time counter -void prtpos(); //Print current file name and position -void prttim(); //Print elapsed time -#define DEBUG(fmt, val) {if (debug) {prtpos(); prttim(); printf(fmt, val);}} -#define DETAIL(fmt, val) {if (debug) printf(fmt, val);} -#define ERROR(fmt, val, err) {fprintf(stderr, fmt, val);exterr(err);} - -int debug; //Print Debug Info (TRUE or FALSE) - -int gencmt; //Generate Assembly Language Comments -char asmcmt[LINELEN]; //Processed Assembly Language Comment - -int curcol, curlin; //Position in Source Code -int savcol, savlin; //Save Position in Source Code - -int bgntim; //Starting Time - -int nxtchr; //Next Character of Source File to Process -int nxtupc; //Next Character Converted to Uppercase -int savchr; //Holds nxtchr when switching input files - -int wrdlen; //Length of Parsed Word -char word[LINELEN]; //Word parsed from source file -char uword[LINELEN]; //Word converted to uppercase -char cmtasm[LINELEN]; //Assembly Language Comment Text - -char hdrnam[FNAMLEN]; //Header File Name -char incdir[FNAMLEN]; //Include File Directory -char inpnam[FNAMLEN]; //Input File Name -char subdir[SUBMAX][FNAMLEN]; //Include File SubDirectory -int subcnt; //Number of Include Directories -int subidx; //Index into subdir[] - -int alcvar; //Allocate Variables Flag -int inblck; //Multiline Block Flag -int infunc; //Inside Function Definition Flag -int lsrtrn; //Last Statement was a Return Flag -int fcase; //First Case Statement Flag - -int padcnt; //Number of Padding Bytes at End of Program - -void exterr(int errnum); //Print current file name & position and exit -void expctd(char *expected); //Print Expected message and exit - -void addcmt(char *s); //Append string to comment -void chrcmt(char c); //Append character to comment -void setcmt(char *s); //Set comment to string -#define SCMNT(str) if (gencmt) {setcmt(str);} -#define ACMNT(str) if (gencmt) {addcmt(str);} -#define CCMNT(chr) if (gencmt) {chrcmt(chr);} -#define LCMNT(str) if (gencmt) {setcmt(str); cmtlin();} +/************************************* + * C02 Common Definitions & Routines * + *************************************/ + +#define FNAMLEN 255 //Maximum File Name Length +#define LINELEN 255 //Maximum Input/Output Line Length +#define CONLEN 6 //Maximum Constant Name Length +#define MAXCON 255 //Maximum Number of Constants +#define STCLEN 6 //Maximum Struct Name Length +#define MAXSTC 32 //Maximum Number of Stuctures +#define STMLEN 6 //Maximum Struct Member Name Length +#define MAXSTM 255 //Maximum Number of Stucture Members +#define VARLEN 6 //Maximum Variable Name Length +#define MAXVAR 255 //Maximum Number of Variables +#define MAXTRM 16 //Maximum Terms in Stack +#define DATASPC 4096 //Space to Allocate for Variable Data +#define SUBMAX 4 //Maximum Number of Sub Directories + +#define LABLEN 6 //Maximum Program Label Length +#define MAXLAB 255 //Maximum Number of Program Labels + +#define LBLLEN 6 //Maximum Label Length +#define LBLFMT "L_%04d" //Label Format +#define LABSFX ":" //Label Suffix +#define MAXLBL 15 //Maximum Number of Labels (Nesting Depth) +#define LOCPFX "." //Local Variable Prefix + +#define CPUOP "PROCESSOR" //Target CPU Pseudo-Operator +#define CPUARG "6502" //Target CPU Operand +#define ORGOP "ORG" //Origin Pseudo-Op +#define EQUOP "EQU" //Equate Pseudo-Op +#define BYTEOP "BYTE" //Define Byte Pseudo-Op +#define STROP "DS" //Define String Pseudo-Op +#define ALNOP "ALIGN" //Align Pseudo-Op +#define USEGOP "SEG.U" //Uninitalized Segment Pseudo-Op +#define LOCOP "SUBROUTINE" //Local Variable Boundary Pseudo-Op + +#define ASMFMT "%-7s %-3s %-12s %s\n" //Assembly Language Line printf Format + +/* Internal defines */ +#define TRUE -1 +#define FALSE 0 + +void initim(); //Initialize elapsed time counter +void prtpos(); //Print current file name and position +void prttim(); //Print elapsed time +#define DEBUG(fmt, val) {if (debug) {prtpos(); prttim(); printf(fmt, val);}} +#define DETAIL(fmt, val) {if (debug) printf(fmt, val);} +#define ERROR(fmt, val, err) {fprintf(stderr, fmt, val);exterr(err);} + +int debug; //Print Debug Info (TRUE or FALSE) +int cmos; //Flag: Use 65C02 Instruction Set + +int gencmt; //Generate Assembly Language Comments +char asmcmt[LINELEN]; //Processed Assembly Language Comment + +int curcol, curlin; //Position in Source Code +int savcol, savlin; //Save Position in Source Code + +int bgntim; //Starting Time + +int nxtchr; //Next Character of Source File to Process +int nxtupc; //Next Character Converted to Uppercase +int savchr; //Holds nxtchr when switching input files + +int wrdlen; //Length of Parsed Word +char word[LINELEN]; //Word parsed from source file +char uword[LINELEN]; //Word converted to uppercase +int pstlen; //Length of Parsed String +char pstrng[LINELEN]; //String parsed fron source file +char cmtasm[LINELEN]; //Assembly Language Comment Text +char cputyp[LINELEN]; //CPU Type + +char hdrnam[FNAMLEN]; //Header File Name +char incdir[FNAMLEN]; //Include File Directory +char inpnam[FNAMLEN]; //Input File Name +char subdir[SUBMAX][FNAMLEN]; //Include File SubDirectory +int subcnt; //Number of Include Directories +int subidx; //Index into subdir[] + +int alcvar; //Allocate Variables Flag +int inblck; //Multiline Block Flag +int infunc; //Inside Function Definition Flag +int lsrtrn; //Last Statement was a Return Flag +int fcase; //First Case Statement Flag + +int padcnt; //Number of Padding Bytes at End of Program + +void exterr(int errnum); //Print current file name & position and exit +void expctd(char *expected); //Print Expected message and exit + +void addcmt(char *s); //Append string to comment +void chrcmt(char c); //Append character to comment +void setcmt(char *s); //Set comment to string +#define SCMNT(str) if (gencmt) {setcmt(str);} +#define ACMNT(str) if (gencmt) {addcmt(str);} +#define CCMNT(chr) if (gencmt) {chrcmt(chr);} +#define LCMNT(str) if (gencmt) {setcmt(str); cmtlin();} diff --git a/src/cond.c b/src/cond.c index 54fd01e..a74a72d 100644 --- a/src/cond.c +++ b/src/cond.c @@ -1,138 +1,138 @@ -/************************************ - * C02 Conditional Parsing Routines * - ************************************/ -#include -#include -#include -#include -#include -#include "common.h" -#include "asm.h" -#include "parse.h" -#include "vars.h" -#include "expr.h" -#include "label.h" -#include "cond.h" - -int cmprtr; //Encoded Comparison Operator -int cmpenc; //Encoded Comparator Character - -/* Encode Comparison Operator Character * - * Args: Comparison Operator Character * - * Returns: Comparison Operator Bit Mask */ -int enccmp(char c) { - int e; - DEBUG("Encoding Comparison Character '%c'", c) - switch(c) { - case '=': e = 1; break; - case '<': e = 2; break; - case '>': e = 4; break; - default: e = 0; - } - if (e) { CCMNT(c); skpchr(); } - DETAIL(", encoded as %d\n", e); - return e; -} - -/* Process and Compile Comparison Operator and * - * Args: comparator - Encoded Comparison Operator * - * Uses: term - Term Being Compared Against * - * label - Branch Target if Comparison is FALSE */ -void prccmp(void) { - DEBUG("Processing comparator %d", cmprtr) DETAIL(" with REVCMP=%d\n", revcmp) - if (cmprtr > 7) { //Process Flag - cmprtr = (cmprtr ^ revcmp) & 1; //Apply Reversal - if (cmprtr) asmlin("BPL", cmplbl); - else asmlin("BMI", cmplbl); - return; - } - cmprtr = (cmprtr ^ revcmp) & 7; //Apply reversal - switch(cmprtr) { - case 0: // Raw Expression (Skip) - asmlin("BEQ", cmplbl); break; - case 1: // = or == - asmlin("CMP", term); asmlin("BNE", cmplbl); break; - case 2: // < - asmlin("CMP", term); asmlin("BCS", cmplbl); break; - case 3: // <= or =< - asmlin("CLC", ""); asmlin("SBC", term); asmlin("BCS", cmplbl); break; - case 4: // > - asmlin("CLC", ""); asmlin("SBC", term); asmlin("BCC", cmplbl); break; - case 5: // >= or => - asmlin("CMP", term); asmlin("BCC", cmplbl); break; - case 6: // <> or >< - asmlin("CMP", term); asmlin("BEQ", cmplbl); break; - case 7: // Raw Expression (Normal) - asmlin("BNE", cmplbl); break; - default: - ERROR("Unsupported comparison operator index %d\n", cmprtr, EXIT_FAILURE) - } -} - -/* Parse Comparison */ -void prscmp(int revrse) { - skpspc(); - cmpenc = enccmp(nxtchr); //Encode Comparison Character - cmprtr = cmpenc; //Set Encoded Comparator - if (cmprtr) { - cmpenc = enccmp(nxtchr); //Encode Next Comparison Character - if (cmpenc != 0) cmprtr = cmprtr | cmpenc; //Combine Encoded Comparator - } - skpspc(); - if (cmprtr) prstrm(FALSE); - //prccmp(); - Do after check for logical operator - DEBUG("Parsed comparator %d\n", cmprtr) -} - -/* Parse Flag Operator */ -void prsflg(int revrse) { - DEBUG("Parsing Flag Operator '%c'\n", nxtchr) - if (match('+')) cmprtr = 8; //Bit 0 = 0 - else if (match('-')) cmprtr = 9; //Bit 1 = 1 - else expctd("Flag operator"); - skpchr(); -} - -/* Parse Logical Operator * - * Sets: logops */ -void prslop(void) { - DEBUG("Checking for Logical Operator\n", 0) - logopr = LOPNONE; - skpspc(); - if (isalph()) { - getwrd(); //Get Logical Operator - DEBUG("Parsing Logical Operator %s\n", word) - if (wordis("AND")) logopr = LOPAND; - else if (wordis("OR")) logopr = LOPOR; - else ERROR("Encountered invalid token \"%s\"\n", word, EXIT_FAILURE) - } - DEBUG("Set LOGOPR to %d\n", logopr) -} - -/* Parse and Compile Conditional Expression * - * Condition = */ -void prscnd(char trmntr, int revrse) { - DEBUG("Parsing condition with REVRSE=%d\n", revrse) - tmplbl[0] = 0; - do { - strcpy(cmplbl, cndlbl); DEBUG("Set CMPLBL to \"%s\"\n", cmplbl); - revcmp = revrse; - if (look('!')) revcmp = (revcmp) ? FALSE: TRUE; - DEBUG("Set REVCMP to %d\n", revcmp) - if (!look('.')) prsxpr(0); - if (look(':')) prsflg(revcmp); //Parse Flag Operator - else prscmp(revcmp); //Parse Comparison Operator - prslop(); //Parse Logical Operator - if (logopr == LOPOR) { - revcmp = (revcmp) ? FALSE: TRUE; - DEBUG("Set REVCMP to %d\n", revcmp) - } - if (logopr && revcmp) { - if (!tmplbl[0]) newlbl(tmplbl); - strcpy(cmplbl, tmplbl); DEBUG("Set CMPLBL to \"%s\"\n", cmplbl); - } - prccmp(); //Process Comparison/Flag Operator - } while (logopr); - if (tmplbl[0]) setlbl(tmplbl); - expect(trmntr); -} +/************************************ + * C02 Conditional Parsing Routines * + ************************************/ +#include +#include +#include +#include +#include +#include "common.h" +#include "asm.h" +#include "parse.h" +#include "vars.h" +#include "expr.h" +#include "label.h" +#include "cond.h" + +int cmprtr; //Encoded Comparison Operator +int cmpenc; //Encoded Comparator Character + +/* Encode Comparison Operator Character * + * Args: Comparison Operator Character * + * Returns: Comparison Operator Bit Mask */ +int enccmp(char c) { + int e; + DEBUG("Encoding Comparison Character '%c'", c) + switch(c) { + case '=': e = 1; break; + case '<': e = 2; break; + case '>': e = 4; break; + default: e = 0; + } + if (e) { CCMNT(c); skpchr(); } + DETAIL(", encoded as %d\n", e); + return e; +} + +/* Process and Compile Comparison Operator and * + * Args: comparator - Encoded Comparison Operator * + * Uses: term - Term Being Compared Against * + * label - Branch Target if Comparison is FALSE */ +void prccmp(void) { + DEBUG("Processing comparator %d", cmprtr) DETAIL(" with REVCMP=%d\n", revcmp) + if (cmprtr > 7) { //Process Flag + cmprtr = (cmprtr ^ revcmp) & 1; //Apply Reversal + if (cmprtr) asmlin("BPL", cmplbl); + else asmlin("BMI", cmplbl); + return; + } + cmprtr = (cmprtr ^ revcmp) & 7; //Apply reversal + switch(cmprtr) { + case 0: // Raw Expression (Skip) + asmlin("BEQ", cmplbl); break; + case 1: // = or == + asmlin("CMP", term); asmlin("BNE", cmplbl); break; + case 2: // < + asmlin("CMP", term); asmlin("BCS", cmplbl); break; + case 3: // <= or =< + asmlin("CLC", ""); asmlin("SBC", term); asmlin("BCS", cmplbl); break; + case 4: // > + asmlin("CLC", ""); asmlin("SBC", term); asmlin("BCC", cmplbl); break; + case 5: // >= or => + asmlin("CMP", term); asmlin("BCC", cmplbl); break; + case 6: // <> or >< + asmlin("CMP", term); asmlin("BEQ", cmplbl); break; + case 7: // Raw Expression (Normal) + asmlin("BNE", cmplbl); break; + default: + ERROR("Unsupported comparison operator index %d\n", cmprtr, EXIT_FAILURE) + } +} + +/* Parse Comparison */ +void prscmp(int revrse) { + skpspc(); + cmpenc = enccmp(nxtchr); //Encode Comparison Character + cmprtr = cmpenc; //Set Encoded Comparator + if (cmprtr) { + cmpenc = enccmp(nxtchr); //Encode Next Comparison Character + if (cmpenc != 0) cmprtr = cmprtr | cmpenc; //Combine Encoded Comparator + } + skpspc(); + if (cmprtr) prstrm(FALSE); + //prccmp(); - Do after check for logical operator + DEBUG("Parsed comparator %d\n", cmprtr) +} + +/* Parse Flag Operator */ +void prsflg(int revrse) { + DEBUG("Parsing Flag Operator '%c'\n", nxtchr) + if (match('+')) cmprtr = 8; //Bit 0 = 0 + else if (match('-')) cmprtr = 9; //Bit 1 = 1 + else expctd("Flag operator"); + skpchr(); +} + +/* Parse Logical Operator * + * Sets: logops */ +void prslop(void) { + DEBUG("Checking for Logical Operator\n", 0) + logopr = LOPNONE; + skpspc(); + if (isalph()) { + getwrd(); //Get Logical Operator + DEBUG("Parsing Logical Operator %s\n", word) + if (wordis("AND")) logopr = LOPAND; + else if (wordis("OR")) logopr = LOPOR; + else ERROR("Encountered invalid token \"%s\"\n", word, EXIT_FAILURE) + } + DEBUG("Set LOGOPR to %d\n", logopr) +} + +/* Parse and Compile Conditional Expression * + * Condition = */ +void prscnd(char trmntr, int revrse) { + DEBUG("Parsing condition with REVRSE=%d\n", revrse) + tmplbl[0] = 0; + do { + strcpy(cmplbl, cndlbl); DEBUG("Set CMPLBL to \"%s\"\n", cmplbl); + revcmp = revrse; + if (look('!')) revcmp = (revcmp) ? FALSE: TRUE; + DEBUG("Set REVCMP to %d\n", revcmp) + if (!look('.')) prsxpr(0); + if (look(':')) prsflg(revcmp); //Parse Flag Operator + else prscmp(revcmp); //Parse Comparison Operator + prslop(); //Parse Logical Operator + if (logopr == LOPOR) { + revcmp = (revcmp) ? FALSE: TRUE; + DEBUG("Set REVCMP to %d\n", revcmp) + } + if (logopr && revcmp) { + if (!tmplbl[0]) newlbl(tmplbl); + strcpy(cmplbl, tmplbl); DEBUG("Set CMPLBL to \"%s\"\n", cmplbl); + } + prccmp(); //Process Comparison/Flag Operator + } while (logopr); + if (tmplbl[0]) setlbl(tmplbl); + expect(trmntr); +} diff --git a/src/cond.h b/src/cond.h index d57196a..1501fe1 100644 --- a/src/cond.h +++ b/src/cond.h @@ -1,10 +1,10 @@ -/************************************ - * C02 Conditional Parsing Routines * - ************************************/ - -enum LOGOPS {LOPNONE, LOPAND, LOPOR}; - -int revcmp; //Reverse Comparison -int logopr; //Logical Operator (set to LOGOPS) - -void prscnd(char trmntr, int revrse); //Parse Conditional Expression +/************************************ + * C02 Conditional Parsing Routines * + ************************************/ + +enum LOGOPS {LOPNONE, LOPAND, LOPOR}; + +int revcmp; //Reverse Comparison +int logopr; //Logical Operator (set to LOGOPS) + +void prscnd(char trmntr, int revrse); //Parse Conditional Expression diff --git a/src/dclrtn.c b/src/dclrtn.c index 445257e..5b54d83 100644 --- a/src/dclrtn.c +++ b/src/dclrtn.c @@ -53,6 +53,7 @@ void addfnc(void) { infunc = TRUE; //Set Inside Function Definition Flag DEBUG("Set infunc to %d\n", infunc) setlbl(fncnam); //Set Function Entry Point + asmlin(LOCOP, ""); //Set Local Variables Boundary if (prmtra[0]) asmlin("STA", prmtra); //Store First Parameter if (prmtry[0]) asmlin("STY", prmtry); //Store Second Parameter if (prmtrx[0]) asmlin("STX", prmtrx); //Store Third Parameter diff --git a/src/dclrtn.h b/src/dclrtn.h index 98486f3..fcf7516 100644 --- a/src/dclrtn.h +++ b/src/dclrtn.h @@ -1,17 +1,17 @@ -/************************************ - * C02 Declaration Compiling Routines * - ************************************/ - -char fncnam[VARLEN+1]; //Function Name -char prmtra[VARLEN+1]; //Function Parameter A -char prmtrx[VARLEN+1]; //Function Parameter X -char prmtry[VARLEN+3]; //Function Parameter Y -int prmcnt; //Number of Parameters -//int lpemtd; //Location Prefix Emitted - -void addcon(int numval); //Add Constant -int pmodfr(); //Check for and Parse Modifier -int ctype(int reqtyp); //Check for Type Keyword -int ptype(int m); //Check for and Parse Type Keyword - -enum types {TNONE, TVOID, TENUM, TBITMASK,TCHAR, TINT, TSTRUCT}; +/************************************ + * C02 Declaration Compiling Routines * + ************************************/ + +char fncnam[VARLEN+1]; //Function Name +char prmtra[VARLEN+1]; //Function Parameter A +char prmtrx[VARLEN+1]; //Function Parameter X +char prmtry[VARLEN+3]; //Function Parameter Y +int prmcnt; //Number of Parameters +//int lpemtd; //Location Prefix Emitted + +void addcon(int numval); //Add Constant +int pmodfr(); //Check for and Parse Modifier +int ctype(int reqtyp); //Check for Type Keyword +int ptype(int m); //Check for and Parse Type Keyword + +enum types {TNONE, TVOID, TENUM, TBITMASK,TCHAR, TINT, TSTRUCT}; diff --git a/src/expr.c b/src/expr.c index ad7c6b8..807cee4 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1,372 +1,454 @@ -/*********************************** - * C02 Expression Parsing Routines * - ***********************************/ - -#include -#include -#include -#include -#include -#include "common.h" -#include "asm.h" -#include "parse.h" -#include "vars.h" -#include "label.h" -#include "expr.h" - -/* Push Term and Operator onto Stack */ -void pshtrm(void) { - if (trmidx >= MAXTRM) ERROR("Maximum Function Call/Array Index Depth Exceeded", 0, EXIT_FAILURE) - oprstk[trmidx] = oper; //Put Current Operator on Stack - strcpy(trmstk[trmidx], term); //Put Current Term on Stack - trmidx++; //Increment Stack Pointer -} - -/* Pop Term and Operator off Stack */ -void poptrm(void) { - trmidx--; //Decrement Stack Pointer - strcpy(term, trmstk[trmidx]); //Restore Current Term from Stack - oper = oprstk[trmidx]; //Restore Current Operator from Stack -} - -/* Parse value (literal or identifier) * - * Args: alwreg - allow registers * - 8 alwcon - allow constants * - * Sets: value - the value (as a string) * - * valtyp - value type */ -void prsval(int alwreg, int alwcon) { - DEBUG("Parsing value\n", 0) - skpspc(); - if (islpre()) prslit(); //Parse Literal - else if (isalph()) prsvar(alwreg, alwcon); //Parse Variable - else if (isbtop()) prsbop(); //Parse Byte Operator - else expctd("literal or variable"); - DEBUG("Parsed value of type %d\n", valtyp) - skpspc(); -} - -/* Process Unary Minus */ -void prcmns(void) { - DEBUG("Processing unary minus", 0) - asmlin("LDA", "#$00"); //Handle Unary Minus -} - -/* Parse array index * - * Args: clbrkt - require closing bracket * - * Sets: value - array index or * - * "" if no index defined */ -void prsidx(int clbrkt) { - expect('['); - prsval(TRUE, TRUE); //Parse Value, Allow Registers & Constants - DEBUG("Parsed array index '%s'\n", value) - if (clbrkt) expect(']'); -} - -/* Process Simple Array Index * - * Uses: term - array variable name * - * valtyp - array index value type * - * value - array index as string * - * word - array index raw string * - * Sets: term - modified variable name */ -void prcsix(void) { - if (valtyp == LITERAL) { - strcat(term, "+"); - strcat(term, word); - } - else if (strcmp(value, "Y")==0) - strcat(term, ",Y"); - else { - if (strcmp(value, "A")==0) asmlin("TAX", ""); - else if (strcmp(value, "X")!=0) asmlin("LDX", value); - strcat(term, ",X"); - } -} - -/* Process Expression Array Index */ -void prcxix(void) { - pshtrm(); //Push Array Variable onto Term Stack - if (trmcnt) asmlin("PHA", ""); //Save Accumulator if not first term - prcftm(FALSE); //Process First Term of Expression - prsrxp(']'); //Parse Rest of Expression - asmlin("TAX", ""); //Transfer Result of Expression to Index Register - if (trmcnt) asmlin("PLA", ""); //Restore Accumator if not first term - poptrm(); //Pop Array Variable off Term Stack - strcat(term, ",X"); -} - -/* Check for, Parse, and Process Index */ -void chkidx(void) { - //DEBUG("Checking for Array Index with valtyp=%d\n", valtyp) - if (valtyp == ARRAY) { - if (look('-')) { - prcmns(); - prcxix(); - } - else { - prsidx(FALSE); - if (valtyp > REGISTER) prcxix(); - else if (look(']')) prcsix(); - else prcxix(); - } - } -} - -/* Parse Term in Expression * - * Sets: term - the term (as a string) */ -int prstrm(int alwint) { - DEBUG("Parsing term\n", 0) - prsval(FALSE, TRUE); //Parse Value - Disallow Registers, Allow Constants - if (valtyp == FUNCTION) ERROR("Function call only allowed in first term\n", 0, EXIT_FAILURE) - strcpy(term, value); - if (valtyp == VARIABLE && prcvar(alwint)) return TRUE; - DEBUG("Parsed term %s\n", term) - chkidx(); //Check for Array Index - skpspc(); - return FALSE; -} - -/* Process Address Reference - * Args: adract = Address Action (adacts) * - * symbol = Symbol to Process */ -void prcadr(int adract, char* symbol) { - DEBUG("Processing address '%s'\n", word) - strcpy(word,"#>("); - strcat(word,symbol); - strcat(word,")"); - if (adract == ADPUSH) { asmlin("LDA", word); asmlin("PHA", ""); } - else asmlin("LDY", word); - strcpy(word,"#<("); - strcat(word,symbol); - strcat(word,")"); - if (adract == ADPUSH) { asmlin("LDA", word); asmlin("PHA", ""); } - else asmlin("LDX", word); -} - -/* Parse and Compile Address of Operator * - * Args: adract = Address Action */ -void prsadr(int adract) { - DEBUG("Parsing address\n", 0) - if (isnpre()) prsnum(0xFFFF); - else { - getwrd(); - if (fndlab(word)) strcpy(value, word); - else prsvrw(FALSE, TRUE); - } - if (adract) prcadr(adract, value); //Compile Address Reference - else strcpy(word, value); //Save for Calling Routine -} - -/* Parse and Create Anonymous String * - * Args: adract = Address Action * - * alwstr = Allow String */ -void prsstr(int adract, int alwstr) { - if (!alwstr) ERROR("Illegal String Reference", 0, EXIT_FAILURE) - DEBUG("Parsing anonymous string\n", 0) - newlbl(vrname); //Generate Variable Name - value[0] = 0; //Use Variable Size 0 - setvar(MTNONE, VTCHAR); //Set Variable Name, Type, and Size - prsdts(); //Parse Data String - setdat(); //Set Variable Data - varcnt++; //Increment Variable Counter - if (adract) prcadr(adract, vrname); //Compile Address Reference - else strcpy(word, vrname); //Save for Calling Routine -} - -/* Check for and Process Address or String * - * Args: adract = Address Action * - * alwstr = Allow String */ -int chkadr(int adract, int alwstr) { - DEBUG("Checking for Address or String\n", 0) - int result = TRUE; - if (look('&')) prsadr(adract); - else if (match('"')) prsstr(adract, alwstr); - else result = FALSE; - skpspc(); - return result; -} - -/* Parse Byte Operator */ -void prsbop(void) { - char byteop = getnxt(); - CCMNT(byteop); - DEBUG("Parsing byte operator '%c'\n", byteop) - if (chkadr(FALSE, FALSE)) { - sprintf(value, "%c(%s)", byteop, word); - valtyp = LITERAL; - } else { - reqvar(FALSE); - if (vartyp != VTINT) ERROR("Integer Value Expected\n", 0, EXIT_FAILURE) - if (byteop == '>') strcat(value, "+1"); - vartyp = VTCHAR; - } - DEBUG("Set value to \"%s\"\n", value) -} - -/* Parse Function Argument or Return Values */ -void prsfpr(char trmntr) { - if (!chkadr(ADLDYX, TRUE) && isxpre() || match('.')) { - if (!look('.')) {if (prsxpf(0)) goto prsfne;} - if (look(',') && !chkadr(ADLDYX, TRUE)) { - if (!look('.')) { - if (prstrm(TRUE)) goto prsfne; - asmlin("LDY", term); - } - if (look(',')) { - prsval(FALSE, TRUE); //Parse Value - Disallow Registers, Allow Constants - if (valtyp > VARIABLE) ERROR("Illegal Value Function Argument\n", 0, EXIT_FAILURE); - if (valtyp == VARIABLE && vartyp != VTCHAR) ERROR("Illegal Variable Type\n", 0, EXIT_FAILURE); - asmlin("LDX", value); } - } - } - prsfne: - expect(trmntr); -} - -/* Parse function call */ -void prsfnc(char trmntr) { - DEBUG("Processing Function Call '%s'\n", term) - //int argexp = FALSE; //Expression(s) in second and third argument - pshtrm(); //Push Function Name onto Term Stack - skpchr(); //skip open paren - CCMNT('('); - prsfpr(')'); //Parse Function Parameters - expect(trmntr); - poptrm(); //Pop Function Name off Term Stack - asmlin("JSR", term); - skpspc(); -} - -/* Process Integer Variable */ -void prcvri(void) { - DEBUG("Processing Integer Variable '%s'\n", value) - asmlin("LDX", value); - strcat(value, "+1"); - asmlin("LDY", value); -} - -/* Process Variable in Term */ -int prcvar(int alwint) { - switch (vartyp) { - case VTINT: - if (!alwint) ERROR("Illegal Use of Integer Variable %s\n", word, EXIT_FAILURE) - prcvri(); - return TRUE; - case VTARRAY: - if (!alwint) ERROR("Illegal Reference to Array %s\n", word, EXIT_FAILURE) - prcadr(ADNONE, term); - return TRUE; - case VTSTRUCT: - if (!alwint) ERROR("Illegal Reference to Struct %s\n", word, EXIT_FAILURE) - prcadr(ADNONE, term); - return TRUE; - default: - return FALSE; - } -} - -/* Process first term of expression */ -int prcftm(int alwint) { - DEBUG("Processing first term '%s'\n", value) - strcpy(term, value); - if (valtyp == VARIABLE && prcvar(alwint)) return TRUE; - if (valtyp == FUNCTION) prsfnc(0); //Parse Expression Function - else if (wordis("A")) return FALSE; - else if (wordis("X")) asmlin("TXA", ""); - else if (wordis("Y")) asmlin("TYA", ""); - else { chkidx(); asmlin("LDA", term); } - return FALSE; -} - -/* Parse first term of expession * - * First term can include function calls */ -int prsftm(int alwint) { - prsval(TRUE, TRUE); //Parse Value, Allow Registers & Constants - return prcftm(alwint); -} - -/* Process Arithmetic or Bitwise Operator * - * and the term that follows it */ -void prcopr(void) { - DEBUG("Processing operator '%c'\n", oper) - switch(oper) { - case '+': asmlin("CLC", ""); asmlin("ADC", term); break; //Addition - case '-': asmlin("SEC", ""); asmlin("SBC", term); break; //Subtraction - case '&': asmlin("AND", term); break; //Bitwise AND - case '!': //For systems that don't have pipe in character set - case '|': asmlin("ORA", term); break; //Bitwise OR - case '^': asmlin("EOR", term); break; //Bitwise XOR - default: ERROR("Unrecognized operator '%c'\n", oper, EXIT_FAILURE) - } - oper = 0; -} - -/* Parse Remainder of Expression */ -void prsrxp(char trmntr) { - skpspc(); - while (isoper()) { - trmcnt++; //Increment Expression Depth - prsopr(); //Parse Operator - prstrm(FALSE); //Parse Term - prcopr(); //Process Operator - trmcnt--; //Decrement Expression Depth - } - expect(trmntr); -} - -int prsxpp(char trmntr, int alwint) { - DEBUG("Parsing expression\n", 0) - skpspc(); - trmcnt = 0; //Initialize Expression Depth - if (match('-')) prcmns(); //Process Unary Minus - else if (prsftm(alwint)) return TRUE; //Parse First Term - prsrxp(trmntr); //Parse Remainder of Express - return FALSE; -} - -/* Parse and compile expression */ -void prsxpr(char trmntr) { - prsxpp(trmntr, FALSE); -} - -/* Parse and compile function parameter expression * - * Returns: TRUE if Integer Expression */ -int prsxpf(char trmntr) { - return prsxpp(trmntr, TRUE); -} - -/* Parse and Compile Integer Expression * - * (Address, Integer Literal, Variable, * - * Struct Member, or Function) * - * Args: trmntr - expression terminator * - * asmxpr - assemble expression * - * Sets: value - Parsed Value or Symbol */ -void prsxpi(char trmntr, int asmxpr) { - skpspc(); - DEBUG("Parsing integer expression\n", 0) - if (!chkadr(TRUE, FALSE)) { - if (isnpre()) { - DEBUG("Parsing Integer Literal\n", 0) - int number = prsnum(0xFFFF); //Parse Number into value - if (asmxpr) { - sprintf(value, "#%d", number & 0xFF); asmlin("LDX", value); - sprintf(value, "#%d", number >> 8); asmlin("LDY", value); - } - } else if (isalph()) { - prsvar(FALSE, TRUE); - if (valtyp == FUNCTION) { - strcpy(term, value); - prsfnc(0); //Parse Expression Function - } else if (valtyp == STRUCTURE) { - prsmbr(value); - if (vartyp != VTINT) ERROR("Illegal Member %s In Integer Expression", value, EXIT_FAILURE) - } else if (valtyp == VARIABLE && vartyp == VTINT) { - if (asmxpr) prcvri(); //Process Integer Variable - } else { - ERROR("Illegal Variable %s In Integer Expression", value, EXIT_FAILURE) - } - } else { - ERROR("Expected Integer Value or Function\n", 0, EXIT_FAILURE); - } - } - expect(trmntr); -} +/*********************************** + * C02 Expression Parsing Routines * + ***********************************/ + +#include +#include +#include +#include +#include +#include "common.h" +#include "asm.h" +#include "parse.h" +#include "vars.h" +#include "label.h" +#include "expr.h" + +/* Push Term and Operator onto Stack */ +void pshtrm(void) { + if (trmidx >= MAXTRM) ERROR("Maximum Function Call/Array Index Depth Exceeded", 0, EXIT_FAILURE) + oprstk[trmidx] = oper; //Put Current Operator on Stack + strcpy(trmstk[trmidx], term); //Put Current Term on Stack + trmidx++; //Increment Stack Pointer + DEBUG("expr.pshtrm: Pushed term %s ", term) + DETAIL("and operator '%onto stack'\n", oper) +} + +/* Pop Term and Operator off Stack */ +void poptrm(void) { + trmidx--; //Decrement Stack Pointer + strcpy(term, trmstk[trmidx]); //Restore Current Term from Stack + oper = oprstk[trmidx]; //Restore Current Operator from Stack + DEBUG("expr.pshtrm: Popped term %s ", term) + DETAIL("and operator '%c' off stack\n", oper) +} + +/* Parse value (literal or identifier) * + * Args: alwreg - allow registers * + 8 alwcon - allow constants * + * Sets: value - the value (as a string) * + * valtyp - value type */ +void prsval(int alwreg, int alwcon) { + DEBUG("expr.prsval: Parsing value\n", 0) + skpspc(); + if (islpre()) prslit(); //Parse Literal + else if (isalph()) prsvar(alwreg, alwcon); //Parse Variable + else if (isbtop()) prsbop(); //Parse Byte Operator + else expctd("literal or variable"); + DEBUG("expr.prsval: Parsed value %s ", value) + DETAIL("of type %d\n", valtyp) + skpspc(); +} + +/* Process Unary Minus */ +void prcmns(void) { + DEBUG("Processing unary minus", 0) + asmlin("LDA", "#$00"); //Handle Unary Minus +} + +/* Parse array index * + * Args: clbrkt - require closing bracket * + * Sets: value - array index or * + * "" if no index defined */ +void prsidx(int clbrkt) { + expect('['); + prsval(TRUE, TRUE); //Parse Value, Allow Registers & Constants + DEBUG("expr.prsidx: Parsed array index '%s'\n", value) + if (clbrkt) expect(']'); +} + +/* Process Simple Array Index * + * Uses: term - array variable name * + * valtyp - array index value type * + * value - array index as string * + * word - array index raw string * + * Sets: term - modified variable name */ +void prcsix(void) { + DEBUG("expr.prcsix: Processing simple array index %s\n", word); + if (valtyp == LITERAL) { + strcat(term, "+"); + strcat(term, word); + } + else if (strcmp(value, "Y")==0) + strcat(term, ",Y"); + else { + if (strcmp(value, "A")==0) asmlin("TAX", ""); + else if (strcmp(value, "X")!=0) asmlin("LDX", value); + strcat(term, ",X"); + } + DEBUG("expr.prcsix: Set term to %s\n", term); +} + +/* Process Expression Array Index */ +void prcxix(void) { + DEBUG("expr.prcxix: Processing Expression Array Index", 0) + pshtrm(); //Push Array Variable onto Term Stack + if (trmcnt) asmlin("PHA", ""); //Save Accumulator if not first term + prcftm(FALSE); //Process First Term of Expression + prsrxp(']'); //Parse Rest of Expression + asmlin("TAX", ""); //Transfer Result of Expression to Index Register + if (trmcnt) asmlin("PLA", ""); //Restore Accumator if not first term + poptrm(); //Pop Array Variable off Term Stack + strcat(term, ",X"); + DEBUG("expr.prcxix: Set term to %s\n", term); +} + +/* Check for, Parse, and Process Index */ +void chkidx(void) { + //DEBUG("Checking for Array Index with valtyp=%d\n", valtyp) + if (valtyp == ARRAY) { + if (look('-')) { + prcmns(); + prcxix(); + } + else { + prsidx(FALSE); + if (valtyp > REGISTER) prcxix(); + else if (look(']')) prcsix(); + else prcxix(); + } + } +} + +/* Parse Pointer * + * Sets: term - Compiled Pointer */ +void prsptr(void) { + DEBUG("Parsing pointer\n", 0) + expect('*'); //Pointer Dereference Operator + prsvar(FALSE,FALSE); //Parse Variable to Dereference + strcpy(term, value); + if (varble.modifr != MTZP) ERROR("Illegal dereference of non-pointer variable %s.\n", value, EXIT_FAILURE) + DEBUG("expr.prsptr: Set term to %s\n", term); +} + +/* Process Pointer Index * + * Sets: term - Compiled Pointer */ +void prcptx(char *index) { + DEBUG("expr.prcptx: Processing Dereferenced Pointer %s ", term) + DETAIL("index [%s]\n", index) + if (strcmp(index,"X")==0) ERROR("Illegal use of register X\n", 0, EXIT_FAILURE); + if (strcmp(index,"A")==0) asmlin("TAY", ""); + else if (strcmp(index,"Y") != 0) asmlin("LDY", index); +} + +/* Process Pointer * + * Sets: term - Compiled Pointer */ +int prcptr(void) { + prsptr(); + DEBUG("expr.prcptr: Dereferencing Pointer %s\n", value); + if (valtyp == ARRAY) { + prsidx(TRUE); + prcptx(value); + sprintf(word, "(%s),Y", term); + } else if (cmos) { + sprintf(word, "(%s)", term); + } else { + asmlin("LDY","0"); + sprintf(word, "(%s),Y", term); + } + strcpy(term, word); + DEBUG("expr.prcptr: Set term to %s\n", term); + return FALSE; //Return Value Not an Integer +} + +/* Parse Term in Expression * + * Sets: term - the term (as a string) * + * Returns: TRUE if term is an integer */ +int prstrm(int alwint) { + DEBUG("Parsing term\n", 0) + if (match('*')) return prcptr(); //Parse and Deference Pointer + prsval(FALSE, TRUE); //Parse Value - Disallow Registers, Allow Constants + if (valtyp == FUNCTION) ERROR("Function call only allowed in first term\n", 0, EXIT_FAILURE) + strcpy(term, value); + if (valtyp == VARIABLE && prcivr(alwint)) return TRUE; + DEBUG("expr.prstrm: Parsed term %s\n", term) + chkidx(); //Check for Array Index + skpspc(); + return FALSE; +} + +/* Process Address Reference + * Args: adract = Address Action (adacts) * + * symbol = Symbol to Process */ +void prcadr(int adract, char* symbol) { + DEBUG("Processing address '%s'\n", word) + strcpy(word,"#>("); + strcat(word,symbol); + strcat(word,")"); + if (adract == ADPUSH) { asmlin("LDA", word); asmlin("PHA", ""); } + else asmlin("LDY", word); + strcpy(word,"#<("); + strcat(word,symbol); + strcat(word,")"); + if (adract == ADPUSH) { asmlin("LDA", word); asmlin("PHA", ""); } + else asmlin("LDX", word); +} + +/* Parse and Compile Address of Operator * + * Args: adract = Address Action */ +void prsadr(int adract) { + DEBUG("Parsing address\n", 0) + if (isnpre()) prsnum(0xFFFF); + else { + getwrd(); + if (fndlab(word)) strcpy(value, word); + else prsvrw(FALSE, TRUE); + } + if (adract) prcadr(adract, value); //Compile Address Reference + else strcpy(word, value); //Save for Calling Routine +} + +/* Parse and Create Anonymous String * + * Args: adract = Address Action * + * alwstr = Allow String */ +void prsstr(int adract, int alwstr) { + if (!alwstr) ERROR("Illegal String Reference", 0, EXIT_FAILURE) + DEBUG("Parsing anonymous string\n", 0) + newlbl(vrname); //Generate Variable Name + value[0] = 0; //Use Variable Size 0 + setvar(MTNONE, VTCHAR); //Set Variable Name, Type, and Size + prsdts(); //Parse Data String + setdat(); //Set Variable Data + varcnt++; //Increment Variable Counter + if (adract) prcadr(adract, vrname); //Compile Address Reference + else strcpy(word, vrname); //Save for Calling Routine +} + +/* Check for and Process Address or String * + * Args: adract = Address Action * + * alwstr = Allow String */ +int chkadr(int adract, int alwstr) { + DEBUG("Checking for Address or String\n", 0) + int result = TRUE; + if (look('&')) prsadr(adract); + else if (match('"')) prsstr(adract, alwstr); + else result = FALSE; + skpspc(); + return result; +} + +/* Parse Byte Operator */ +void prsbop(void) { + char byteop = getnxt(); + CCMNT(byteop); + DEBUG("Parsing byte operator '%c'\n", byteop) + if (chkadr(FALSE, FALSE)) { + sprintf(value, "%c(%s)", byteop, word); + valtyp = LITERAL; + } else { + reqvar(FALSE); + if (vartyp != VTINT) ERROR("Integer Value Expected\n", 0, EXIT_FAILURE) + if (byteop == '>') strcat(value, "+1"); + vartyp = VTCHAR; + } + DEBUG("Set value to \"%s\"\n", value) +} + +/* Parse Function Argument or Return Values */ +void prsfpr(char trmntr) { + int pusha = 0; int pushy = 0; //A and Y Arguments Pushed + if (!chkadr(ADLDYX, TRUE) && isxpre() || match('.')) { + if (look('.')) pusha = 255; + else {if (prsxpf(0)) goto prsfne;} + if (look(',') && !chkadr(ADLDYX, TRUE)) { + if (look('.')) { + pushy = -1; + } + else { + if (look('(')) { + if (pusha==0) {pusha = 1; asmlin("PHA","");} //Save A on Stack + prsxpr(')'); asmlin("TAY", ""); //Evaluate Expression, and Copy to Y + } + else { + if (prstrm(TRUE)) goto prsfne; + asmlin("LDY", term); + } + } + if (look(',')) { + if (look('(')) { + if (pusha==0) {pusha = 1; asmlin("PHA","");} //Save A on Stack + if (pushy==0) {pushy = 1; asmlin("PHA",""); asmlin("PHY","");} //Save Y on Stack + prsxpr(')'); asmlin("TAX", ""); //Evaluate Expression, and Copy to X + } + else { + prsval(FALSE, TRUE); //Parse Value - Disallow Registers, Allow Constants + if (valtyp > VARIABLE) ERROR("Illegal Value Function Argument\n", 0, EXIT_FAILURE); + if (valtyp == VARIABLE && vartyp != VTCHAR) ERROR("Illegal Variable Type\n", 0, EXIT_FAILURE); + asmlin("LDX", value); + } + } + } + } + prsfne: + if (pushy==1) {asmlin("PLA",""); asmlin("TAY","");} //Pull Y Off Stack + if (pusha==1) asmlin("PLA",""); //Pull A Off Stack + expect(trmntr); +} + +/* Parse function call */ +void prsfnc(char trmntr) { + DEBUG("Processing Function Call '%s'\n", term) + //int argexp = FALSE; //Expression(s) in second and third argument + pshtrm(); //Push Function Name onto Term Stack + skpchr(); //skip open paren + CCMNT('('); + prsfpr(')'); //Parse Function Parameters + expect(trmntr); + poptrm(); //Pop Function Name off Term Stack + asmlin("JSR", term); + skpspc(); +} + +/* Process Integer Variable */ +void prcvri(void) { + DEBUG("Processing Integer Variable '%s'\n", value) + asmlin("LDX", value); + strcat(value, "+1"); + asmlin("LDY", value); +} + +/* Process Integer Variable in Term * + * Args: alwint = Allow Integer-Like Variable * + * Returns: Integer-Like Variable Processed - TRUE/FALSE */ +int prcivr(int alwint) { + switch (vartyp) { + case VTINT: + if (!alwint) ERROR("Illegal Use of Integer Variable %s\n", word, EXIT_FAILURE) + prcvri(); + return TRUE; + case VTARRAY: + if (!alwint) ERROR("Illegal Reference to Array %s\n", word, EXIT_FAILURE) + prcadr(ADNONE, term); + return TRUE; + case VTSTRUCT: + if (!alwint) ERROR("Illegal Reference to Struct %s\n", word, EXIT_FAILURE) + prcadr(ADNONE, term); + return TRUE; + default: + return FALSE; + } +} + +/* Process first term of expression */ +int prcftm(int alwint) { + DEBUG("Processing first term '%s'\n", value) + strcpy(term, value); + if (valtyp == VARIABLE && prcivr(alwint)) return TRUE; + if (valtyp == FUNCTION) prsfnc(0); //Parse Expression Function + else if (wordis("A")) return FALSE; + else if (wordis("X")) asmlin("TXA", ""); + else if (wordis("Y")) asmlin("TYA", ""); + else { chkidx(); asmlin("LDA", term); } + return FALSE; +} + +/* Parse first term of expession * + * First term can include function calls */ +int prsftm(int alwint) { + DEBUG("Parsing first term\n", 0) + if (match('*')) { + prcptr(); //Parse and Deference Pointer + asmlin("LDA", term); + return FALSE; + } + prsval(TRUE, TRUE); //Parse Value, Allow Registers & Constants + return prcftm(alwint); +} + +/* Process Arithmetic or Bitwise Operator * + * and the term that follows it */ +void prcopr(void) { + DEBUG("Processing operator '%c'\n", oper) + switch(oper) { + case '+': asmlin("CLC", ""); asmlin("ADC", term); break; //Addition + case '-': asmlin("SEC", ""); asmlin("SBC", term); break; //Subtraction + case '&': asmlin("AND", term); break; //Bitwise AND + case '!': //For systems that don't have pipe in character set + case '|': asmlin("ORA", term); break; //Bitwise OR + case '^': asmlin("EOR", term); break; //Bitwise XOR + default: ERROR("Unrecognized operator '%c'\n", oper, EXIT_FAILURE) + } + oper = 0; +} + +/* Parse Remainder of Expression */ +void prsrxp(char trmntr) { + skpspc(); + while (isoper()) { + trmcnt++; //Increment Expression Depth + prsopr(); //Parse Operator + prstrm(FALSE); //Parse Term + prcopr(); //Process Operator + trmcnt--; //Decrement Expression Depth + } + expect(trmntr); +} + +int prsxpp(char trmntr, int alwint) { + DEBUG("Parsing expression\n", 0) + skpspc(); + trmcnt = 0; //Initialize Expression Depth + if (match('-')) prcmns(); //Process Unary Minus + else if (prsftm(alwint)) return TRUE; //Parse First Term + prsrxp(trmntr); //Parse Remainder of Express + return FALSE; +} + +/* Parse and compile expression */ +void prsxpr(char trmntr) { + prsxpp(trmntr, FALSE); +} + +/* Parse and compile function parameter expression * + * Returns: TRUE if Integer Expression */ +int prsxpf(char trmntr) { + return prsxpp(trmntr, TRUE); +} + +/* Parse and Compile Integer Expression * + * (Address, Integer Literal, Variable, * + * Struct Member, or Function) * + * Args: trmntr - expression terminator * + * asmxpr - assemble expression * + * Sets: value - Parsed Value or Symbol */ +void prsxpi(char trmntr, int asmxpr) { + skpspc(); + DEBUG("Parsing integer expression\n", 0) + if (!chkadr(TRUE, FALSE)) { + if (isnpre()) { + DEBUG("Parsing Integer Literal\n", 0) + int number = prsnum(0xFFFF); //Parse Number into value + if (asmxpr) { + sprintf(value, "#%d", number & 0xFF); asmlin("LDX", value); + sprintf(value, "#%d", number >> 8); asmlin("LDY", value); + } + } else if (isalph()) { + prsvar(FALSE, TRUE); + if (valtyp == FUNCTION) { + strcpy(term, value); + DEBUG("expr.prsxpi: Set term to %s\n", term) + prsfnc(0); //Parse Expression Function + } else if (valtyp == STRUCTURE) { + prsmbr(value); + if (vartyp != VTINT) ERROR("Illegal Member %s In Integer Expression", value, EXIT_FAILURE) + } else if (valtyp == VARIABLE && vartyp == VTINT) { + if (asmxpr) prcvri(); //Process Integer Variable + } else { + ERROR("Illegal Variable %s In Integer Expression", value, EXIT_FAILURE) + } + } else { + ERROR("Expected Integer Value or Function\n", 0, EXIT_FAILURE); + } + } + expect(trmntr); +} diff --git a/src/expr.h b/src/expr.h index f57a653..0844a97 100644 --- a/src/expr.h +++ b/src/expr.h @@ -1,30 +1,32 @@ -/********************************** - * C02 Expession Parsing Routines * - **********************************/ - -enum adacts {ADNONE, ADLDYX, ADPUSH}; - -char term[255]; //Term parsed from equation - -char oprstk[MAXTRM]; //Operator Stack -char trmstk[MAXTRM][VARLEN+1]; //Function/Index Terms Stack -int trmidx; //Next Index in Stack - -int trmcnt; //Number of total terms in current expression - -int chkadr(int adract, int alwstr); //Check for and Process Address or String -void chkidx(); //Check for, Parse, and Process Index -int prcftm(int alwint); //Process First Term -void prcvri(void); //Process Integer Variable -int prcvar(int alwint); //Process Variable in Term -void prsadr(int adract); //Parse and Compile Address of Operator -void prsbop(void); //Parse Byte Operator -void prsval(int alwreg, int alwcon); //Parse Value -void prsfnc(char trmntr); //Parse function call -void prsfpr(char trmntr); //Parse Function Paraeters or Return -void prsidx(); //Parse Array Index -int prstrm(int alwint); //Parse Term in Expression -void prsrxp(char trmntr); //Parse Rest of Expression -int prsxpf(char trmntr); //Parse Expression in Function Call -void prsxpr(char trmntr); //Parse Expression -void prsxpi(char trmntr, int asmxpr); //Parse Integer Expression +/********************************** + * C02 Expession Parsing Routines * + **********************************/ + +enum adacts {ADNONE, ADLDYX, ADPUSH}; + +char term[255]; //Term parsed from equation + +char oprstk[MAXTRM]; //Operator Stack +char trmstk[MAXTRM][VARLEN+1]; //Function/Index Terms Stack +int trmidx; //Next Index in Stack + +int trmcnt; //Number of total terms in current expression + +int chkadr(int adract, int alwstr); //Check for and Process Address or String +void chkidx(); //Check for, Parse, and Process Index +int prcftm(int alwint); //Process First Term +void prcptx(char *index); //Process Pointer Index +void prcvri(void); //Process Integer Variable +int prcivr(int alwint); //Process Integer Variable in Term +void prsadr(int adract); //Parse and Compile Address of Operator +void prsbop(void); //Parse Byte Operator +void prsval(int alwreg, int alwcon); //Parse Value +void prsfnc(char trmntr); //Parse function call +void prsfpr(char trmntr); //Parse Function Paraeters or Return +void prsidx(); //Parse Array Index +void prsptr(void); //Parse Pointer +int prstrm(int alwint); //Parse Term in Expression +void prsrxp(char trmntr); //Parse Rest of Expression +int prsxpf(char trmntr); //Parse Expression in Function Call +void prsxpr(char trmntr); //Parse Expression +void prsxpi(char trmntr, int asmxpr); //Parse Integer Expression diff --git a/src/files.c b/src/files.c index 147c2d3..76c57d9 100644 --- a/src/files.c +++ b/src/files.c @@ -1,102 +1,102 @@ -/****************************** - * C02 File Handling Routines * - ******************************/ - -#include -#include -#include -#include -#include - -#include "common.h" -#include "files.h" - -/* Error - Print textual description of system error * - * and exit with system error code */ -void extsys(char *s) { - perror(s); - exterr(errno); -} - -/* Open Source File * - * Uses: srcnam - Source File Name * - * Sets: srcfil - Source File Handle */ -void opnsrc(void) { - DEBUG("Processing Source File Name '%s'\n", srcnam) - if (strrchr(srcnam, '.') == NULL) strcat(srcnam, ".c02"); //if no extension. add ".c02" - DEBUG("opening Source File '%s'\n", srcnam) - srcfil = fopen(srcnam, "r"); //open file - if (srcfil == NULL) extsys(srcnam); -} - -/* Close Source File */ -void clssrc(void) { fclose(srcfil); } - -/* Open Output File * - * Uses: outnam - Output File Name * - * Sets: outfil - Output File Handle */ -void opnout(void) { - DEBUG("Processing Output File Name '%s'\n", outnam) - if (strlen(outnam) == 0) //if Output File not specified - { - strcpy(outnam, srcnam); //copy Source Name to Ouput Name - char *dot = strrchr(outnam, '.'); //find extension - if (dot != NULL) *dot = 0; //and remove it - DEBUG("Set Output File Name to '%s'\n", outnam) - } - if (strrchr(outnam, '.') == NULL) strcat(outnam, ".asm"); //if no extension, add ".asm" - DEBUG("Opening Output File '%s'\n", outnam) - outfil = fopen(outnam, "w"); //open file - if (outfil == NULL) extsys(outnam); -} - -/* Close Output File */ -void clsout(void) { - fprintf(outfil, "\n"); - fclose(outfil); -} - -/* Open Log File * - * Uses: srcnam - Source File Name * - * Sets: logfil - Log File Handle */ -void opnlog(void) { - strcpy(lognam, srcnam); //set Log File Name to Source File Name - char *dot = strrchr(lognam, '.'); //find file extension - if (dot != NULL) *dot = 0; //and remove it - strcat(lognam, ".log"); //add extension ".log" - DEBUG("Opening Log File '%s'\n", lognam) - logfil = fopen(lognam, "w"); - if (logfil == NULL) extsys(lognam); -} - -/* Close Log File * - * Uses: logfil - Log File Handle */ -void clslog(void) { fclose(logfil); } - -/* Open Include file * - * Uses: incnam - Include File Name * - * subnam - Include File Name (Subdirectory) * - * Sets: incfil - Include File Handle */ -void opninc(int chksub) -{ - if (chksub) { - for (subidx=0; subidx +#include +#include +#include +#include + +#include "common.h" +#include "files.h" + +/* Error - Print textual description of system error * + * and exit with system error code */ +void extsys(char *s) { + perror(s); + exterr(errno); +} + +/* Open Source File * + * Uses: srcnam - Source File Name * + * Sets: srcfil - Source File Handle */ +void opnsrc(void) { + DEBUG("Processing Source File Name '%s'\n", srcnam) + if (strrchr(srcnam, '.') == NULL) strcat(srcnam, ".c02"); //if no extension. add ".c02" + DEBUG("opening Source File '%s'\n", srcnam) + srcfil = fopen(srcnam, "r"); //open file + if (srcfil == NULL) extsys(srcnam); +} + +/* Close Source File */ +void clssrc(void) { fclose(srcfil); } + +/* Open Output File * + * Uses: outnam - Output File Name * + * Sets: outfil - Output File Handle */ +void opnout(void) { + DEBUG("Processing Output File Name '%s'\n", outnam) + if (strlen(outnam) == 0) //if Output File not specified + { + strcpy(outnam, srcnam); //copy Source Name to Ouput Name + char *dot = strrchr(outnam, '.'); //find extension + if (dot != NULL) *dot = 0; //and remove it + DEBUG("Set Output File Name to '%s'\n", outnam) + } + if (strrchr(outnam, '.') == NULL) strcat(outnam, ".asm"); //if no extension, add ".asm" + DEBUG("Opening Output File '%s'\n", outnam) + outfil = fopen(outnam, "w"); //open file + if (outfil == NULL) extsys(outnam); +} + +/* Close Output File */ +void clsout(void) { + fprintf(outfil, "\n"); + fclose(outfil); +} + +/* Open Log File * + * Uses: srcnam - Source File Name * + * Sets: logfil - Log File Handle */ +void opnlog(void) { + strcpy(lognam, srcnam); //set Log File Name to Source File Name + char *dot = strrchr(lognam, '.'); //find file extension + if (dot != NULL) *dot = 0; //and remove it + strcat(lognam, ".log"); //add extension ".log" + DEBUG("Opening Log File '%s'\n", lognam) + logfil = fopen(lognam, "w"); + if (logfil == NULL) extsys(lognam); +} + +/* Close Log File * + * Uses: logfil - Log File Handle */ +void clslog(void) { fclose(logfil); } + +/* Open Include file * + * Uses: incnam - Include File Name * + * subnam - Include File Name (Subdirectory) * + * Sets: incfil - Include File Handle */ +void opninc(int chksub) +{ + if (chksub) { + for (subidx=0; subidx -#include -#include -#include -#include - -#include "common.h" -#include "files.h" -#include "asm.h" -#include "parse.h" -#include "label.h" -#include "vars.h" - -/* Add New Program Label */ -void addlab(char *name) { - if (fndvar(name)) ERROR("Label %s conflicts with variable with same name", name, EXIT_FAILURE) - if (fndlab(name)) ERROR("Duplicate program label %s\n", name, EXIT_FAILURE) - DEBUG("Adding Program Label %s ", name) DEBUG("at index %d\n", labcnt) - strcpy(labnam[labcnt++], name); -} - -int fndlab(char *name) { - DEBUG("Looking for Program Label %s\n", name) - for (labidx=0; labidx-1; i--) - if (lblflg[lbltyp[i]] == lbflag) break; - DEBUG("Search produced label index %d\n", i) - if (i>=0) strcpy(tmplbl, lblnam[i]); - return i; -} - -/* Set Block Flag for Last Label */ -void setblk(int blkflg) { lblblk[lblcnt-1] = blkflg; } - -/* Set label for next line of * - * Assembly Language Code * - * to word */ -void setlbl(char *lblset) { - DEBUG("Setting Label '%s'\n", lblset) - if (strlen(lblasm) > 0) { - DEBUG("Emitting Label '%s'\n'", lblasm); - asmlin("",""); //Emit Block End Label on it's own line - } - if (strlen(lblset) > LBLLEN) ERROR("Label '%s' exceeds maximum size\n", word, EXIT_FAILURE) - strcpy(lblasm, lblset); -} - -/* Parse Program Label */ -void prslab(void) { - DEBUG("Parsing Label '%s''\n", word) - addlab(word); - CCMNT(nxtchr); - skpchr(); //skip ':' -} - -/* generate new label */ -void newlbl(char* lbname) { - sprintf(lbname, LBLFMT, lblnxt++); - DEBUG("Generated new label '%s'\n", lbname) -} - -/* Check Label Contents * - * If lbname is blank, generate new * - * label and copy into lbname */ -void chklbl(char* lbname) { - if (lbname[0]) return; - newlbl(lbname); -} - -/* Request Label * - * if label is already set, returns that label * - * else generates new label and sets it */ -void reqlbl(char* lbname) { - DEBUG("Requesting Label\n",0) - if (lblasm[0] == 0) {newlbl(lbname); setlbl(lbname);} - else {strcpy(lbname,lblasm); DEBUG("Found lblasm set to \"%s\"\n", lblasm)} -} - -/* End Function Block */ -void endfnc(void) { - DEBUG("Ending function definition with lsrtrn set to %d\n", lsrtrn) - if (!lsrtrn) asmlin("RTS", ""); - infunc = FALSE; - DEBUG("Set infunc to %d\n", infunc) -} - -/* Pop Label from Stack and Emit on Next Line */ -int poplbl(void) { - int lbtype = lbltyp[--lblcnt]; - DEBUG("Popped label type %d\n", lbtype) - switch (lbtype) { - case LTFUNC: endfnc(); break; //Return From Subroutine - case LTDO: strcpy(loplbl, lblnam[lblcnt]); break; - case LTDWHL: strcpy(endlbl, lblnam[lblcnt]); break; - case LTCASE: strcpy(cndlbl, lblnam[lblcnt]); break; - case LTLOOP: asmlin("JMP", lblnam[lblcnt--]); //Jump to Beginning of Loop - default: setlbl(lblnam[lblcnt]); //Emit End of Loop Label - } - if (lbtype != LTCASE) inblck = lblblk[lblcnt-1]; - return lbtype; -} - -/* Get Top Label and Return Type */ -int toplbl(char *rtlbl) { - if (lblcnt) { - strcpy(rtlbl, lblnam[lblcnt-1]); - DEBUG("Found top label %s\n", rtlbl) - return lbltyp[lblcnt-1]; - } - rtlbl[0] = 0; //Clear Label - return LTNONE; -} - -/* Push Label onto Stack * - * Args: lbltyp - Label type * - * Uses: curlbl - Label to push */ -void pshlbl(int lbtype, char* lbname) { - DEBUG("Pushing label type %d\n", lbtype) - strcpy(lblnam[lblcnt], lbname); - lbltyp[lblcnt] = lbtype; - lblblk[lblcnt++] = FALSE; - DEBUG("Pushed label '%s' onto stack\n", lbname) -} +/****************************************************** + * C02 Label Parsing, Generation, and Lookup Routines * + ******************************************************/ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "files.h" +#include "asm.h" +#include "parse.h" +#include "label.h" +#include "vars.h" + +/* Add New Program Label */ +void addlab(char *name) { + if (fndvar(name)) ERROR("Label %s conflicts with variable with same name", name, EXIT_FAILURE) + if (fndlab(name)) ERROR("Duplicate program label %s\n", name, EXIT_FAILURE) + DEBUG("Adding Program Label %s ", name) DEBUG("at index %d\n", labcnt) + strcpy(labnam[labcnt++], name); +} + +int fndlab(char *name) { + DEBUG("Looking for Program Label %s\n", name) + for (labidx=0; labidx-1; i--) + if (lblflg[lbltyp[i]] == lbflag) break; + DEBUG("Search produced label index %d\n", i) + if (i>=0) strcpy(tmplbl, lblnam[i]); + return i; +} + +/* Set Block Flag for Last Label */ +void setblk(int blkflg) { lblblk[lblcnt-1] = blkflg; } + +/* Set label for next line of * + * Assembly Language Code * + * to word */ +void setlbl(char *lblset) { + DEBUG("Setting Label '%s'\n", lblset) + if (strlen(lblasm) > 0) { + DEBUG("Emitting Label '%s'\n'", lblasm); + asmlin("",""); //Emit Block End Label on it's own line + } + if (strlen(lblset) > LBLLEN) ERROR("Label '%s' exceeds maximum size\n", word, EXIT_FAILURE) + strcpy(lblasm, lblset); +} + +/* Parse Program Label */ +void prslab(void) { + DEBUG("Parsing Label '%s''\n", word) + addlab(word); + CCMNT(nxtchr); + skpchr(); //skip ':' +} + +/* generate new label */ +void newlbl(char* lbname) { + sprintf(lbname, LBLFMT, lblnxt++); + DEBUG("Generated new label '%s'\n", lbname) +} + +/* Check Label Contents * + * If lbname is blank, generate new * + * label and copy into lbname */ +void chklbl(char* lbname) { + if (lbname[0]) return; + newlbl(lbname); +} + +/* Request Label * + * if label is already set, returns that label * + * else generates new label and sets it */ +void reqlbl(char* lbname) { + DEBUG("Requesting Label\n",0) + if (lblasm[0] == 0) {newlbl(lbname); setlbl(lbname);} + else {strcpy(lbname,lblasm); DEBUG("Found lblasm set to \"%s\"\n", lblasm)} +} + +/* End Function Block */ +void endfnc(void) { + DEBUG("Ending function definition with lsrtrn set to %d\n", lsrtrn) + if (!lsrtrn) asmlin("RTS", ""); + infunc = FALSE; + DEBUG("Set infunc to %d\n", infunc) +} + +/* Pop Label from Stack and Emit on Next Line */ +int poplbl(void) { + int lbtype = lbltyp[--lblcnt]; + DEBUG("Popped label type %d\n", lbtype) + switch (lbtype) { + case LTFUNC: endfnc(); break; //Return From Subroutine + case LTDO: strcpy(loplbl, lblnam[lblcnt]); break; + case LTDWHL: strcpy(endlbl, lblnam[lblcnt]); break; + case LTCASE: strcpy(cndlbl, lblnam[lblcnt]); break; + case LTLOOP: asmlin("JMP", lblnam[lblcnt--]); //Jump to Beginning of Loop + default: setlbl(lblnam[lblcnt]); //Emit End of Loop Label + } + if (lbtype != LTCASE) inblck = lblblk[lblcnt-1]; + return lbtype; +} + +/* Get Top Label and Return Type */ +int toplbl(char *rtlbl) { + if (lblcnt) { + strcpy(rtlbl, lblnam[lblcnt-1]); + DEBUG("Found top label %s\n", rtlbl) + return lbltyp[lblcnt-1]; + } + rtlbl[0] = 0; //Clear Label + return LTNONE; +} + +/* Push Label onto Stack * + * Args: lbltyp - Label type * + * Uses: curlbl - Label to push */ +void pshlbl(int lbtype, char* lbname) { + DEBUG("Pushing label type %d\n", lbtype) + strcpy(lblnam[lblcnt], lbname); + lbltyp[lblcnt] = lbtype; + lblblk[lblcnt++] = FALSE; + DEBUG("Pushed label '%s' onto stack\n", lbname) +} diff --git a/src/label.h b/src/label.h index 0b2068a..f83c242 100644 --- a/src/label.h +++ b/src/label.h @@ -1,41 +1,41 @@ -/****************************************************** - * C02 Label Parsing, Generation, and Lookup Routines * - ******************************************************/ - -char labnam[MAXLAB+1][LABLEN+1]; //Program Label Names -int labcnt; //Number of Program Labels -int labidx; //Index into labnam[] - -char curlbl[LBLLEN+1]; //Most recently generated label -char cmplbl[LBLLEN+1]; //Label for Comparison -char cndlbl[LBLLEN+1]; //Label for Conditional Code -char endlbl[LBLLEN+1]; //End Label -char forlbl[LBLLEN+1]; //For Loop Label -char loplbl[LBLLEN+1]; //Skip Increment Label -char skplbl[LBLLEN+1]; //Skip Increment Label -char tmplbl[LBLLEN+1]; //Temporary Label -char lblnam[MAXLBL+1][LBLLEN+1]; //Label Name Table -int lbltyp[MAXLBL+1]; //Label Type -int lblblk[MAXLBL+1]; //Label Ends Program Block -int lblcnt; //Number of Labels in stack -int lblnxt; //Sequence of next label to be generated -char lbltmp[LBLLEN+1]; //Label Temporary Storage - -enum ltypes {LTNONE, LTIF, LTELSE, LTLOOP, LTEND, LTDO, LTDWHL, LTSLCT, LTCASE, LTFUNC}; //Label Types -enum lflags {LFNONE, LFBGN, LFEND}; //Label Flag Types - -void addlab(char *name); //Add Program Label -int fndlab(char *name); //Find Program Label -void prslab(); //Parse Program Label -void loglab(void); //Print Program Label Table - -void chklbl(char* lbname); //Check Label Contents -int lstlbl(int lbflag); //Find Last Label of Specified Types * -void newlbl(char* lbname); //Generate New Block Label -int poplbl(); //Pop Last Label and Emit on Next Line -void pshlbl(int lbtype, char* lbname); //Push Label onto Stack -void reqlbl(char* lbname); //Require Label -void setblk(int blkflg); //Set Block Flag for Last Label -void setlbl(char *lblset); //Emit word as Label on Next Line -int toplbl(char *rtlbl); //Get Top Label and Return Type - +/****************************************************** + * C02 Label Parsing, Generation, and Lookup Routines * + ******************************************************/ + +char labnam[MAXLAB+1][LABLEN+1]; //Program Label Names +int labcnt; //Number of Program Labels +int labidx; //Index into labnam[] + +char curlbl[LBLLEN+1]; //Most recently generated label +char cmplbl[LBLLEN+1]; //Label for Comparison +char cndlbl[LBLLEN+1]; //Label for Conditional Code +char endlbl[LBLLEN+1]; //End Label +char forlbl[LBLLEN+1]; //For Loop Label +char loplbl[LBLLEN+1]; //Skip Increment Label +char skplbl[LBLLEN+1]; //Skip Increment Label +char tmplbl[LBLLEN+1]; //Temporary Label +char lblnam[MAXLBL+1][LBLLEN+1]; //Label Name Table +int lbltyp[MAXLBL+1]; //Label Type +int lblblk[MAXLBL+1]; //Label Ends Program Block +int lblcnt; //Number of Labels in stack +int lblnxt; //Sequence of next label to be generated +char lbltmp[LBLLEN+1]; //Label Temporary Storage + +enum ltypes {LTNONE, LTIF, LTELSE, LTLOOP, LTEND, LTDO, LTDWHL, LTSLCT, LTCASE, LTFUNC}; //Label Types +enum lflags {LFNONE, LFBGN, LFEND}; //Label Flag Types + +void addlab(char *name); //Add Program Label +int fndlab(char *name); //Find Program Label +void prslab(); //Parse Program Label +void loglab(void); //Print Program Label Table + +void chklbl(char* lbname); //Check Label Contents +int lstlbl(int lbflag); //Find Last Label of Specified Types * +void newlbl(char* lbname); //Generate New Block Label +int poplbl(); //Pop Last Label and Emit on Next Line +void pshlbl(int lbtype, char* lbname); //Push Label onto Stack +void reqlbl(char* lbname); //Require Label +void setblk(int blkflg); //Set Block Flag for Last Label +void setlbl(char *lblset); //Emit word as Label on Next Line +int toplbl(char *rtlbl); //Get Top Label and Return Type + diff --git a/src/parse.c b/src/parse.c index c7474c5..83562b4 100644 --- a/src/parse.c +++ b/src/parse.c @@ -13,6 +13,8 @@ #include "asm.h" #include "parse.h" #include "label.h" +#include "expr.h" +#include "stmnt.h" /* Various tests against nxtchr */ int match(char c) {return TF(nxtchr == c);} @@ -81,12 +83,15 @@ void skpspc(void) { * otherwise FALSE */ int look(char c) { int found; + DEBUG("parse.look: Looking for '%c', ", c); skpspc(); found = match(c); if (found) { skpchr(); CCMNT(c); + DETAIL("Found\n", 0); } + else DETAIL("Not found\n", 0); return found; } @@ -136,6 +141,8 @@ void getwrd(void) { while (isanum()) word[wrdlen++] = toupper(getnxt()); word[wrdlen] = 0; ACMNT(word); + DEBUG("parse.getwrd: Read word '%s' ", word) + DETAIL("delimited by '%c'\n", nxtchr) } /* Escape Character */ @@ -154,31 +161,41 @@ char escape(char c) { } } +/* Escape Numeric Literal */ +char escnum(void) { + DEBUG("Escaping numeric literal\n", 0); + char c = prsnum(0xff); + return c; +} + /* Get String * * Sets: word = parsed string * wrdlen = length of string (including terminator) */ void getstr(void) { char strdel; int escnxt = FALSE; - wrdlen = 0; + pstlen = 0; DEBUG("Parsing string\n", 0) strdel = getnxt(); //Get String Delimiter CCMNT(strdel); while(!match(strdel) || escnxt) { + if (isnl()) ERROR("String Not Terminated", 0, EXIT_FAILURE) CCMNT(nxtchr); if (escnxt) { - word[wrdlen++] = escape(getnxt()); + if (isnpre()) pstrng[pstlen++] = escnum(); + else pstrng[pstlen++] = escape(getnxt()); escnxt = FALSE; } else { if (match('\\')) escnxt = TRUE; - else word[wrdlen++] = prcchr(nxtchr); + else pstrng[pstlen++] = prcchr(nxtchr); skpchr(); } } skpchr(); //Skip End Delimiter CCMNT(strdel); - word[wrdlen] = 0; + pstrng[pstlen] = 0; + strcpy(word,pstrng); wrdlen=pstlen; } /* Read Binary number from input file * @@ -357,21 +374,24 @@ void poperr(char* name) { } /* Process Post Operator */ -void prcpst(int isint, char* name, char *index) { - DEBUG("Processing post operation '%c'\n", oper) +void prcpst(int isint, char* name, char *index, char indtyp, char ispntr) { + DEBUG("parse.prcpst: Processing post operation '%c'\n", oper) + if (ispntr) ERROR("Post Operation on dereferenced pointer %s not supported\n", name, EXIT_FAILURE) + //sprintf(word,"(%s),Y", name); strcpy(name, word); } char name1[VARLEN+3]; strcpy(name1, name); strcat(name1, "+1"); if (strlen(index)) { - asmlin("LDX", index); - strcat(name,",X"); + if (ispntr) prcptx(index); //Process Pointer Index + else prcidx(indtyp, name, index); //Process Index } + else if (ispntr) asmlin("LDY","0"); switch(oper) { case '+': if (strcmp(name, "X")==0) asmlin("INX", ""); else if (strcmp(name, "Y")==0) asmlin("INY", ""); - else if (strcmp(name, "A")==0) poperr(name); //65C02 supports implicit INC, 6502 does not + else if (strcmp(name, "A")==0 && !cmos) poperr(name); //65C02 supports implicit INC, 6502 does not else { - asmlin("INC", name); + asmlin("INC", word); if (isint) { newlbl(skplbl); asmlin("BNE", skplbl); @@ -383,7 +403,7 @@ void prcpst(int isint, char* name, char *index) { case '-': if (strcmp(name, "X")==0) asmlin("DEX", ""); else if (strcmp(name, "Y")==0) asmlin("DEY", ""); - else if (strcmp(name, "A")==0) poperr(name); //65C02 supports implicit DEC, 6502 does not + else if (strcmp(name, "A")==0 && !cmos) poperr(name); //65C02 supports implicit DEC, 6502 does not else { if (isint) { newlbl(skplbl); @@ -392,7 +412,7 @@ void prcpst(int isint, char* name, char *index) { asmlin("DEC", name1); setlbl(skplbl); } - asmlin("DEC", name); + asmlin("DEC", name); } break; case '<': @@ -419,7 +439,7 @@ void prcpst(int isint, char* name, char *index) { } /* Parse Post Operator */ -int prspst(char trmntr, int isint, char* name, char* index) { +int prspst(char trmntr, int isint, char* name, char* index, char indtyp, char ispntr) { oper = getnxt(); CCMNT(oper); DEBUG("Checking for post operation '%c'\n", oper) @@ -427,7 +447,7 @@ int prspst(char trmntr, int isint, char* name, char* index) { skpchr(); CCMNT(oper); expect(trmntr); - prcpst(isint, name, index); //Process Post-Op + prcpst(isint, name, index, indtyp, ispntr); //Process Post-Op return 0; } DEBUG("Not a post operation\n", 0) diff --git a/src/parse.h b/src/parse.h index 6e8c5b2..8c3b36e 100644 --- a/src/parse.h +++ b/src/parse.h @@ -55,7 +55,7 @@ int prsbyt(); //Parse Numeric Byte void prslit(); //Parse Literal int prsnum(int maxval); //Parse Numeric void prsopr(); //Parse Arithmetic Operator -int prspst(char trmntr, int isint, char* name, char* index); //Parse Post Operator +int prspst(char trmntr, int isint, char* name, char* index, char indtyp, char ispntr); //Parse Post Operator int psizof(void); //Parse SizeOf Operator int pidxof(void); //Parse SizeOf Operator void skpchr(); //Skip Next Character diff --git a/src/stmnt.c b/src/stmnt.c index 63746a9..08336c3 100644 --- a/src/stmnt.c +++ b/src/stmnt.c @@ -1,536 +1,579 @@ -/************************************ - * C02 Statement Compiling Routines * - ************************************/ - -#include -#include -#include -#include -#include - -#include "common.h" -#include "asm.h" -#include "parse.h" -#include "label.h" -#include "vars.h" -#include "cond.h" -#include "expr.h" -#include "stmnt.h" - -/* Begin Program Block */ -void bgnblk(char blkchr) { - DEBUG("Beginning program block\n", 0) - if (blkchr) { - expect(blkchr); - inblck = TRUE; - } - else - inblck = look('{'); - DEBUG("Set INBLCK to %d\n", inblck) - setblk(inblck); -} - -/* End Program Block * - * Args: blkflg: End of Multiline Block */ -void endblk(int blkflg) { - int lbtype; - DEBUG("Ending program block with flag %d\n", blkflg) - expect('}'); //Block End Character - DEBUG("Found inblck set to %d\n", inblck) - if (inblck != blkflg) ERROR("Encountered '}' without matching '{'\n", 0, EXIT_FAILURE) - lbtype = poplbl(); - if (lbtype == LTDO) pdowhl(); //Parse While at End of Do Loop -} - -/* Parse Shortcut If */ -void prssif(char trmntr) { - newlbl(cndlbl); //Create Label for "if FALSE" expression - prscnd(')', FALSE); //Parse Condition - expect('?'); - prsxpr(':'); //Parse "if TRUE" expression - newlbl(skplbl); //Create End of Expression Label - asmlin("JMP", skplbl); //Jump over "if FALSE" expression - setlbl(cndlbl); //Emit "if FALSE" label - prsxpr(trmntr); //Parse "if FALSE" expression - setlbl(skplbl); //Emit End of Expression Label -} - -/* Process Array Index */ -void prcidx(int idxtyp, char *name, char *index) -{ - if (strlen(index)) { - if (idxtyp == LITERAL) { - strcat(name, "+"); - strcat(name, index); - } - else { - asmlin("LDX", index); - strcat(name,",X"); - } - } -} - -/* Set word to assignment variable * - * adding write offset (if set) */ -void setasn(char *name) { - strcpy(word, name); - if (wrtofs[0]) strcat(word, wrtofs); -} - -/* Process Assignment of X and Y variables */ -void prcaxy(void) { - DEBUG("Processing X assignment variable '%s'\n", xsnvar) - if (xsnvar[0]) { - setasn(xsnvar); - if (strlen(xsnidx)) { //Process X variable Index - if (xsnivt != LITERAL) { - asmlin("PHA", ""); //Save Accumulator - asmlin("TXA", ""); //Transfer Return Value to Accumulator - prcidx(xsnivt, word, xsnidx); //Process Index - asmlin("STA", word); //Store Return Value - asmlin("PLA", ""); //Restore Accumulator - } else { - prcidx(xsnivt, word, xsnidx); //Process Index - asmlin("STX", word); //Store Return Value - } - } - else asmlin("STX", word); //Store Return Value - xsnvar[0] = 0; - } - DEBUG("Processing Y assignment variable '%s'\n", ysnvar) - if (ysnvar[0]) { - setasn(ysnvar); - if (strlen(ysnidx)) prcidx(ysnivt, word, ysnidx); //Process Index - asmlin("STY", word); //Store Return Value - ysnvar[0] = 0; - } -} - -/* Process Assignment */ -void prcasn(char trmntr) { - expect('='); - if (look('(')) prssif(trmntr); //Parse Shortcut If - else prsxpr(trmntr); //Parse Expression - prcaxy(); //Process X and Y assignments - DEBUG("Checking if '%s' is a register\n", asnvar) - if (strcmp(asnvar, "X")==0) asmlin("TAX", ""); - else if (strcmp(asnvar, "Y")==0) asmlin("TAY", ""); - else if (strcmp(asnvar, "A")==0) return; - DEBUG("Processing assignment variable '%s'\n", asnvar) - setasn(asnvar); - if (asnidx[0]) prcidx(asnivt, word, asnidx); //Process Index - asmlin("STA", word); //Store Return Value -} - -/* Process Integer Assignment */ -void prcasi(char trmntr) { - DEBUG("Processing Integer Assignment\n", 0); - expect('='); - strcpy(xsnvar, vrname); //Set Assignment LSB - strcpy(ysnvar, vrname); strcat(ysnvar, "+1"); //Set Assignment MSB - ysnidx[0] = 0; //No Y Index - prsxpi(trmntr, TRUE); //Parse Integer Expression, Allowing Functions - prcaxy(); -} - -/* Parse and Return Array Index and Type */ -int getidx(char* idx) { - prsidx(TRUE); //Parse Array Index - if (valtyp == LITERAL) strncpy(idx, word, VARLEN); - else strncpy(idx, value, VARLEN); - DEBUG("Parsed index %s\n", idx) - return valtyp; -} - -/* Process Assignment Variable(s) */ -void prcavr(char trmntr) { - chksym(TRUE, FALSE, word); - DEBUG("Processing assignment of variable %s\n", word); - strcpy(vrname, word); //save variable to assign to - if (valtyp == STRUCTURE) prsmbr(vrname); //Updates word and vartyp - if (vartyp == VTINT) { - if (ispopr()) {if (prspst(trmntr, TRUE, vrname, "")) expctd("post operator");} - else prcasi(trmntr); //Process Integer Assignment - return; - } - strcpy(asnvar, vrname); - asntyp = valtyp; //Set Assigned Variable Type - DEBUG("Set STA variable to %s\n", asnvar) - if (asntyp == VARIABLE && look(';')) { - asmlin("STA", asnvar); - return; - } - if (asntyp == ARRAY) asnivt = getidx(asnidx); //Get Array Index and Type - else asnidx[0] = 0; - DEBUG("Set STA index to '%s'", asnidx) DETAIL(" and type to %d\n", asnivt) - if (ispopr()) { - if (prspst(trmntr, FALSE, asnvar, asnidx)) expctd("post operator"); - return; - } - if (look(',')) { - if (asntyp == REGISTER) ERROR("Register %s not allowed in plural assignment\n", asnvar, EXIT_FAILURE) - prsvar(FALSE, FALSE); //get variable name - strcpy(ysnvar, word); - DEBUG("Set STY variable to %s\n", ysnvar) - if (valtyp == ARRAY) ysnivt = getidx(ysnidx); //Get Array Index and Type - else ysnidx[0] = 0; - DEBUG("Set STY index to '%s'", ysnidx) DETAIL(" and type to %d\n", ysnivt) - if (look(',')) { - prsvar(FALSE, FALSE); //get variable name - strcpy(xsnvar, word); - DEBUG("Set STX variable to %s\n", xsnvar) - //if (valtyp == ARRAY) ERROR("Array element not allowed in third assignment\n", 0, EXIT_FAILURE) - if (valtyp == ARRAY) xsnivt = getidx(xsnidx); //Get Array Index and Type - else xsnidx[0] = 0; - } - } - prcasn(trmntr); -} - -/* Parse 'asm' String Parameter */ -void pasmst(char trmntr) { - skpspc(); //Skip Spaces - if (!match('"')) expctd("string"); - getstr(); - skpspc(); - expect(trmntr); -} - -/* Parse and Compile 'asm' statement */ -void pasm(void) { - char opcode[LINELEN]; - expect('('); - pasmst(','); - if (strlen(word)) setlbl(word); - pasmst(','); - strcpy(opcode, word); - pasmst(')'); - expect(';'); - asmlin(opcode, word); -} - -/* Parse and Compile an Assignment */ -void prsasn(char trmntr) { - getwrd(); //Get Variable to be Assigned - DEBUG("Parsing assignment of word %s\n", word) - prcavr(trmntr); -} - -/* parse and compile 'break'/'continue' statement */ -void pbrcnt(int lbflag) -{ - DEBUG("Parsing BREAK/CONTINUE statement\n", 0) - if (lstlbl(lbflag) < 0) ERROR("Break/continue statement outside of loop\n", 0, EXIT_FAILURE) - DEBUG("Found Label '%s'\n", tmplbl) - asmlin("JMP", tmplbl); - expect(';'); -} - -/* parse and compile 'do' statement */ -void pdo(void) { - DEBUG("Parsing DO statement '%c'\n", nxtchr) - newlbl(endlbl); //Create End Label - pshlbl(LTDWHL, endlbl); //and Push onto Stack - reqlbl(loplbl); //Get or Create/Set Loop Label - pshlbl(LTDO, loplbl); //Push onto Stack - bgnblk(FALSE); //Check For and Begin Block -} - -/* parse and compile 'while' after 'do' statement */ -void pdowhl(void) { - DEBUG("Parsing WHILE after DO '%c'\n", nxtchr) - getwrd(); //Check for While - if (!wordis("WHILE")) expctd("while statement"); - expect('('); - strcpy(cndlbl, loplbl); //Set Conditional Label to Loop Label - prscnd(')', TRUE); //Parse Conditional Expession - poplbl(); //Pop While Conditional Label - setlbl(endlbl); //and Set Label to Emit on Next Line - expect(';'); //Check for End of Statement -} - - -/* parse and compile for statement */ -void pfor(void) { - DEBUG("Parsing FOR statement '%c'\n", nxtchr); - expect('('); - prsasn(';'); //Process Initial Assignment - newlbl(forlbl); //Create For Loop Conditional Label - setlbl(forlbl); //and Set to Emit on Next Line - newlbl(endlbl); //Create End Label - pshlbl(LTEND, endlbl); //and Push onto Stack - newlbl(loplbl); //Create Loop Label - pshlbl(LTLOOP, loplbl); //and Push onto Stack - newlbl(cndlbl); //Create Conditional Label - prscnd(';', TRUE); //Parse Conditional Expession - asmlin("JMP", endlbl); //Jump over Increment - setlbl(loplbl); //Set to Emit on Next Line - prsasn(')'); //Parse Increment Assignment - asmlin("JMP", forlbl); //Jump to Conditional - setlbl(cndlbl); //Emit Label at Start of Loop - bgnblk(FALSE); //Check For and Begin Block -} - -/* parse and compile if statement */ -void pif(void) { - DEBUG("Parsing IF statement\n", 0) - expect('('); - newlbl(cndlbl); //Create New Label - pshlbl(LTIF,cndlbl); //Push Onto Stack - prscnd(')', FALSE); //Parse Conditional Expession - bgnblk(FALSE); //Check For and Begin Block -} - -/* parse and compile else statement */ -void pelse(void) { - DEBUG("Parsing ELSE statement\n", 0) - strcpy(lbltmp, lblasm); //Save Line Label - lblasm[0] = 0; //and Clear It - if (toplbl(skplbl) != LTELSE) { //Get Chained ELSE Label or - newlbl(skplbl); //Create Skip Label - pshlbl(LTELSE, skplbl); //Push Onto Stack - } - asmlin("JMP", skplbl); //Emit Jump over Block Code - strcpy(lblasm, lbltmp); //Restore Line Label - bgnblk(FALSE); //Check For and Begin Block -} - -/* parse and compile if statement */ -void pgoto(void) { - DEBUG("Parsing GOTO statement\n", 0) - if (look('(')) { - DEBUG("Processing Indirect GOTO\n", 0); - prsxpi(')', FALSE); //Parse Integer Expression w/o Assembly - sprintf(word, "(%s)", value); //Set Indirect Argument - } else { - if (!chkadr(ADNONE, FALSE)) getwrd(); - } - expect(';'); - asmlin("JMP", word); -} - -/* parse and compile inline statement */ -void pinlne(void) { - DEBUG("Parsing INLINE statement\n", 0) - do { - DEBUG("Parsing inline parameter\n", 0) - if (look('&')) { - reqvar(FALSE); //Get Variable Name - strcpy(word, "<"); - strcat(word, value); - strcat(word, ", >"); - strcat(word, value); - asmlin(BYTEOP, word); - } - else if (look('"')) { - value[0] = 0; - while (!match('"')) { - CCMNT(nxtchr); - sprintf(word, "$%hhX,", getnxt()); - strcat(value, word); - } - strcat(value,"0"); - CCMNT(nxtchr); - skpchr(); //Skip Terminating Quote - asmlin(BYTEOP, value); - } - else { - prslit(0xFF); //Parse Literal - sprintf(word, "$%hhX", litval); //not needed? - asmlin(BYTEOP, value); - } - } while (look(',')); - expect(';'); -} - -/* parse and compile pop statement */ -void ppop(void) { - DEBUG("Parsing POP statement\n", 0) - do { - if (look('.')) term[0]=0; - else { - reqvar(TRUE); - strcpy(term, value); - chkidx(); - } - asmlin("PLA", ""); //Pop Value off Stack - if (term[0]) asmlin("STA", term); - } while (look(',')); - expect(';'); -} - -/* parse and compile push statement */ -void ppush(void) { - DEBUG("Parsing PUSH statement\n", 0) - do { - if (!chkadr(ADPUSH, TRUE)) { - prsxpr(0); //Parse Expression - asmlin("PHA",""); //Push Result on Stack - } - } while (look(',')); - expect(';'); -} - -/* parse and compile return statement */ -void pretrn(void) { - DEBUG("Parsing RETURN statement\n", 0) - skpspc(); - prsfpr(';'); //Parse Function Return Valuea - asmlin("RTS", ""); - lsrtrn = TRUE; //Set RETURN flag -} - -/* parse and compile select statement */ -void pslct(void) { - DEBUG("Parsing SELECT statement\n", 0) - expect('('); - prsxpr(')'); //Parse Expression - newlbl(endlbl); //Create New Label - pshlbl(LTSLCT,endlbl); //Push Onto Stack - bgnblk('{'); //Require Beginning of Block - fcase = TRUE; - strcpy(xstmnt, "CASE"); //Require Next Statement to be CASE -} - -/* process end of case block */ -void ecase(void) { - DEBUG("Processing end of CASE block\n", 0) - if (poplbl(cndlbl) != LTCASE) ERROR("%s not at end of CASE block\n", word, EXIT_FAILURE) - if (toplbl(endlbl) != LTSLCT) ERROR("Illegal nesting in SELECT statement\n", 0, EXIT_FAILURE) - asmlin("JMP", endlbl); //Emit jump over default case - setlbl(cndlbl); //Set entry point label to emit -} - -/* parse and compile select statement */ -void pcase(void) { - if (!fcase) ecase(); //Process end of case block - skplbl[0] = 0; //Clear Skip Label - newlbl(cndlbl); //Create Conditional Label - pshlbl(LTCASE, cndlbl); //and Push onto Stack - while(TRUE) { - prstrm(FALSE); //Parse CASE argument - if (!fcase || valtyp != LITERAL || litval) - asmlin("CMP", term); //Emit Comparison - if (look(',')) { - chklbl(skplbl); //Emit skip to beginning of CASE block - asmlin("BEQ", skplbl); - fcase = 0; - continue; //Parse next argument - } - bgnblk(':'); //Emit branch to end of CASE block - asmlin("BNE", cndlbl); - break; - } - if (skplbl[0]) setlbl(skplbl); //Set CASE block label if defined - fcase = FALSE; -} - -/* parse and compile default statement */ -void pdflt(void) { - expect(':'); - ecase(); //Process end of case block -} - -/* parse and compile while statement */ -void pwhile(void) { - DEBUG("Parsing WHILE statement '%c'\n", nxtchr) - expect('('); - newlbl(endlbl); //Create End Label - pshlbl(LTEND, endlbl); //and Push onto Stack - reqlbl(loplbl); //Get or Create/Set Loop Label - pshlbl(LTLOOP, loplbl); //Push onto Stack - if (!look(')')) { - newlbl(cndlbl); //Create Conditional Skip Label - prscnd(')', TRUE); //Parse Conditional Expession - asmlin("JMP", endlbl); //Emit Jump to End of Loop - setlbl(cndlbl); //and Set Label to Emit on Next Line - } - bgnblk(FALSE); //Check For and Begin Block -} - -/* generate unimplemented statement error */ -void punimp(void) { - ERROR("Unimplemented statement '%s' encountered\n", word, EXIT_FAILURE) -} - -/* Parse Function Call as Statement */ -void prsfns(void) { - strcpy(term, word); //Copy Function Name - prsfnc(';'); //Parse Function Call - return; -} - -/* parse and compile identifier (variable or function call) */ -void prssym(void) { - DEBUG("Parsing Identifier %s\n", word) - valtyp = gettyp(); - if (valtyp == FUNCTION) prsfns(); //Parse Statement Function Call - else prcavr(';'); //Parse Assignment -} - -/* parse and compile program statement */ -void pstmnt(void) { - DEBUG("Parsing statement '%s'\n", word) - if (wordis("DO")) { - pdo(); - return; - } - if (wordis("ELSE")) { - pelse(); - return; - } - if (wordis("FOR")) { - pfor(); - return; - } - if (wordis("IF")) { - pif(); - return; - } - if (wordis("SWITCH")) { - ERROR("SWITCH not implemented. Use SELECT.\n", word, EXIT_FAILURE) - } - if (wordis("SELECT")) { - pslct(); - return; - } - if (wordis("CASE")) { - pcase(); - return; - } - if (wordis("DEFAULT")) { - pdflt(); - return; - } - if (wordis("WHILE")) { - pwhile(); - return; - } - if(match(':')) { - prslab(); //Parse Program Label - setlbl(word); //Set Label to Emit - return; - } - if (wordis("ASM")) pasm(); - else if (wordis("BREAK")) - pbrcnt(LFEND); - else if (wordis("CONTINUE")) - pbrcnt(LFBGN); - else if (wordis("GOTO")) - pgoto(); - else if (wordis("INLINE")) - pinlne(); - else if (wordis("POP")) - ppop(); - else if (wordis("PUSH")) - ppush(); - else if (wordis("RETURN")) - pretrn(); - else - prssym(); - if (lblcnt && !inblck) { - DEBUG("Ending implied block\n", 0) - if (poplbl() == LTDO) - pdowhl(); //Parse While at End of Do Loop - } -} +/************************************ + * C02 Statement Compiling Routines * + ************************************/ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "asm.h" +#include "parse.h" +#include "label.h" +#include "vars.h" +#include "cond.h" +#include "expr.h" +#include "stmnt.h" + +/* Begin Program Block */ +void bgnblk(char blkchr) { + DEBUG("Beginning program block\n", 0) + if (blkchr) { + DEBUG("Expecting Block Delimiter '%c'\n", blkchr); + expect(blkchr); + inblck = TRUE; + } + else + inblck = look('{'); + DEBUG("Set INBLCK to %d\n", inblck) + setblk(inblck); +} + +/* End Program Block * + * Args: blkflg: End of Multiline Block */ +void endblk(int blkflg) { + int lbtype; + DEBUG("Ending program block with flag %d\n", blkflg) + expect('}'); //Block End Character + DEBUG("Found inblck set to %d\n", inblck) + if (inblck != blkflg) ERROR("Encountered '}' without matching '{'\n", 0, EXIT_FAILURE) + lbtype = poplbl(); + if (lbtype == LTDO) pdowhl(); //Parse While at End of Do Loop +} + +/* Parse Shortcut If */ +void prssif(char trmntr) { + newlbl(cndlbl); //Create Label for "if FALSE" expression + prscnd(')', FALSE); //Parse Condition + expect('?'); + prsxpr(':'); //Parse "if TRUE" expression + newlbl(skplbl); //Create End of Expression Label + asmlin("JMP", skplbl); //Jump over "if FALSE" expression + setlbl(cndlbl); //Emit "if FALSE" label + prsxpr(trmntr); //Parse "if FALSE" expression + setlbl(skplbl); //Emit End of Expression Label +} + +/* Process Array Index */ +void prcidx(int idxtyp, char *name, char *index) +{ + if (strlen(index)) { + if (idxtyp == LITERAL) { + strcat(name, "+"); + strcat(name, index); + } + else { + asmlin("LDX", index); + strcat(name,",X"); + } + } +} + +/* Set word to assignment variable * + * adding write offset (if set) */ +void setasn(char *name, char ispntr) { + if (ispntr) strcpy(word,"("); + else word[0] = 0; + strcat(word, name); + if (wrtofs[0]) strcat(word, wrtofs); + if (ispntr) strcat(word,")"); +} + +void prcixy(char rgstr, char* idx, int ivt) { + DEBUG("Processing %c register indexed assignment\n", rgstr) + if (strlen(idx)) { //Process X variable Index + if (ivt != LITERAL) { + asmlin("PHA", ""); //Save Accumulator + if (rgstr == 'X') asmlin("TXA", ""); //Transfer Return Value to Accumulator + else asmlin("TYA", ""); + prcidx(ivt, word, idx); //Process Index + asmlin("STA", word); //Store Return Value + asmlin("PLA", ""); //Restore Accumulator + } else { + prcidx(ivt, word, idx); //Process Index + if (rgstr == 'X') asmlin("STX", word); //Store Return Value + else asmlin("STY", word); + } + } +} + +/* Process Assignment of X and Y variables */ +void prcaxy(void) { + DEBUG("Processing X assignment variable '%s'\n", xsnvar) + if (xsnvar[0]) { + setasn(xsnvar, FALSE); + if (strlen(xsnidx)) prcixy('X', xsnidx, xsnivt); //Process Index + else asmlin("STX", word); //Store Return Value + xsnvar[0] = 0; + } + DEBUG("Processing Y assignment variable '%s'\n", ysnvar) + if (ysnvar[0]) { + setasn(ysnvar, FALSE); + if (strlen(ysnidx)) prcixy('Y', ysnidx, ysnivt); //Process Index + else asmlin("STY", word); //Store Return Value + ysnvar[0] = 0; + } +} + +/* Process Assignment */ +void prcasn(char trmntr, char ispntr) { + expect('='); + if (look('(')) prssif(trmntr); //Parse Shortcut If + else prsxpr(trmntr); //Parse Expression + prcaxy(); //Process X and Y assignments + DEBUG("Checking if '%s' is a register\n", asnvar) + if (strcmp(asnvar, "X")==0) asmlin("TAX", ""); + else if (strcmp(asnvar, "Y")==0) asmlin("TAY", ""); + else if (strcmp(asnvar, "A")==0) return; + DEBUG("Processing assignment variable '%s'\n", asnvar) + setasn(asnvar, ispntr); + if (asnidx[0]) { + if (ispntr) prcptx(asnidx); //Process Pointer Index + else prcidx(asnivt, word, asnidx); //Process Index + } + else if (ispntr && !cmos) { + strcat(word, ",Y"); + asmlin("LDY","0"); + } + asmlin("STA", word); //Store Return Value +} + +/* Process Integer Assignment */ +void prcasi(char trmntr) { + DEBUG("Processing Integer Assignment\n", 0); + expect('='); + strcpy(xsnvar, vrname); //Set Assignment LSB + strcpy(ysnvar, vrname); strcat(ysnvar, "+1"); //Set Assignment MSB + ysnidx[0] = 0; //No Y Index + prsxpi(trmntr, TRUE); //Parse Integer Expression, Allowing Functions + prcaxy(); +} + +/* Parse and Return Array Index and Type */ +int getidx(char* idx) { + prsidx(TRUE); //Parse Array Index + if (valtyp == LITERAL) strncpy(idx, word, VARLEN); + else strncpy(idx, value, VARLEN); + DEBUG("stmnt.getidx: Parsed index %s\n", idx) + return valtyp; +} + +/* Process Accumulator Assignment Variable */ +int prcava(char *name, char trmntr, char ispntr) { + strcpy(asnvar, name); + asntyp = valtyp; //Set Assigned Variable Type + DEBUG("stmnt.prcava: Set STA variable to %s\n", asnvar) + if (asntyp == VARIABLE && look(';')) { + asmlin("STA", asnvar); + return TRUE; + } + if (asntyp == ARRAY) asnivt = getidx(asnidx); //Get Array Index and Type + else asnidx[0] = 0; + if (ispntr && strcmp(asnidx, "X") == 0) ERROR("Illegal use of register X\n", 0, EXIT_FAILURE) + DEBUG("stmnt.prcava: Set STA index to '%s'", asnidx) DETAIL(" and type to %d\n", asnivt) + if (ispopr()) { + if (prspst(trmntr, FALSE, asnvar, asnidx, asnivt, ispntr)) expctd("post operator"); + return TRUE; + } + return FALSE; +} + +/* Process Assignment Variable(s) */ +void prcavr(char trmntr) { + chksym(TRUE, FALSE, word); + DEBUG("Processing assignment of variable %s\n", word); + strcpy(vrname, word); //save variable to assign to + if (valtyp == STRUCTURE) prsmbr(vrname); //Updates word and vartyp + if (vartyp == VTINT) { + if (ispopr()) {if (prspst(trmntr, TRUE, vrname, "", 0, FALSE)) expctd("post operator");} + else prcasi(trmntr); //Process Integer Assignment + return; + } + if (prcava(vrname, trmntr, FALSE)) return; + if (look(',')) { + if (asntyp == REGISTER) ERROR("Register %s not allowed in plural assignment\n", asnvar, EXIT_FAILURE) + prsvar(FALSE, FALSE); //get variable name + strcpy(ysnvar, word); + DEBUG("Set STY variable to %s\n", ysnvar) + if (valtyp == ARRAY) ysnivt = getidx(ysnidx); //Get Array Index and Type + else ysnidx[0] = 0; + DEBUG("Set STY index to '%s'", ysnidx) DETAIL(" and type to %d\n", ysnivt) + if (look(',')) { + prsvar(FALSE, FALSE); //get variable name + strcpy(xsnvar, word); + DEBUG("Set STX variable to %s\n", xsnvar) + //if (valtyp == ARRAY) ERROR("Array element not allowed in third assignment\n", 0, EXIT_FAILURE) + if (valtyp == ARRAY) xsnivt = getidx(xsnidx); //Get Array Index and Type + else xsnidx[0] = 0; + } + } + prcasn(trmntr, FALSE); +} + +/* Parse 'asm' String Parameter */ +void pasmst(char trmntr) { + skpspc(); //Skip Spaces + if (!match('"')) expctd("string"); + getstr(); + skpspc(); + expect(trmntr); +} + +/* Parse and Compile 'asm' statement */ +void pasm(void) { + char opcode[LINELEN]; + expect('('); + pasmst(','); + if (strlen(word)) setlbl(word); + pasmst(','); + strcpy(opcode, word); + pasmst(')'); + expect(';'); + asmlin(opcode, word); +} + +/* Parse and Compile Assignment of Pointer */ +void prcasp(char trmntr) { + prsptr(); //Parse Pointer Dereference + DEBUG("stmnt.prcasp: Processing assignment to dereferenced pointer %s\n", value) + if (prcava(value, trmntr, TRUE)) return; //Process Accumulator Assignment Variable + prcasn(trmntr, TRUE); +} + +/* Parse and Compile an Assignment */ +void prsasn(char trmntr) { + if (match('*')) prcasp(trmntr); + else { + getwrd(); //Get Variable to be Assigned + DEBUG("Parsing assignment of word %s\n", word) + prcavr(trmntr); + } +} + +/* parse and compile 'break'/'continue' statement */ +void pbrcnt(int lbflag) +{ + DEBUG("Parsing BREAK/CONTINUE statement\n", 0) + if (lstlbl(lbflag) < 0) ERROR("Break/continue statement outside of loop\n", 0, EXIT_FAILURE) + DEBUG("Found Label '%s'\n", tmplbl) + asmlin("JMP", tmplbl); + expect(';'); +} + +/* parse and compile 'do' statement */ +void pdo(void) { + DEBUG("Parsing DO statement '%c'\n", nxtchr) + newlbl(endlbl); //Create End Label + pshlbl(LTDWHL, endlbl); //and Push onto Stack + reqlbl(loplbl); //Get or Create/Set Loop Label + pshlbl(LTDO, loplbl); //Push onto Stack + bgnblk(FALSE); //Check For and Begin Block +} + +/* parse and compile 'while' after 'do' statement */ +void pdowhl(void) { + DEBUG("Parsing WHILE after DO '%c'\n", nxtchr) + getwrd(); //Check for While + if (!wordis("WHILE")) expctd("while statement"); + expect('('); + strcpy(cndlbl, loplbl); //Set Conditional Label to Loop Label + prscnd(')', TRUE); //Parse Conditional Expession + poplbl(); //Pop While Conditional Label + setlbl(endlbl); //and Set Label to Emit on Next Line + expect(';'); //Check for End of Statement +} + + +/* parse and compile for statement */ +void pfor(void) { + DEBUG("Parsing FOR statement '%c'\n", nxtchr); + expect('('); + prsasn(';'); //Process Initial Assignment + newlbl(forlbl); //Create For Loop Conditional Label + setlbl(forlbl); //and Set to Emit on Next Line + newlbl(endlbl); //Create End Label + pshlbl(LTEND, endlbl); //and Push onto Stack + newlbl(loplbl); //Create Loop Label + pshlbl(LTLOOP, loplbl); //and Push onto Stack + newlbl(cndlbl); //Create Conditional Label + prscnd(';', TRUE); //Parse Conditional Expession + asmlin("JMP", endlbl); //Jump over Increment + setlbl(loplbl); //Set to Emit on Next Line + prsasn(')'); //Parse Increment Assignment + asmlin("JMP", forlbl); //Jump to Conditional + setlbl(cndlbl); //Emit Label at Start of Loop + bgnblk(FALSE); //Check For and Begin Block +} + +/* parse and compile if statement */ +void pif(void) { + DEBUG("Parsing IF statement\n", 0) + expect('('); + newlbl(cndlbl); //Create New Label + pshlbl(LTIF,cndlbl); //Push Onto Stack + prscnd(')', FALSE); //Parse Conditional Expession + bgnblk(FALSE); //Check For and Begin Block +} + +/* parse and compile else statement */ +void pelse(void) { + DEBUG("Parsing ELSE statement\n", 0) + strcpy(lbltmp, lblasm); //Save Line Label + lblasm[0] = 0; //and Clear It + if (toplbl(skplbl) != LTELSE) { //Get Chained ELSE Label or + newlbl(skplbl); //Create Skip Label + pshlbl(LTELSE, skplbl); //Push Onto Stack + } + asmlin("JMP", skplbl); //Emit Jump over Block Code + strcpy(lblasm, lbltmp); //Restore Line Label + bgnblk(FALSE); //Check For and Begin Block +} + +/* parse and compile if statement */ +void pgoto(void) { + DEBUG("Parsing GOTO statement\n", 0) + if (look('(')) { + DEBUG("Processing Indirect GOTO\n", 0); + prsxpi(')', FALSE); //Parse Integer Expression w/o Assembly + sprintf(word, "(%s)", value); //Set Indirect Argument + } else { + if (!chkadr(ADNONE, FALSE)) getwrd(); + } + expect(';'); + asmlin("JMP", word); +} + +/* parse and compile inline statement */ +void pinlne(void) { + DEBUG("Parsing INLINE statement\n", 0) + do { + DEBUG("Parsing inline parameter\n", 0) + if (look('&')) { + reqvar(FALSE); //Get Variable Name + strcpy(word, "<"); + strcat(word, value); + strcat(word, ", >"); + strcat(word, value); + asmlin(BYTEOP, word); + } + else if (look('"')) { + value[0] = 0; + while (!match('"')) { + CCMNT(nxtchr); + sprintf(word, "$%hhX,", getnxt()); + strcat(value, word); + } + strcat(value,"0"); + CCMNT(nxtchr); + skpchr(); //Skip Terminating Quote + asmlin(BYTEOP, value); + } + else { + prslit(0xFF); //Parse Literal + sprintf(word, "$%hhX", litval); //not needed? + asmlin(BYTEOP, value); + } + } while (look(',')); + expect(';'); +} + +/* parse and compile pop statement */ +void ppop(void) { + DEBUG("Parsing POP statement\n", 0) + do { + if (look('.')) term[0]=0; + else { + reqvar(TRUE); + strcpy(term, value); + chkidx(); + } + asmlin("PLA", ""); //Pop Value off Stack + if (term[0]) asmlin("STA", term); + } while (look(',')); + expect(';'); +} + +/* parse and compile push statement */ +void ppush(void) { + DEBUG("Parsing PUSH statement\n", 0) + do { + if (!chkadr(ADPUSH, TRUE)) { + prsxpr(0); //Parse Expression + asmlin("PHA",""); //Push Result on Stack + } + } while (look(',')); + expect(';'); +} + +/* parse and compile return statement */ +void pretrn(int INTRPT) { + DEBUG("Parsing RETURN statement\n", 0) + skpspc(); + if (INTRPT) { + expect(';'); + asmlin("RTI", ""); + } else { + prsfpr(';'); //Parse Function Return Valuea + asmlin("RTS", ""); + } + lsrtrn = TRUE; //Set RETURN flag +} + +/* parse and compile select statement */ +void pslct(void) { + DEBUG("Parsing SELECT statement\n", 0) + expect('('); + prsxpr(')'); //Parse Expression + newlbl(endlbl); //Create New Label + pshlbl(LTSLCT,endlbl); //Push Onto Stack + bgnblk('{'); //Require Beginning of Block + fcase = TRUE; + strcpy(xstmnt, "CASE"); //Require Next Statement to be CASE +} + +/* process end of case block */ +void ecase(void) { + DEBUG("Processing end of CASE block\n", 0) + if (poplbl(cndlbl) != LTCASE) ERROR("%s not at end of CASE block\n", word, EXIT_FAILURE) + if (toplbl(endlbl) != LTSLCT) ERROR("Illegal nesting in SELECT statement\n", 0, EXIT_FAILURE) + asmlin("JMP", endlbl); //Emit jump over default case + setlbl(cndlbl); //Set entry point label to emit +} + +/* parse and compile select statement */ +void pcase(void) { + if (!fcase) ecase(); //Process end of case block + skplbl[0] = 0; //Clear Skip Label + newlbl(cndlbl); //Create Conditional Label + pshlbl(LTCASE, cndlbl); //and Push onto Stack + while(TRUE) { + prstrm(FALSE); //Parse CASE argument + if (!fcase || valtyp != LITERAL || litval) + asmlin("CMP", term); //Emit Comparison + if (look(',')) { + chklbl(skplbl); //Emit skip to beginning of CASE block + asmlin("BEQ", skplbl); + fcase = 0; + continue; //Parse next argument + } + bgnblk(':'); //Emit branch to end of CASE block + asmlin("BNE", cndlbl); + break; + } + if (skplbl[0]) setlbl(skplbl); //Set CASE block label if defined + fcase = FALSE; +} + +/* parse and compile default statement */ +void pdflt(void) { + expect(':'); + ecase(); //Process end of case block +} + +/* parse and compile while statement */ +void pwhile(void) { + DEBUG("Parsing WHILE statement '%c'\n", nxtchr) + expect('('); + newlbl(endlbl); //Create End Label + pshlbl(LTEND, endlbl); //and Push onto Stack + reqlbl(loplbl); //Get or Create/Set Loop Label + pshlbl(LTLOOP, loplbl); //Push onto Stack + if (!look(')')) { + newlbl(cndlbl); //Create Conditional Skip Label + prscnd(')', TRUE); //Parse Conditional Expession + asmlin("JMP", endlbl); //Emit Jump to End of Loop + setlbl(cndlbl); //and Set Label to Emit on Next Line + } + bgnblk(FALSE); //Check For and Begin Block +} + +/* generate unimplemented statement error */ +void punimp(void) { + ERROR("Unimplemented statement '%s' encountered\n", word, EXIT_FAILURE) +} + +/* Parse Function Call as Statement */ +void prsfns(void) { + strcpy(term, word); //Copy Function Name + prsfnc(';'); //Parse Function Call + return; +} + +/* parse and compile identifier (variable or function call) */ +void prssym(void) { + DEBUG("Parsing Identifier %s\n", word) + valtyp = gettyp(); + if (valtyp == FUNCTION) prsfns(); //Parse Statement Function Call + else prcavr(';'); //Parse Assignment +} + +/* parse and compile program statement */ +void pstmnt(void) { + DEBUG("Parsing statement '%s'\n", word) + if (wordis("DO")) { + pdo(); + return; + } + if (wordis("ELSE")) { + pelse(); + return; + } + if (wordis("FOR")) { + pfor(); + return; + } + if (wordis("IF")) { + pif(); + return; + } + if (wordis("SWITCH")) { + ERROR("SWITCH not implemented. Use SELECT.\n", word, EXIT_FAILURE) + } + if (wordis("SELECT")) { + pslct(); + return; + } + if (wordis("CASE")) { + pcase(); + return; + } + if (wordis("DEFAULT")) { + pdflt(); + return; + } + if (wordis("WHILE")) { + pwhile(); + return; + } + if(match(':')) { + prslab(); //Parse Program Label + setlbl(word); //Set Label to Emit + return; + } + if (wordis("ASM")) pasm(); + else if (wordis("BREAK")) + pbrcnt(LFEND); + else if (wordis("CONTINUE")) + pbrcnt(LFBGN); + else if (wordis("GOTO")) + pgoto(); + else if (wordis("INLINE")) + pinlne(); + else if (wordis("POP")) + ppop(); + else if (wordis("PUSH")) + ppush(); + else if (wordis("RESUME")) + pretrn(TRUE); + else if (wordis("RETURN")) + pretrn(FALSE); + else + prssym(); + if (lblcnt && !inblck) { + DEBUG("Ending implied block\n", 0) + if (poplbl() == LTDO) + pdowhl(); //Parse While at End of Do Loop + } +} diff --git a/src/stmnt.h b/src/stmnt.h index 610066a..7809a6d 100644 --- a/src/stmnt.h +++ b/src/stmnt.h @@ -1,21 +1,23 @@ -/************************************ - * C02 Statement Compiling Routines * - ************************************/ - -char asnvar[VARLEN+1]; //Assigned Variable Name -int asntyp; //Assigned Variable Type -char asnidx[VARLEN+1] ; //Assigned Variable Index -int asnivt; //Assigned Index Variable Type -char ysnvar[VARLEN+1]; //Assigned Y Variable Name -char ysnidx[VARLEN+1] ; //Assigned Y Variable Index -int ysnivt; //Assigned Y Index Variable Type -char xsnvar[VARLEN+1]; //Assigned X Variable Name -char xsnidx[VARLEN+1] ; //Assigned X Variable Index -int xsnivt; //Assigned X Index Variable Type - -char xstmnt[LINELEN]; //Expected Statement - -void bgnblk(char blkchr); //End Program Block -void endblk(int blkflg); //End Program Block -void pdowhl(); //Parse and Compile WHILE after DO -void pstmnt(); //Parse and Compile Program Statement +/************************************ + * C02 Statement Compiling Routines * + ************************************/ + +char asnvar[VARLEN+1]; //Assigned Variable Name +int asntyp; //Assigned Variable Type +char asnidx[VARLEN+1] ; //Assigned Variable Index +int asnivt; //Assigned Index Variable Type +char ysnvar[VARLEN+1]; //Assigned Y Variable Name +char ysnidx[VARLEN+1] ; //Assigned Y Variable Index +int ysnivt; //Assigned Y Index Variable Type +char xsnvar[VARLEN+1]; //Assigned X Variable Name +char xsnidx[VARLEN+1] ; //Assigned X Variable Index +int xsnivt; //Assigned X Index Variable Type + +char xstmnt[LINELEN]; //Expected Statement + +void bgnblk(char blkchr); //End Program Block +void endblk(int blkflg); //End Program Block +void prcasp(char trmntr); //Process Pointer Assignment +void prcidx(int idxtyp, char *name, char *index); +void pdowhl(); //Parse and Compile WHILE after DO +void pstmnt(); //Parse and Compile Program Statement diff --git a/src/vars.c b/src/vars.c index 38ac9f1..b72812f 100644 --- a/src/vars.c +++ b/src/vars.c @@ -21,7 +21,7 @@ * varcnt if not found * * Returns: TRUE if found, otherwise FALSE */ int fndvar(char *name) { - DEBUG("Looking up variable '%s'\n", name) + DEBUG("vars,fndvar: Looking up variable '%s'\n", name) for (varidx=0; varidx -1) { @@ -159,7 +159,7 @@ int pidxof(void) { * Returns: variable size (as integer */ int psizof(void) { expect('@'); //Check for and Skip SizeOf Operator - DEBUG("Parsing SizeOf operator", 0); + DEBUG("vars.pdizof: Parsing SizeOf operator", 0); mbridx = -1; //Set Member Index to None reqvar(FALSE); //Parse Variable Name to get Size Of if (mbridx > -1) { @@ -181,7 +181,7 @@ int psizof(void) { /* Parse Data Array */ void prsdta(void) { - DEBUG("Parsing Array Data\n", 0) + DEBUG("vars.prsdta: Parsing Array Data\n", 0) int i; dtype = DTARRY; expect('{'); @@ -202,7 +202,7 @@ void prsdts(void) { dtype = DTSTR; getstr(); strcpy(value, word); - DEBUG("Parsed Data String '%s'\n", value) + DEBUG("vars.prsdts: Parsed Data String '%s'\n", value) } /* Store variable data * @@ -212,34 +212,34 @@ void prsdts(void) { void setdat(void) { int i; if (dtype == DTBYTE) { - DEBUG("Setting variable data to '%d'\n", litval) + DEBUG("vars.setdat: Setting variable data to '%d'\n", litval) dlen = 1; datvar[dsize++] = litval; } else if (dtype == DTINT) { - DEBUG("Setting variable data to '%d'\n", litval) + DEBUG("vars.setdat: Setting variable data to '%d'\n", litval) dlen = 2; datvar[dsize++] = litval & 0xFF; datvar[dsize++] = litval >> 8; } else if (dtype == DTARRY) { - DEBUG("Setting variable data to array of length %d\n", dlen) + DEBUG("vars.setdat: Setting variable data to array of length %d\n", dlen) for (i=0; i%1.dbg IF %ERRORLEVEL% NEQ 0 GOTO EOF ECHO Assembling File %1.asm -C:\Programs\dasm %1.asm -f1 -o%1.prg -l%1.lst -s%1.sym +..\a02.exe -p %1.asm %1.asm %1.lst >%1.out +REM C:\Programs\dasm %1.asm -f1 -o%1.prg -l%1.lst -s%1.sym IF %ERRORLEVEL% NEQ 0 GOTO EOF