1
0
mirror of https://github.com/RevCurtisP/C02.git synced 2024-11-22 16:34:15 +00:00
C02/src/parse.c
2018-07-30 13:03:54 -04:00

405 lines
12 KiB
C

/*************************************
* C02 Input File Parsing Routines *
*************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include "common.h"
#include "files.h"
#include "asm.h"
#include "parse.h"
/* Various tests against nxtchr */
int match(char c) {return TF(nxtchr == c);}
int inbtwn(char mn, char mx) {return TF(nxtupc >= mn && nxtupc <= mx);}
int isalph(void) {return isalpha(nxtchr);}
int isanum(void) {return isalnum(nxtchr);}
int isapos(void) {return match('\'');}
int isbin(void) {return inbtwn('0', '1');}
int isbpre(void) {return TF(isnpre() || isapos());}
int isdec(void) {return inbtwn('0', '9');}
int iscpre(void) {return match('#');}
int ishexd(void) {return TF(isdec() || inbtwn('A', 'Z'));}
int islpre(void) {return TF(isbpre() || iscpre() || isszop() || isxfop());}
int isnl(void) {return TF(match('\n') || match('\r'));}
int isnpre(void) {return TF(isdec() || match('$') || match('%'));}
int isoper(void) {return TF(strchr("+-&|^", nxtchr));}
int ispopr(void) {return TF(strchr("+-<>", nxtchr));}
int isprnt(void) {return isprint(nxtchr);}
int isspc(void) {return isspace(nxtchr);}
int isszop(void) {return match('@');}
int isvpre(void) {return TF(isalph() || islpre());}
int isxfop(void) {return match('?');}
int isxpre(void) {return TF(isvpre() || match('-'));}
/* Process ASCII Character */
char prcchr(char c) {
if (invasc) c = isalpha(c) ? (islower(c)?toupper(c):tolower(c)) : c;
if (mskasc) c = c | 0x80;
if (invasc || mskasc) DEBUG("Character converted to '%c'\n", c)
return c;
}
/* if Word is s then return TRUE else return FALSE*/
int wordis(char *s) {
return strcmp(word, s) == 0;
}
/* Get Next Character from Current Input File *
* Uses: inpfil - Input File Handle *
* Sets: nxtchr - Next Character in Source File */
char getnxt(void) {
int wascr = match('\r');
char c = nxtchr;
//if (nxtwrd[nxtptr]) //If nxtwrd is set
// nxtchr = nxtwrd[nxtptr++]; // Pop First Character from nxtwrd
//else
nxtchr = fgetc(inpfil);
nxtupc = toupper(nxtchr);
if (wascr && match('\n')) return c; //Skip NL after CR
if (isnl()) curcol=1; else curcol++;
if (curcol == 1) curlin++;
return c;
}
/* Advance Input File to next printable character */
void skpspc(void) {
//DEBUG("Skipping Spaces\n", 0)
if (isspc()) CCMNT(' '); //Add only the first space to comments
while (isspc()) getnxt();
}
/* Check if the next printable character is c *
* and advance past it if it is *
* Returns TRUE is character is found, *
* otherwise FALSE */
int look(char c) {
int found;
skpspc();
found = match(c);
if (found) {
skpchr();
CCMNT(c);
}
return found;
}
/* if next printable character is c then skip, else generate error */
void expect(char c) {
if (c == 0) return;
if (look(c)) return;
else ERROR("Expected Character '%c'\n", c, EXIT_FAILURE)
}
/* Advance Input File to next printable character */
void skpchr(void) {
getnxt();
}
/* Advance Input File to end of line */
void skpeol(void) {while (!isnl()) getnxt();}
/* Advance Source File to end of comment *
* Recognizes both C and C++ style comments */
void skpcmt(void)
{
DEBUG("Skipping Comment\n", 0)
skpchr(); //skip initial /
if (match('/')) skpeol(); //if C style comment skip rest of line
else if (match('*')) //if C++ style comment
while (TRUE) // skip to */
{
skpchr();
if (!match('*')) continue;
while (match('*')) skpchr();
if (!match('/')) continue;
skpchr();
break;
//todo: add code to catch unterminated comment
}
else expctd("/ or *"); //if neither error out
}
/* Reads next Word in current Input File, where *
* a Word is a sequence of AlphaNumeric characters *
* Sets: word - the Word read from the source file */
void getwrd(void) {
int wrdlen = 0;
skpspc();
if (!isalph()) expctd("Alphabetic Character");
while (isanum()) word[wrdlen++] = toupper(getnxt());
word[wrdlen] = 0;
ACMNT(word);
}
/* Escape Character */
char escape(char c) {
DEBUG("Escaping character '%c'\n", c)
switch (c) {
case 'a': return 0x07; //Alert (Beep/Bell)
case 'b': return 0x08; //Backspace
case 'e': return 0x08; //Escape
case 'f': return 0x0C; //Form Feed
case 'n': return 0x0A; //Newline (Line Feed)
case 'r': return 0x0D; //Return (Carriage Return)
case 't': return 0x09; //Tab (Horizontal)
case 'v': return 0x0B; //Vertical Tab
default: return c;
}
}
/* Get String */
void getstr(void) {
char strdel;
int wrdlen = 0, escnxt = FALSE;
DEBUG("Parsing string\n", 0)
strdel = getnxt(); //Get String Delimiter
CCMNT(strdel);
while(!match(strdel) || escnxt) {
CCMNT(nxtchr);
if (escnxt) {
word[wrdlen++] = escape(getnxt());
escnxt = FALSE;
}
else {
if (match('\\')) escnxt = TRUE;
else word[wrdlen++] = prcchr(nxtchr);
skpchr();
}
}
skpchr(); //Skip End Delimiter
CCMNT(strdel);
word[wrdlen++] = 0;
}
/* Read Binary number from input file *
* a Binary is a series of binary digits (0 or 1) *
* prefixed with '%' *
* Sets: word - binary number including leading '%' *
* Returns: integer value of number */
int prsbin(void) {
int wrdlen = 0;
int digit;
int number = 0;
if (!match('%')) expctd("binary number");
word[wrdlen++] = nxtchr;
getnxt();
while (isbin()) {
word[wrdlen++] = nxtchr;
digit = nxtchr - '0';
number = number * 2 + digit;
skpchr();
}
word[wrdlen] = 0;
return (number);
}
/* Read Decimal number from input file *
* a Decimal is a series of digits (0-9) *
* Sets: word - number without leading 0's *
* Returns: integer value of number */
int prsdec(void) {
int wrdlen = 0;
int digit;
int number = 0;
if (!isdec()) expctd("Digit");
while (isdec())
{
if (!match('0') || number != 0) //skip leading zeros
word[wrdlen++] = nxtchr;
digit = getnxt() - '0';
number = number * 10 + digit;
}
if (number == 0) word[wrdlen++] = '0';
word[wrdlen] = 0;
return(number);
}
/* Reads Hexadecimal number from input file *
* Sets: word - Hex number including leading '$' *
* Returns: integer value of number */
int prshex(void) {
int wrdlen = 0;
int digit;
int number = 0;
DEBUG("Parsing hexadecimal literal '", 0)
if (!match('$')) expctd("hexadecimal number");
word[wrdlen++] = getnxt();
while (ishexd()) {
DETAIL("%c", nxtchr);
word[wrdlen++] = nxtchr;
if (isdec()) digit = nxtchr - '0';
else digit = nxtupc - 'A' + 10;
number = number * 16 + digit;
skpchr();
}
DETAIL("'\n", 0);
word[wrdlen] = 0;
return (number);
}
/* Read Character Literal from Input File *
* Sets: word - Character literal including *
* single quotes *
* Returns: ASCII value of literal */
int prschr(void) {
int wrdlen = 0;
char c;
DEBUG("Parsing character literal\n", 0)
word[wrdlen++] = getnxt(); //Initial Single Quote
if (match('\\')) word[wrdlen++] = getnxt();
c = getnxt();
DEBUG("Extracted character %c\n", c)
word[wrdlen++] = prcchr(c);
if (!match('\'')) expctd("character delimiter");
word[wrdlen++] = getnxt();
word[wrdlen] = 0;
return (int)c;
}
/* Parse numeric value *
* Args: maxval - maximum allowed value *
* Sets: value - parsed number (as string) *
* word - parsed text of value *
* Returns: parsed number */
int prsnum(int maxval) {
int number;
skpspc();
if (!isbpre()) expctd("literal value");
switch(nxtchr) {
case '%': number = prsbin(); break;
case '$': number = prshex(); break;
case '\'': number = prschr(); break;
default: number = prsdec();
}
DEBUG("Parsed number %s ", word)
DETAIL("with value %d\n", number)
if (number > maxval) ERROR("Out of bounds literal '%d';\n", number, EXIT_FAILURE)
if (maxval > 255) sprintf(value, "$%04X", number);
else sprintf(value, "$%02X", number);
ACMNT(word)
return number;
}
/* Parse Nuneric Byte Value */
int prsbyt(void) {return prsnum(0xFF);}
/* Find Defined Constant */
void fnddef(char *name) {
DEBUG("Looking up defined constant '%s'\n", word)
for (conidx=0; conidx<concnt; conidx++)
if (strcmp(connam[conidx], name) == 0) return;
conidx = -1;
}
/* Parse Constant */
int prscon(void) {
expect('#');
getwrd(); //Get Constant Name
fnddef(word);
if (conidx < 0) ERROR("Undefined constant '%s'\n", word, EXIT_FAILURE)
strcpy(value, word);
return conval[conidx];
}
/* Parse numeric literal *
* Args: maxval - maximum allowed value *
* Sets: litval - literal (as an integer) *
* value - literal (as asm arg) *
* valtyp - value type (LITERAL) *
* word - literal (as a string) *
* Note: Value is converted to hexadecimal *
* because DASM uses the format 'c for *
* character arguments instead of 'c' */
void prslit(void) {
skpspc();
if (iscpre()) litval = prscon(); //Parse Constant
else if (isszop()) litval = psizof(); //Parse SizeOf Operator
else if (isxfop()) litval = pidxof(); //Parse IndexOf Operator
else litval = prsbyt(); //Parse Byte Value
valtyp = LITERAL;
strcpy(word, value); //Patch for DASM
strcpy(value, "#");
strcat(value, word);
DEBUG("Generated literal '%s'\n", value)
}
/* Get Value Type */
int gettyp(void) {
if (match('(')) return FUNCTION;
else if (match('[')) return ARRAY;
else return VARIABLE;
}
/* Parse arithmetic or bitwise operator */
void prsopr(void) {
if (!isoper()) expctd("Arithmetic or bitwise operator");
oper = getnxt();
DEBUG("Parsed operator '%c'\n", oper)
CCMNT(oper);
skpspc();
}
/* Generate Post-Operation Error */
void poperr(char* name) {
fprintf(stderr, "Illegal post-operation %c%c on register %s\n", oper, oper, name);
exterr(EXIT_FAILURE);
}
/* Process Post Operator */
void prcpst(char* name, char *index) {
DEBUG("Processing post operation '%c'\n", oper)
if (strlen(index)) {
asmlin("LDX", index);
strcat(name,",X");
}
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 asmlin("INC", name);
break;
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 asmlin("DEC", name);
break;
case '<':
if (strcmp(name, "X")==0) poperr(name); //Index Register Shift not Supported
else if (strcmp(name, "Y")==0) poperr(name); //Index Register Shift not Supported
else if (strcmp(name, "A")==0) asmlin("ASL", "");
else asmlin("ASL", name);
break;
case '>':
if (strcmp(name, "X")==0) poperr(name); //Index Register Shift not Supported
else if (strcmp(name, "Y")==0) poperr(name); //Index Register Shift not Supported
else if (strcmp(name, "A")==0) asmlin("LSR", "");
else asmlin("LSR", name);
break;
default:
ERROR("Unrecognized post operator '%c'\n", oper, EXIT_FAILURE)
}
}
/* Parse Post Operator */
int prspst(char trmntr, char* name, char* index) {
oper = getnxt();
CCMNT(oper);
DEBUG("Checking for post operation '%c'\n", oper)
if (nxtchr == oper) {
skpchr();
CCMNT(oper);
expect(trmntr);
prcpst(name, index); //Process Post-Op
return 0;
}
DEBUG("Not a post operation\n", 0)
return oper;
}