1
0
mirror of https://github.com/RevCurtisP/C02.git synced 2024-06-08 06:29:32 +00:00
C02/stmnt.c
2018-03-01 23:46:23 -05:00

536 lines
14 KiB
C

/************************************
* C02 Statement Compiling Routines *
************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#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("Begining 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(tmplbl); //Create End of Expression Label
asmlin("JMP", tmplbl); //Jump over "if FALSE" expression
setlbl(cndlbl); //Emit "if FALSE" label
prsxpr(trmntr); //Parse "if FALSE" expression
setlbl(tmplbl); //Emit End of Expression Label
}
/* Process Array Index */
void prcidx(int idxtyp, char *name, char *index)
{
if (strlen(index)) {
if (idxtyp == CONSTANT) {
strcat(name, "+");
strcat(name, index);
}
else {
asmlin("LDX", index);
strcat(name,",X");
}
}
}
/* Process Assignment */
void prcasn(char trmntr)
{
expect('=');
if (look('('))
prssif(trmntr); //Parse Shortcut If
else
prsxpr(trmntr); //Parse Expression
DEBUG("Processing X assignment variable '%s'\n", xsnvar);
if (xsnvar[0]) {
asmlin("STX", xsnvar);
xsnvar[0] = 0;
}
DEBUG("Processing Y assignment variable '%s'\n", ysnvar);
if (ysnvar[0]) {
if (strlen(ysnidx))
prcidx(ysnivt, ysnvar, ysnidx);
asmlin("STY", ysnvar);
ysnvar[0] = 0;
}
DEBUG("Processing assignment variable '%s'\n", asnvar);
if (strcmp(asnvar, "X")==0)
asmlin("TAX", "");
else if (strcmp(asnvar, "Y")==0)
asmlin("TAY", "");
else if ((strcmp(asnvar, "A")!=0))
{
if (strlen(asnidx))
prcidx(asnivt, asnvar, asnidx);
asmlin("STA", asnvar);
}
}
/* Parse and Return Array Index and Type */
int getidx(char* idx)
{
prsidx(); //Parse Array Index
if (valtyp == CONSTANT)
strncpy(idx, word, VARLEN);
else
strncpy(idx, value, VARLEN);
DEBUG("Set assigned index to %s\n", asnidx);
return valtyp;
}
/* Process Assignment Variable(s) */
void prcvar(char trmntr)
{
chksym(TRUE, word);
strcpy(asnvar, word); //save variable to assign to
asntyp = valtyp; //Set Assigned Varable 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
DEBUG("Set STA index to %s\n", asnidx);
DEBUG("Set STA index type to %d\n", asnivt);
}
else
asnidx[0] = 0;
if (ispopr()) {
if (prspst(trmntr, asnvar, asnidx)) //Parse Post Operator
expctd("post operator");
/*refactor - put a return here and remove followig else*/
}
else {
if (look(',')) {
if (asntyp == REGISTER) {
ERROR("Register %s not allowed in plural assignment\n", asnvar, EXIT_FAILURE);
}
prsvar(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
DEBUG("Set STY index to %s\n", ysnidx);
DEBUG("Set STY index type to %d\n", ysnivt);
}
else
ysnidx[0] = 0;
if (look(',')) {
prsvar(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);
}
}
}
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()
{
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
prcvar(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()
{
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
//newlbl(loplbl); //Create Do Loop Label
//setlbl(loplbl); //Set Label to Emit on Next Line
pshlbl(LTDO, loplbl); //Push onto Stack
bgnblk(FALSE); //Check For and Begin Block
}
/* parse and compile 'while' after 'do' statement */
void pdowhl() {
DEBUG("Parsing WHILE after DO '%c'\n", nxtchr);
getwrd(); //Check for While
if (!wordis("WHILE"))
expctd("while statement");
expect('(');
//poplbl(); //Pop While Conditional Label
strcpy(cndlbl, loplbl); //Set Conditional Label to Loop Label
prscnd(')', TRUE); //Parse Conditional Expession
//asmlin("JMP", loplbl); //Emit Jump to Beginning of Loop
//setlbl(cndlbl); //and Set Label to Emit on Next Line
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() {
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() {
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() {
DEBUG("Parsing ELSE statement\n", 0);
strcpy(lbltmp, lblasm); //Save Line Label
lblasm[0] = 0; //and Clear It
newlbl(skplbl); //Create Skip Label
pshlbl(LTIF, 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() {
DEBUG("Parsing GOTO statement\n", 0);
getwrd();
expect(';');
asmlin("JMP", word);
}
/* parse and compile inline statement */
void pinlne()
{
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 {
prscon(0xFF);
sprintf(word, "$%hhX", cnstnt); //not needed?
asmlin(BYTEOP, value);
}
} while (look(','));
expect(';');
}
/* parse and compile pop statement */
void ppop()
{
DEBUG("Parsing POP statement\n", 0);
do {
asmlin("PLA", ""); //Pop Value off Stack
if (!look('*')) {
reqvar(TRUE);
strcpy(term, value);
chkidx();
asmlin("STA", term);
}
} while (look(','));
expect(';');
}
/* parse and compile push statement */
void ppush()
{
DEBUG("Parsing PUSH statement\n", 0);
do {
if (!chkadr(1)) {
prsxpr(0); //Parse Expression
asmlin("PHA",""); //Push Result on Stack
}
} while (look(','));
expect(';');
}
/* parse and compile return statement */
void pretrn() {
DEBUG("Parsing RETURN statement\n", 0);
if (!look(';'))
prsxpr(';');
asmlin("RTS", "");
lsrtrn = TRUE; //Set RETURN flag
}
/* parse and compile select statement */
void pslct() {
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() {
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() {
if (!fcase)
ecase("CASE"); //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(); //Parse CASE argument
if (!fcase || valtyp != CONSTANT || cnstnt)
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() {
expect(':');
ecase(); //Process end of case block
}
/* parse and compile while statement */
void pwhile() {
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
//newlbl(loplbl); //create Loop Label
//setlbl(loplbl); //Set to Emit on Next Line
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() {
ERROR("Unimplemented statement '%s' encountered\n", word, EXIT_FAILURE);
}
/* Parse Function Call as Statement */
void prsfns()
{
strcpy(term, word); //Copy Function Name
prsfnc(';'); //Parse Function Call
return;
}
/* parse and compile identifier (variable or function call) */
void prssym()
{
DEBUG("Parsing Identifier %s\n", word);
valtyp = gettyp();
if (valtyp == FUNCTION)
prsfns(); //Parse Statement Function Call
else
prcvar(';'); //Parse Assignment
}
/* parse and compile program statement */
void pstmnt()
{
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(':')) {
prslbl(); //Parse Label
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
}
}