2017-03-28 04:09:18 +00:00
|
|
|
/**************************************************************
|
|
|
|
* C02 Compiler - (C) 2013 Curtis F Kaylor *
|
|
|
|
* *
|
2017-05-05 03:15:53 +00:00
|
|
|
* C02 is a simpified C-like language designed for the 6502 *
|
2017-03-28 04:09:18 +00:00
|
|
|
* *
|
|
|
|
* This Compiler generates crasm compatible assembly language *
|
|
|
|
* *
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2017-04-22 18:39:52 +00:00
|
|
|
#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
|
2018-02-13 22:25:57 +00:00
|
|
|
#include "dclrtn.h" //Statement Compiling Code
|
2017-04-22 18:39:52 +00:00
|
|
|
#include "include.h" //Include File Parsing
|
2017-03-28 04:09:18 +00:00
|
|
|
|
2017-04-03 23:50:25 +00:00
|
|
|
/* Initilize Compiler Variables */
|
|
|
|
void init()
|
|
|
|
{
|
2017-04-22 18:39:52 +00:00
|
|
|
DEBUG("Initializing Compiler Variables\n",0);
|
|
|
|
defcnt = 0;
|
|
|
|
varcnt = 0;
|
|
|
|
lblcnt = 0;
|
|
|
|
curcol = 0;
|
|
|
|
curlin = 0;
|
|
|
|
inpfil = srcfil;
|
|
|
|
strcpy(inpnam, srcnam);
|
2018-01-28 18:27:33 +00:00
|
|
|
strcpy(incdir, "../include/");
|
2017-04-22 18:39:52 +00:00
|
|
|
alcvar = TRUE;
|
2017-05-01 01:17:50 +00:00
|
|
|
inblck = FALSE;
|
2017-05-05 03:15:53 +00:00
|
|
|
xstmnt[0] = 0;
|
2017-04-22 18:39:52 +00:00
|
|
|
nxtwrd[0] = 0;
|
|
|
|
nxtptr = 0;
|
2017-06-27 00:16:23 +00:00
|
|
|
vrwrtn = FALSE;
|
|
|
|
zpaddr = 0;
|
2018-01-28 18:27:33 +00:00
|
|
|
invasc = FALSE;
|
2018-02-15 04:40:57 +00:00
|
|
|
mskasc = FALSE;
|
2018-02-13 23:26:57 +00:00
|
|
|
fcase = FALSE;
|
2017-04-03 23:50:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Reads and parses the next Word in Source File */
|
2018-01-28 18:27:33 +00:00
|
|
|
void pword()
|
2017-04-22 18:39:52 +00:00
|
|
|
{
|
2017-05-16 00:25:11 +00:00
|
|
|
lsrtrn = FALSE; //Clear RETURN flag
|
2017-04-22 18:39:52 +00:00
|
|
|
getwrd();
|
2017-05-01 01:17:50 +00:00
|
|
|
ACMNT(word);
|
2017-04-22 18:39:52 +00:00
|
|
|
DEBUG("Parsing Word '%s'\n", word);
|
2018-02-13 23:26:57 +00:00
|
|
|
if (xstmnt[0]) {
|
|
|
|
if (wordis(xstmnt))
|
|
|
|
xstmnt[0] = 0; //Clear xstmnt
|
|
|
|
else
|
2017-05-05 03:15:53 +00:00
|
|
|
ERROR("Expected '%s' statement\n", xstmnt, EXIT_FAILURE);
|
2018-02-13 23:26:57 +00:00
|
|
|
}
|
2017-06-27 00:16:23 +00:00
|
|
|
if (!pmodfr() && !ptype(MTNONE))
|
2017-04-22 18:39:52 +00:00
|
|
|
pstmnt(); //Parse Statement
|
2017-04-03 23:50:25 +00:00
|
|
|
}
|
|
|
|
|
2017-04-22 18:39:52 +00:00
|
|
|
/* Process a directive */
|
|
|
|
void pdrctv()
|
2017-04-03 23:50:25 +00:00
|
|
|
{
|
2017-04-22 18:39:52 +00:00
|
|
|
skpchr(); //skip '#'
|
|
|
|
getwrd(); //read directive into word
|
2017-04-03 23:50:25 +00:00
|
|
|
DEBUG("Processing directive '%s'\n", word);
|
2017-06-27 00:16:23 +00:00
|
|
|
if (wordis("DEFINE"))
|
|
|
|
pdefin(); //Parse Define
|
|
|
|
else if (wordis("INCLUDE"))
|
2017-04-22 18:39:52 +00:00
|
|
|
pincfl(); //Parse Include File
|
2017-06-27 00:16:23 +00:00
|
|
|
else if (wordis("ERROR")) {
|
2017-04-22 18:39:52 +00:00
|
|
|
ERROR("Error \n", 0, EXIT_FAILURE);
|
2017-06-27 00:16:23 +00:00
|
|
|
}
|
|
|
|
else if (wordis("PRAGMA"))
|
|
|
|
pprgma();
|
|
|
|
else
|
|
|
|
ERROR("Illegal directive %s encountered\n", word, EXIT_FAILURE);
|
2017-04-03 23:50:25 +00:00
|
|
|
}
|
|
|
|
|
2018-02-13 23:16:23 +00:00
|
|
|
void prolog()
|
|
|
|
{
|
|
|
|
DEBUG("Writing Assembly Prolog\n", 0);
|
|
|
|
asmlin(CPUOP,CPUARG);
|
|
|
|
setcmt("Program ");
|
|
|
|
addcmt(srcnam);
|
|
|
|
cmtlin();
|
|
|
|
}
|
|
|
|
|
2017-04-22 18:39:52 +00:00
|
|
|
void epilog()
|
2017-04-03 23:50:25 +00:00
|
|
|
{
|
2017-06-27 00:16:23 +00:00
|
|
|
if (!vrwrtn) vartbl(); //Write Variable Table
|
2017-04-03 23:50:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Compile Source Code*/
|
|
|
|
void compile()
|
|
|
|
{
|
2017-04-22 18:39:52 +00:00
|
|
|
DEBUG("Starting Compilation\n", 0);
|
2017-04-03 23:50:25 +00:00
|
|
|
init();
|
2017-04-22 18:39:52 +00:00
|
|
|
prolog();
|
|
|
|
skpchr();
|
|
|
|
DEBUG("Parsing Code\n", 0);
|
2017-04-03 23:50:25 +00:00
|
|
|
while (TRUE)
|
|
|
|
{
|
2017-04-22 18:39:52 +00:00
|
|
|
skpspc();
|
|
|
|
//DEBUG("Checking next character '%c'\n", nxtchr);
|
|
|
|
if (match(EOF))
|
|
|
|
break;
|
2017-05-01 01:17:50 +00:00
|
|
|
else if (match('}'))
|
|
|
|
endblk(TRUE); //End Multi-Line Program Block
|
2017-04-22 18:39:52 +00:00
|
|
|
else if (match('#'))
|
2017-05-01 01:17:50 +00:00
|
|
|
pdrctv(); //Parse Directive
|
2017-04-03 23:50:25 +00:00
|
|
|
else if (match('/'))
|
2017-05-01 01:17:50 +00:00
|
|
|
skpcmt(); //Skip Comment
|
2017-04-22 18:39:52 +00:00
|
|
|
else if (isalph())
|
2017-05-01 01:17:50 +00:00
|
|
|
pword(); //Parse Word
|
2017-04-03 23:50:25 +00:00
|
|
|
else
|
2017-05-01 01:17:50 +00:00
|
|
|
ERROR("Unexpected character '%c'\n", nxtchr, EXIT_FAILURE);
|
2017-04-03 23:50:25 +00:00
|
|
|
}
|
2017-04-22 18:39:52 +00:00
|
|
|
epilog();
|
2017-04-03 23:50:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Display "Usage" text and exit*/
|
|
|
|
void usage()
|
|
|
|
{
|
|
|
|
printf("Usage: c02 sourcefile.c02\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2017-06-27 00:16:23 +00:00
|
|
|
/* Parse Command Line Argument */
|
|
|
|
int popt(int arg, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
char opt; //Option
|
|
|
|
char optarg[32]; //Option Argument
|
|
|
|
opt = argv[arg][1];
|
|
|
|
//if strchr(opt, "i") {
|
|
|
|
//if (strlen(argv[arg] > 2)
|
|
|
|
//}
|
|
|
|
ERROR("Illegal option -%c\n", opt, EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2017-04-03 23:50:25 +00:00
|
|
|
/* Parse Command Line Arguments *
|
2017-04-22 18:39:52 +00:00
|
|
|
* Sets: srcnam - Source File Name (from first arg) *
|
|
|
|
* outnam - Output File Name (from optional second arg) */
|
|
|
|
void pargs(int argc, char *argv[])
|
2017-04-03 23:50:25 +00:00
|
|
|
{
|
2017-06-27 00:16:23 +00:00
|
|
|
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<argc; arg++) {
|
|
|
|
DEBUG("Parsing argument %d\n", arg);
|
|
|
|
if (argv[arg][0] == '-') {
|
|
|
|
arg = popt(arg, argc, argv);
|
|
|
|
}
|
|
|
|
else if (srcnam[0] == 0) {
|
|
|
|
strcpy(srcnam, argv[arg]); //set Source File Name to first arg
|
|
|
|
DEBUG("srcnam set to '%s'\n", srcnam);
|
|
|
|
}
|
|
|
|
else if (outnam[0] == 0) {
|
|
|
|
strcpy(outnam, argv[arg]); //set Out File Name to second arg
|
|
|
|
DEBUG("outnam set to '%s'\n", outnam);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ERROR("Unexpected argument '%s'\n", argv[arg], EXIT_FAILURE);
|
|
|
|
}
|
2017-04-03 23:50:25 +00:00
|
|
|
}
|
2017-03-28 04:09:18 +00:00
|
|
|
|
2017-04-22 18:39:52 +00:00
|
|
|
int main(int argc, char *argv[])
|
2017-03-28 04:09:18 +00:00
|
|
|
{
|
2017-04-22 18:39:52 +00:00
|
|
|
debug = TRUE; //Output Debug Info
|
|
|
|
gencmt = TRUE; //Generate Assembly Language Comments
|
2017-03-28 04:09:18 +00:00
|
|
|
|
|
|
|
printf("C02 Compiler (C) 2012 Curtis F Kaylor\n" );
|
|
|
|
|
2017-04-22 18:39:52 +00:00
|
|
|
pargs(argc, argv); //Parse Command Line Arguments
|
|
|
|
|
|
|
|
opnsrc(); //Open Source File
|
|
|
|
opnout(); //Open Output File
|
|
|
|
opnlog(); //Open Log File
|
2017-03-28 04:09:18 +00:00
|
|
|
|
|
|
|
compile();
|
|
|
|
|
2017-06-27 00:16:23 +00:00
|
|
|
logdef();
|
2017-03-28 04:09:18 +00:00
|
|
|
|
2017-04-22 18:39:52 +00:00
|
|
|
clssrc(); //Close Source File
|
|
|
|
clsout(); //Close Output File
|
|
|
|
clslog(); //Close Log File
|
2017-03-28 04:09:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|