1
0
mirror of https://github.com/RevCurtisP/C02.git synced 2024-06-26 05:29:32 +00:00
C02/src/vars.c

491 lines
17 KiB
C
Raw Normal View History

2018-02-13 22:25:57 +00:00
/*************************************
* C02 Variable Management 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"
#include "label.h"
#include "vars.h"
2019-05-13 03:34:47 +00:00
#include "dclrtn.h"
2018-02-13 22:25:57 +00:00
/* Lookup variable name in variable table *
* Sets: varidx = index into vartbl array *
2018-02-13 22:25:57 +00:00
* varcnt if not found *
* Returns: TRUE if found, otherwise FALSE */
2018-03-04 03:32:39 +00:00
int fndvar(char *name) {
DEBUG("vars.fndvar: Looking up variable '%s'\n", name)
for (varidx=0; varidx<varcnt; varidx++) {
if (strcmp(vartbl[varidx].name, name) == 0) {
memcpy(&varble, &vartbl[varidx], sizeof(varble));
2019-05-13 03:34:47 +00:00
vartyp = varble.type;
return TRUE;
}
}
2018-02-13 22:25:57 +00:00
return FALSE;
}
2018-03-08 19:35:00 +00:00
/* Lookup structure name in struct table *
* Sets: stcidx = index into sctnam array *
2018-03-08 19:35:00 +00:00
* sctcnt if not found *
* Returns: TRUE if found, otherwise FALSE */
int fndstc(char *name) {
DEBUG("vars.fndstc: Looking up struct '%s'\n", name)
2018-03-08 19:35:00 +00:00
for (stcidx=0; stcidx<stccnt; stcidx++)
if (strcmp(strcts[stcidx].name, name) == 0) return TRUE;
return FALSE;
}
/* Lookup structure member name in table *
* Sets: stmidx = index into stmnam array *
* stmcnt if not found *
* Returns: TRUE if found, otherwise FALSE */
int fndmbr(int idx, char *name) {
DEBUG("vars.fndmbr: Looking up member '%s'\n", word)
2018-03-08 19:35:00 +00:00
for (mbridx=0; mbridx<mbrcnt; mbridx++) {
if (membrs[mbridx].strcti != idx) continue;
2019-05-13 03:34:47 +00:00
if (strcmp(membrs[mbridx].name, name) == 0) {
memcpy(&membr, &membrs[mbridx], sizeof(membr));
vartyp = membr.vartyp;
return TRUE;
}
2018-03-08 19:35:00 +00:00
}
return FALSE;
}
2018-02-13 22:25:57 +00:00
/* Check for variable *
* Generates error if variable is undefined *
* Args: alwreg - allow register name *
2018-08-03 20:38:20 +00:00
* alwcon - allow const variable *
2018-02-13 22:25:57 +00:00
* name - variable name */
2018-08-03 20:38:20 +00:00
void chksym(int alwreg, int alwcon, char *name) {
2020-02-23 18:19:25 +00:00
DEBUG("vars.chksym: Checking symbol %s\n", name)
2018-02-13 22:25:57 +00:00
if (strlen(name) == 1 && strchr("AXY", name[0])) {
if (alwreg && valtyp != ARRAY) {
valtyp = REGISTER;
return;
}
ERROR("Illegal reference to register %s\n", name, EXIT_FAILURE)
2018-02-13 22:25:57 +00:00
}
if (!fndvar(name))
ERROR("Undeclared variable '%s' encountered\n", name, EXIT_FAILURE)
if (!alwcon && (varble.modifr & MTCONST))
2018-08-03 20:38:20 +00:00
ERROR("Illegal use of const variable '%s'\n", name, EXIT_FAILURE)
2018-02-13 22:25:57 +00:00
}
/* Process struct member *
* Args: offset - Offset into Top Struct
* name - Struct Variable */
void prcmbr(char* name) {
2018-03-08 19:35:00 +00:00
expect('.'); //Check for and Skip Period
if (stcidx < 0) ERROR("Variable %s is Not a Structure\n", value, EXIT_FAILURE)
2018-03-09 01:07:31 +00:00
getwrd(); //Get Member Name
2018-03-08 19:35:00 +00:00
valtyp = gettyp(); //Determine Variable Type
if (valtyp == FUNCTION) ERROR("Illegal Function Reference\n", 0, EXIT_FAILURE)
DEBUG("vars.prcmbr: Checking for member %s", word) DETAIL(" with struct index %d\n", stcidx)
2018-03-08 19:35:00 +00:00
if (!fndmbr(stcidx, word)) ERROR("Struct does Not Contain Member %s\n", word, EXIT_FAILURE)
2019-05-13 03:34:47 +00:00
mbrofs += membr.offset; //Get Member Offet in Struct
}
/* Parse next word as struct member *
* Args: name - Struct Variable *
* Sets: name - Variable + Offset *
* valtyp - Member Type */
void prsmbr(char* name) {
mbrofs = 0;
stcidx = varble.stcidx; //Get Struct Index
prcmbr(name);
2019-05-13 03:34:47 +00:00
while (membr.vartyp == VTSTRUCT && nxtchr == '.') {
stcidx = membr.symidx;
prcmbr(membr.name);
}
sprintf(word, "+$%hhX", mbrofs); //Get Member Offet in Struct
2018-03-09 01:07:31 +00:00
strcat(name, word); //Add Offset to Struct
2018-03-08 19:35:00 +00:00
}
2019-05-19 02:24:30 +00:00
/* Parse word as variable or function name *
2018-02-13 22:25:57 +00:00
* Args: alwreg - Allow Register Names *
* Sets: value - Identifier Name *
* valtyp - Identifier Type */
2019-05-19 02:24:30 +00:00
void prsvrw(int alwreg, int alwcon) {
2018-03-08 19:35:00 +00:00
valtyp = gettyp(); //Determine Variable Type
2018-08-03 20:38:20 +00:00
if (valtyp != FUNCTION) chksym(alwreg, alwcon, word);
2018-02-13 22:25:57 +00:00
strcpy(value, word);
DEBUG("vars.prsvrw: Parsed variable '%s'\n", value)
if (valtyp == STRUCTURE) prsmbr(value);
2018-02-13 22:25:57 +00:00
}
2019-05-19 02:24:30 +00:00
/* Parse next word as variable or function name *
* Args: alwreg - Allow Register Names *
* Sets: value - Identifier Name *
* valtyp - Identifier Type */
void prsvar(int alwreg, int alwcon) {
getwrd(); //Get Variable Name
prsvrw(alwreg, alwcon); //Parse Variable name in word
}
2018-02-13 22:25:57 +00:00
/* Require and Parse Variable Name *
* Parameters: alwary - Allow Array Reference *
* Sets: vrname - operand for LDA/STA/LDY/STY */
2018-03-04 03:32:39 +00:00
void reqvar(int alwary) {
2018-08-03 20:38:20 +00:00
prsvar(FALSE, TRUE);
if (!alwary && valtyp != VARIABLE) expctd("Variable");
2018-02-13 22:25:57 +00:00
}
/* Parse IndexOf Operator *
* Sets: value - variable size (as string) *
* Returns: variable size (as integer */
int pidxof(void) {
expect('?'); //Check for and Skip SizeOf Operator
DEBUG("vars.pidxof: Parsing IndexOf operator\n", 0);
mbridx = -1; //Set Member Index to None
reqvar(FALSE); //Parse Variable Name to get Size Of
if (mbridx > -1) {
2019-05-13 03:34:47 +00:00
sprintf(value, "$%hhX", membr.offset);
return membr.offset;
}
ERROR("IndexOf operator requires a struct member\n", 0, EXIT_FAILURE);
return 0; //Suppress Warning
}
2018-03-09 01:07:31 +00:00
/* Parse SizeOf Operator *
* Sets: value - variable size (as string) *
* Returns: variable size (as integer */
int psizof(void) {
expect('@'); //Check for and Skip SizeOf Operator
DEBUG("vars.psizof: Parsing SizeOf operator\n", 0);
2018-03-09 01:07:31 +00:00
mbridx = -1; //Set Member Index to None
reqvar(FALSE); //Parse Variable Name to get Size Of
if (mbridx > -1) {
2019-05-13 03:34:47 +00:00
sprintf(value, "$%hhX", membr.size);
return membr.size;
2018-03-09 01:07:31 +00:00
}
if (datlen[varidx]) {
sprintf(value, "$%hhX", datlen[varidx]);
return datlen[varidx];
}
if (strlen(varble.size) == 0) {
2018-03-09 01:07:31 +00:00
strcpy(value,"1");
return 1;
}
strcpy(value, varble.size);
2018-03-09 01:07:31 +00:00
if (strcmp(value, "*") == 0) ERROR("Unable to Determine Size of Variable %s\n", vrname, EXIT_FAILURE);
return atoi(value);
}
2018-02-13 22:25:57 +00:00
/* Parse Data Array */
2018-03-04 03:32:39 +00:00
void prsdta(void) {
DEBUG("vars.prsdta: Parsing Array Data\n", 0)
2018-08-04 22:29:04 +00:00
int i;
2018-02-13 22:25:57 +00:00
dtype = DTARRY;
expect('{');
dlen = 0;
do {
2018-08-04 22:29:04 +00:00
skpspc();
if (match('"')) { //Parse and Add String (including terminator)
getstr(); for (i=0; i<=wrdlen; i++) dattmp[dlen++] = word[i];
} else { //Parse and Add Literal
prslit(); dattmp[dlen++] = litval;
}
} while (look(','));
2018-02-13 22:25:57 +00:00
expect('}');
}
/* Parse Data String */
2018-03-04 03:32:39 +00:00
void prsdts(void) {
2018-02-13 22:25:57 +00:00
dtype = DTSTR;
getstr();
strcpy(value, word);
DEBUG("vars.prsdts: Parsed Data String '%s'\n", value)
2018-02-13 22:25:57 +00:00
}
/* Store variable data *
* Uses: value - Data to store *
* Sets: datvar[] - Variable Data *
* datlen[] - Data Length */
2018-03-04 03:32:39 +00:00
void setdat(void) {
2018-02-13 22:25:57 +00:00
int i;
if (dtype == DTBYTE) {
DEBUG("vars.setdat: Setting variable data to '%d'\n", litval)
2018-02-13 22:25:57 +00:00
dlen = 1;
2018-03-07 16:38:22 +00:00
datvar[dsize++] = litval;
2018-02-13 22:25:57 +00:00
}
else if (dtype == DTINT) {
DEBUG("vars.setdat: Setting variable data to '%d'\n", litval)
dlen = 2;
datvar[dsize++] = litval & 0xFF;
datvar[dsize++] = litval >> 8;
}
2018-02-13 22:25:57 +00:00
else if (dtype == DTARRY) {
DEBUG("vars.setdat: Setting variable data to array of length %d\n", dlen)
for (i=0; i<dlen; i++) datvar[dsize++] = dattmp[i];
2018-02-13 22:25:57 +00:00
}
else {
DEBUG("vars.setdat: Setting variable data to '%s'\n", value)
2018-02-13 22:25:57 +00:00
dlen = strlen(value);
for (i=0; i<dlen; i++) datvar[dsize++] = value[i];
2018-02-13 22:25:57 +00:00
}
datlen[varcnt] = dlen;
dattyp[varcnt] = dtype;
DEBUG("vars.setdat: Total data allocated: %d bytes\n", dsize)
2018-02-13 22:25:57 +00:00
}
/* Parse and store variable data */
void prsdat(int m, int t) {
2018-08-03 20:38:20 +00:00
if ((m & MTCONST) == 0) ERROR("Initialization allowed only on variables declared CONST\n", 0, EXIT_FAILURE);
DEBUG("vars.prsdat: Parsing variable data\n", 0)
2018-02-13 22:25:57 +00:00
skpspc();
if (t == VTINT) {dtype = DTINT; litval = prsnum(0xFFFF); } //Parse Integer
else if (islpre()) {dtype = DTBYTE; prslit(); } //Parse Data Literal
else if (match('"')) prsdts(); //Parse Data String
else if (match('{')) prsdta(); //Parse Data Array
2018-03-07 16:38:22 +00:00
else expctd("numeric or string literal");
if (alcvar || dtype <= DTINT) setdat(); //Store Data Value
2018-02-13 22:25:57 +00:00
}
/* Add Variable to Variable table *
2018-03-08 13:23:05 +00:00
* Uses: vrname - variable name *
2018-02-13 22:25:57 +00:00
* value - variable size */
2018-03-04 03:32:39 +00:00
void setvar(int m, int t) {
DEBUG("vars.setvar: Added variable '%s' ", vrname);
strncpy(vartbl[varcnt].name, vrname, VARLEN);
vartbl[varcnt].modifr = m;
vartbl[varcnt].type = t;
strncpy(vartbl[varcnt].size, value, 3);
vartbl[varcnt].stcidx = (t == VTSTRUCT) ? stcidx : -1;
2018-02-13 22:25:57 +00:00
DETAIL("at index %d\n", varcnt);
}
/* Parse and Compile Variable Declaration *
2018-08-03 20:38:20 +00:00
* Uses: word - variable name */
2018-03-04 03:32:39 +00:00
void addvar(int m, int t) {
2018-02-13 22:25:57 +00:00
strcpy(vrname, word); //Save Variable Name
2019-05-19 02:24:30 +00:00
if (fndlab(vrname)) ERROR("Variable %s conflicts with label of same name\n", vrname, EXIT_FAILURE)
2018-03-08 13:23:05 +00:00
if (fndvar(vrname)) ERROR("Duplicate declaration of variable '%s\n", vrname, EXIT_FAILURE)
if (t == VTVOID) ERROR("Illegal Variable Type\n", 0, EXIT_FAILURE)
2018-08-03 20:38:20 +00:00
if (m & MTZP) {
if (alcvar) {
int zpgmax = (t == VTINT) ? zpgend -1 : zpgend;
if (zpaddr > zpgmax) ERROR("Free Zero Page Space Exceeded\n", 0, EXIT_FAILURE)
setlbl(vrname);
sprintf(word, "$%hhX", zpaddr++);
if (t == VTINT) zpaddr++; //int uses two bytes
asmlin(EQUOP, word);
}
strcpy(value, "*"); //Set Variable to Non Allocated
}
2018-08-03 20:38:20 +00:00
else if (m & MTALS) {
setlbl(vrname);
skpspc();
expect('=');
skpspc();
if (isnpre())
prsnum(0xFFFF);
else {
prsvar(FALSE, FALSE);
2019-05-13 03:34:47 +00:00
if (t == VTINT && vartyp != t)
ERROR("ALIAS Type Mismatch\n", 0, EXIT_FAILURE)
if (t > VTINT) ERROR("Type may not be ALIASed\n", 0, EXIT_FAILURE)
}
asmlin(EQUOP, word);
strcpy(value, "*"); //Set Variable to Non Allocated
2018-02-13 22:25:57 +00:00
}
else {
2018-03-08 13:23:05 +00:00
if (t == VTSTRUCT) {
DEBUG("vars.addvar: Setting variable size to %d\n", strct.size)
2018-03-08 14:39:32 +00:00
sprintf(value, "%d", strct.size);
} else if (t == VTINT) {
DEBUG("vars.addvar: Setting variable size to %d\n", 2)
sprintf(value, "%d", 2);
} else if (match('[')) {
t = VTARRAY; //Set Type to Array
2018-03-09 01:07:31 +00:00
CCMNT('[')
2018-02-13 22:25:57 +00:00
skpchr();
if (alcvar) {
DEBUG("vars.addvar: Parsing array size\n", 0)
prslit();
sprintf(value, "%d", litval + 1);
2018-02-13 22:25:57 +00:00
}
expect(']');
}
2018-03-08 13:23:05 +00:00
else value[0] = 0;
2018-02-13 22:25:57 +00:00
if (!alcvar) strcpy(value, "*");
}
if (look('=')) {
prsdat(m, t); //Parse Variable Data
if (dtype > DTINT) t = VTARRAY;
}
setvar(m, t); //Add to Variable Table
2018-02-13 22:25:57 +00:00
varcnt++; //Increment Variable Counter
}
2018-08-03 20:38:20 +00:00
/* Write Variable Definitions *
* Args: m = write CONST vars flag */
void vardef(int m) {
2018-02-13 22:25:57 +00:00
int i, j;
2018-03-16 03:46:52 +00:00
DEBUG("Writing Variable Table\n", 0)
2018-08-04 22:29:04 +00:00
fprintf(logfil, "\n%-8s %s %s %s %s %s\n", "Variable", "Mod", "Type", "Size", "Struct", "Data");
2018-02-13 22:25:57 +00:00
dlen = 0;
for (i=0; i<varcnt; i++) {
memcpy(&varble, &vartbl[i], sizeof(varble));
if ((varble.modifr & MTCONST) != m) { dlen += datlen[i]; continue; }
fprintf(logfil, "%-8s %3d %4d %4s %6d %1d-%d\n", varble.name, varble.modifr, varble.type, varble.size, varble.stcidx, dattyp[i], datlen[i]);
strcpy(lblasm, varble.name);
DEBUG("Set Label to '%s'\n", lblasm)
if (strcmp(varble.size, "*") == 0) continue;
if (varble.modifr & MTALGN) {
DEBUG("Aligning variable '%s'\n", varble.name)
2018-02-13 22:25:57 +00:00
asmlin(ALNOP, "256");
}
if (datlen[i]) {
DEBUG("Building Data for Variable '%s'", varble.name)
DETAIL(" with length %d\n", datlen[i]);
2018-02-13 22:25:57 +00:00
value[0] = 0;
for (j=0; j<datlen[i]; j++) {
if (strlen(value)) strcat(value,",");
2018-02-13 22:25:57 +00:00
sprintf(word, "$%hhX", datvar[dlen++]);
strcat(value, word);
if (strlen(value)>64) {asmlin(BYTEOP,value); value[0]=0;}
}
if (dattyp[i] == DTSTR) {
if (strlen(value)) strcat(value,",");
strcat(value, "$00");
2018-02-13 22:25:57 +00:00
}
DEBUG("Allocating Data for Variable '%s'\n", varble.name)
2018-02-13 22:25:57 +00:00
asmlin(BYTEOP, value);
}
else if (strlen(varble.size) > 0) {
DEBUG("Allocating array '%s'\n", varble.name)
asmlin(STROP, varble.size);
2018-02-13 22:25:57 +00:00
}
else {
DEBUG("Allocating variable '%s'\n", varble.name)
2018-02-13 22:25:57 +00:00
asmlin(BYTEOP, "0");
}
}
vrwrtn = TRUE;
}
2018-03-08 13:23:05 +00:00
2018-08-03 20:38:20 +00:00
/* Write Variable Table */
void wvrtbl(void) {
2018-08-03 20:38:20 +00:00
LCMNT("Variables declared CONST")
vardef(MTCONST); //Write CONST Definitions
//Emit Segment Mnemonic for RAM Variables here
LCMNT("Writable Variables")
if (rambas) {
asmlin(USEGOP,"RAMVARS"); //Create Uninitialized Segment
sprintf(word, "$%X", rambas);
asmlin(ORGOP, word); //Set Origin to RAM Base Address
}
2018-08-03 20:38:20 +00:00
vardef(0); //Write All Other Variables
}
2018-03-08 13:23:05 +00:00
/* Parse and Compile Struct Declaration */
void addstc(void) {
if (!fndstc(word)) ERROR("Undefined Struct '%s\n", word,EXIT_FAILURE)
2018-03-08 14:39:32 +00:00
strct = strcts[stcidx]; //Retrieve Structure
2019-05-13 03:34:47 +00:00
do {
getwrd(); //Get Variable Name
addvar(MTNONE, VTSTRUCT);
} while (look(','));
2018-03-08 13:23:05 +00:00
expect(';');
}
/* Parse Struct Definition *
* Uses: word - Struct Name */
void defstc(void) {
DEBUG("vars.defstc: Parsing struct definition\n", 0)
2018-03-08 13:23:05 +00:00
if (fndstc(word)) ERROR("Duplicate Declaration of Struct '%s\n", word,EXIT_FAILURE)
2019-05-13 03:34:47 +00:00
int type;
int prnidx = stcidx;
2018-03-08 14:39:32 +00:00
strncpy(strct.name, word, STCLEN);
DEBUG("vars.defstc: Set struct name to '%s'\n", word);
2018-03-08 14:39:32 +00:00
strct.size = 0; //Initialize Struct Length
while (look('/')) skpcmt(FALSE); //Skip Comments
2018-03-08 13:23:05 +00:00
do {
2019-05-13 03:34:47 +00:00
getwrd(); //Get Next word
type = ctype(TRUE); //Check if word is a type declaration
switch (type) {
case TSTRUCT:
vartyp = VTSTRUCT;
getwrd(); //Get Structure Name
if (!fndstc(word)) ERROR("Structure '%s' Not Defined\n", word, EXIT_FAILURE)
mbrsiz = strcts[stcidx].size;
break;
case TINT:
vartyp = VTINT;
mbrsiz = 2;
stcidx = -1;
break;
case TCHAR:
vartyp = VTCHAR;
mbrsiz = 1;
stcidx = -1;
break;
2020-02-23 18:19:25 +00:00
case TENUM:
ERROR("ENUM in STRUCT Not Implemented\n", 0, EXIT_FAILURE)
break;
2019-05-13 03:34:47 +00:00
default:
ERROR("Invalid Type %s in Struct Definition\n", word, EXIT_FAILURE)
}
DEBUG("vars.defstc: Parsing members of type %s\n", word)
2019-05-13 03:34:47 +00:00
do {
getwrd(); //Get Member Name
DEBUG("vars.defstc: Parsing member %s\n", word)
2019-05-13 03:34:47 +00:00
if (fndmbr(stccnt, word)) ERROR("Duplicate Declaration of Struct Member '%s\n", word,EXIT_FAILURE)
if (strlen(word) > STMLEN) ERROR("Member Name %s too long\n", word, EXIT_FAILURE)
strcpy(membr.name, word); //Set Member Name
membr.strcti = prnidx; //Set Parent Struct Index
membr.vartyp = vartyp; //Set Member Variable Type
membr.symidx = stcidx; //Set Member Symbol Index
membr.offset = strct.size; //Set Offset into Struct
membr.size = mbrsiz; //Set Member Size
if (membr.vartyp == VTCHAR) {
DEBUG("vars.defstc: Checking member for array definition\n", 0)
2019-05-13 03:34:47 +00:00
if (match('[')) {
CCMNT('[');
skpchr();
membr.vartyp = VTARRAY;
DEBUG("vars.defstc: Parsing member array size\n", 0)
prslit();
membr.size = litval + 1;
2019-05-13 03:34:47 +00:00
expect(']');
}
}
DEBUG("vars.defstc: Set member type to %d", membr.vartyp) DETAIL(" and size to %d\n", membr.size);
DEBUG("vars.defstc: Adding member at index %d\n", mbrcnt);
2019-05-13 03:34:47 +00:00
membrs[mbrcnt++] = membr;
strct.size += membr.size;
} while (look(','));
2018-03-08 13:23:05 +00:00
expect(';');
while (look('/')) skpcmt(FALSE); //Skip Comments
2018-03-08 13:23:05 +00:00
} while (!look('}'));
expect(';');
2018-03-08 14:39:32 +00:00
if (strct.size > 256) ERROR("Structure Size %d Exceeds Limit of 256 bytes.\n", strct.size, EXIT_FAILURE);
DEBUG("vars.defstc: Adding struct with size %d", strct.size) DETAIL("at index %d\n", stccnt);
2018-03-08 14:39:32 +00:00
strcts[stccnt++] = strct;
}
/* Print Struc Tables to Log File */
void logstc(void) {
fprintf(logfil, "\n%-8s %5s\n", "Struct", "Size");
for (stcidx=0; stcidx<stccnt; stcidx++) {
fprintf(logfil, "%-8s %5d\n", strcts[stcidx].name, strcts[stcidx].size);
}
fprintf(logfil, "\n%-8s %-8s", "Struct", "Member");
fprintf(logfil, " %5s %5s %6s %5s\n", "Type", "Index", "Offset", "Size");
2018-03-08 14:39:32 +00:00
for (mbridx=0; mbridx<mbrcnt; mbridx++) {
membr = membrs[mbridx];
fprintf(logfil, "%-8s %-8s", strcts[membr.strcti].name, membr.name);
2019-05-13 03:34:47 +00:00
fprintf(logfil, " %5d %5d %6d %5d\n", membr.vartyp, membr.symidx, membr.offset, membr.size);
2018-03-08 14:39:32 +00:00
}
2018-03-08 13:23:05 +00:00
}