2017-04-22 18:39:52 +00:00
|
|
|
/*************************************
|
|
|
|
* 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 "parse.h"
|
|
|
|
|
|
|
|
char opstr[2]; //Operator as a String
|
|
|
|
|
|
|
|
/* Various tests against nxtchr */
|
2017-05-01 01:17:50 +00:00
|
|
|
int match(char c) {return TF(nxtchr == c);}
|
|
|
|
int inbtwn(char mn, char mx) {return TF(nxtchr >= mn && nxtchr <= mx);}
|
2017-04-22 18:39:52 +00:00
|
|
|
int isprnt() {return isprint(nxtchr);}
|
|
|
|
int isalph() {return isalpha(nxtchr);}
|
|
|
|
int isanum() {return isalnum(nxtchr);}
|
|
|
|
int isdec() {return inbtwn('0', '9');}
|
2017-05-01 01:17:50 +00:00
|
|
|
int ishexd() {return TF(isdec() || inbtwn('A', 'Z'));}
|
2017-04-22 18:39:52 +00:00
|
|
|
int isbin() {return inbtwn('0', '1');}
|
2017-05-01 01:17:50 +00:00
|
|
|
int isnl() {return TF(match('\n') || match('\r'));}
|
2017-04-22 18:39:52 +00:00
|
|
|
int isspc() {return isspace(nxtchr);}
|
2017-05-01 01:17:50 +00:00
|
|
|
int isnpre() {return TF(isdec() || match('$') || match('%'));}
|
2017-04-22 18:39:52 +00:00
|
|
|
int isapos() {return match('\'');}
|
2017-05-01 01:17:50 +00:00
|
|
|
int iscpre() {return TF(isnpre() || isapos());}
|
|
|
|
int isvpre() {return TF(isalph() || iscpre());}
|
|
|
|
int isoper() {return TF(strchr("+-&|^", nxtchr));}
|
|
|
|
int ispopr() {return TF(strchr("+-<>", nxtchr));}
|
2017-04-22 18:39:52 +00:00
|
|
|
|
|
|
|
/* 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()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
DEBUG("Skipping Spaces\n", 0);
|
|
|
|
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 (look(c))
|
|
|
|
return;
|
|
|
|
else {
|
|
|
|
printf("Expected Character '%c', but found '%c'\n", c, nxtchr);
|
|
|
|
exterr(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Advance Input File to next printable character */
|
|
|
|
void skpchr() {char skip = getnxt();}
|
|
|
|
|
|
|
|
/* Advance Input File to end of line */
|
|
|
|
void skpeol() {while (!isnl()) getnxt();}
|
|
|
|
|
|
|
|
/* Advance Source File to end of comment *
|
|
|
|
* Recognizes both C and C++ style comments */
|
|
|
|
void skpcmt()
|
|
|
|
{
|
|
|
|
DEBUG("Skipping Comment\n", 0);
|
|
|
|
skpchr(); //skip initial /
|
|
|
|
if (match('/')) //if C style comment
|
|
|
|
skpeol(); // 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 //if neither
|
|
|
|
expctd("/ or *"); // 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()
|
|
|
|
{
|
|
|
|
int wrdlen = 0;
|
|
|
|
skpspc();
|
|
|
|
if (!isalph()) expctd("Alphabetic Character");
|
|
|
|
while (isanum())
|
|
|
|
{
|
|
|
|
word[wrdlen++] = getnxt();
|
|
|
|
}
|
|
|
|
word[wrdlen] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get Definition Text */
|
|
|
|
void getdef()
|
|
|
|
{
|
|
|
|
int wrdlen = 0;
|
|
|
|
skpspc();
|
|
|
|
while (isprnt()) {
|
|
|
|
word[wrdlen++] = getnxt();
|
|
|
|
}
|
|
|
|
word[wrdlen] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process define directive */
|
|
|
|
void prsdef()
|
|
|
|
{
|
|
|
|
getwrd(); //get defined identifier
|
|
|
|
DEBUG("Defining '%s'\n", word);
|
|
|
|
strncpy(defnam[defcnt], word, VARLEN);
|
|
|
|
getdef();
|
|
|
|
DEBUG("Defined as '%s'\n", word);
|
|
|
|
strncat(deftxt[defcnt], word, DEFLEN);
|
|
|
|
defcnt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for and Expand DEFINE *
|
|
|
|
* Sets: nxtwrd, nxtchr, nxtupr *
|
|
|
|
* if match is found */
|
|
|
|
void expdef()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (!isalph()) return;
|
|
|
|
DEBUG("Checking for definition '%s'\n", word);
|
|
|
|
nxtptr = 0;
|
|
|
|
for (i=0; i<defcnt; i++) {
|
|
|
|
if (strcmp(word, defnam[i]) == 0) {
|
|
|
|
strcpy(nxtwrd, deftxt[i]);
|
|
|
|
nxtchr = nxtwrd[0];
|
|
|
|
nxtupc = toupper(nxtchr);
|
|
|
|
DEBUG("Expanded to '%s'\n", word);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strcpy(nxtwrd, word);
|
|
|
|
}
|
|
|
|
|
|
|
|
char escape(char c)
|
|
|
|
{
|
2017-05-01 01:17:50 +00:00
|
|
|
DEBUG("Escaping character '%c'\n", c);
|
2017-04-22 18:39:52 +00:00
|
|
|
switch (c) {
|
|
|
|
case 'r': return 0x0d;
|
|
|
|
default: return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-01 01:17:50 +00:00
|
|
|
/* Get String */
|
|
|
|
|
|
|
|
void getstr() {
|
|
|
|
char strdel, tmpchr;
|
|
|
|
int wrdlen = 0, escnxt = FALSE;
|
2017-04-22 18:39:52 +00:00
|
|
|
DEBUG("Parsing string\n", 0);
|
2017-05-01 01:17:50 +00:00
|
|
|
strdel = getnxt(); //Get String Delimiter
|
|
|
|
CCMNT(strdel);
|
|
|
|
while(match(strdel) == escnxt) {
|
|
|
|
CCMNT(nxtchr);
|
|
|
|
if (escnxt) {
|
2017-04-22 18:39:52 +00:00
|
|
|
word[wrdlen++] = escape(getnxt());
|
2017-05-01 01:17:50 +00:00
|
|
|
escnxt = FALSE;
|
|
|
|
}
|
2017-04-22 18:39:52 +00:00
|
|
|
else {
|
|
|
|
if (match('\\'))
|
2017-05-01 01:17:50 +00:00
|
|
|
escnxt = TRUE;
|
2017-04-22 18:39:52 +00:00
|
|
|
else
|
|
|
|
word[wrdlen++] = nxtchr;
|
|
|
|
skpchr();
|
|
|
|
}
|
|
|
|
}
|
2017-05-01 01:17:50 +00:00
|
|
|
skpchr(); //Skip End Delimiter
|
|
|
|
CCMNT(strdel);
|
2017-04-22 18:39:52 +00:00
|
|
|
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()
|
|
|
|
{
|
|
|
|
int wrdlen = 0;
|
|
|
|
int digit;
|
|
|
|
int number = 0;
|
|
|
|
if (!match('%'))
|
|
|
|
expctd("hexadecimal 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()
|
|
|
|
{
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
int wrdlen = 0;
|
|
|
|
int digit;
|
|
|
|
int number = 0;
|
|
|
|
DEBUG("Parsing hexadecimal constant\n", 0);
|
|
|
|
if (!match('$'))
|
|
|
|
expctd("hexadecimal number");
|
|
|
|
word[wrdlen++] = getnxt();
|
|
|
|
while (ishexd()) {
|
|
|
|
DEBUG("Found hex digit '%c'\n", nxtchr);
|
|
|
|
word[wrdlen++] = nxtchr;
|
|
|
|
if (isdec())
|
|
|
|
digit = nxtchr - '0';
|
|
|
|
else
|
|
|
|
digit = nxtchr - 'A' + 10;
|
|
|
|
number = number * 16 + digit;
|
|
|
|
skpchr();
|
|
|
|
}
|
|
|
|
word[wrdlen] = 0;
|
|
|
|
return (number);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reads Character constant from input file *
|
|
|
|
* Sets: word - Character constant including *
|
|
|
|
* single quotes *
|
|
|
|
* Returns: ASCII value of constant */
|
|
|
|
int prschr()
|
|
|
|
{
|
|
|
|
int wrdlen = 0;
|
|
|
|
char c;
|
|
|
|
DEBUG("Parsing character constant\n", 0);
|
|
|
|
expect('\'');
|
|
|
|
word[wrdlen++] = '\'';
|
|
|
|
if (match('\\'))
|
|
|
|
word[wrdlen++] = getnxt();
|
|
|
|
c = getnxt();
|
|
|
|
DEBUG("Extracted character %c\n", c);
|
|
|
|
word[wrdlen++] = c;
|
|
|
|
expect('\'');
|
|
|
|
word[wrdlen++] = '\'';
|
|
|
|
word[wrdlen] = 0;
|
|
|
|
return (int)c;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse numeric value *
|
|
|
|
* Args: maxval - maximum allowed value *
|
|
|
|
* Sets: value - parsed number (as string) *
|
|
|
|
* Returns: parsed number */
|
|
|
|
int prsnum(int maxval)
|
|
|
|
{
|
|
|
|
int number;
|
|
|
|
skpspc();
|
|
|
|
if (!iscpre()) expctd("constant value");
|
|
|
|
switch(nxtchr) {
|
|
|
|
case '%':
|
|
|
|
number = prsbin();
|
|
|
|
break;
|
|
|
|
case '$':
|
|
|
|
number = prshex();
|
|
|
|
break;
|
|
|
|
case '\'':
|
|
|
|
number = prschr();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
number = prsdec();
|
|
|
|
}
|
|
|
|
DEBUG("Parsed number '%s'\n", word);
|
|
|
|
DEBUG("with value '%d'\n", number);
|
|
|
|
|
|
|
|
if (number > maxval) {
|
|
|
|
ERROR("Out of bounds constant '%d';\n", number, EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (maxval > 255)
|
|
|
|
sprintf(value, "$%04X", number);
|
|
|
|
else
|
|
|
|
sprintf(value, "$%02X", number);
|
|
|
|
return number;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse numeric constant *
|
|
|
|
* Args: maxval - maximum allowed value *
|
|
|
|
* Sets: value - the constant (as a string) *
|
|
|
|
* valtyp - value type (CONSTANT) */
|
|
|
|
void prscon(int maxval)
|
|
|
|
{
|
2017-05-01 01:17:50 +00:00
|
|
|
cnstnt = prsnum(maxval);
|
2017-04-22 18:39:52 +00:00
|
|
|
valtyp = CONSTANT;
|
|
|
|
if (maxval > 255)
|
2017-05-01 01:17:50 +00:00
|
|
|
sprintf(value, "#$%04X", cnstnt);
|
2017-04-22 18:39:52 +00:00
|
|
|
else
|
2017-05-01 01:17:50 +00:00
|
|
|
sprintf(value, "#$%02X", cnstnt);
|
2017-04-22 18:39:52 +00:00
|
|
|
DEBUG("Generated constant '%s'\n", value);
|
|
|
|
}
|
2017-05-01 01:17:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Get Value Type */
|
|
|
|
int gettyp()
|
2017-04-22 18:39:52 +00:00
|
|
|
{
|
|
|
|
if (match('(')) return FUNCTION;
|
|
|
|
else if (match('[')) return ARRAY;
|
|
|
|
else return VARIABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse next word as variable or function name *
|
|
|
|
* Sets: value - Identifier Name *
|
|
|
|
* valtyp - Identifier Type */
|
|
|
|
void prsvar()
|
|
|
|
{
|
|
|
|
getwrd();
|
2017-05-01 01:17:50 +00:00
|
|
|
valtyp = gettyp();
|
2017-04-22 18:39:52 +00:00
|
|
|
if (valtyp != FUNCTION) chksym(word);
|
|
|
|
strcpy(value, word);
|
|
|
|
DEBUG("Parsed variable '%s'\n", value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse arithmetic or bitwise operator */
|
|
|
|
void prsopr()
|
|
|
|
{
|
|
|
|
if (!isoper)
|
|
|
|
expctd("Arithmetic or bitwise operator");
|
|
|
|
oper = getnxt();
|
|
|
|
DEBUG("Parsed operator '%c'\n", oper);
|
|
|
|
opstr[0] = oper;
|
|
|
|
opstr[1] = 0;
|
|
|
|
ACMNT(opstr);
|
|
|
|
skpspc();
|
|
|
|
}
|
|
|
|
|