mirror of
https://github.com/RevCurtisP/C02.git
synced 2025-02-17 21:30:34 +00:00
Added a whole bunch of stuff - single file becoming unmanageable
This commit is contained in:
parent
0f32c48e22
commit
1a05d5fc23
702
c02.c
702
c02.c
@ -7,7 +7,6 @@
|
|||||||
* *
|
* *
|
||||||
**************************************************************/
|
**************************************************************/
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -17,36 +16,69 @@
|
|||||||
#define TRUE -1
|
#define TRUE -1
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
|
|
||||||
#define VARLEN 7 /*Maximum Variable Length*/
|
#define VARLEN 7 //Maximum Variable Length
|
||||||
#define MAXVAR 255 /*Maximum Number of Variables*/
|
#define MAXVAR 255 //Maximum Number of Variables
|
||||||
|
#define LABLEN 6 //Maximum Label Length
|
||||||
|
#define LABFMT "L_%04d" //Label Format
|
||||||
|
#define LABSFX ":" //Label Suffix
|
||||||
|
#define MAXLAB 15 //Maximum Number of Labels (Nesting Depth)
|
||||||
|
#define COMPOPS " =< >" //Comparison Operators
|
||||||
|
|
||||||
#define DEBUG(s, val) if (debug) printf(s, val)
|
#define CPU_OP "PROCESSOR" //Target CPU Pseudo-Operator
|
||||||
|
#define CPU_ARG "6502" //Target CPU Operand
|
||||||
|
#define BYTE_OP "DC" //Define Byte Pseudo-Op
|
||||||
|
#define SPC_OP "DS" //Define String Pseudo-Op
|
||||||
|
|
||||||
enum data_type {BYTE, CHAR};
|
#define DEBUG(s, val) if (debug) {print_pos(); printf(s, val);}
|
||||||
enum term_type {NUMBER, VARIABLE};
|
|
||||||
|
enum data_types {BYTE, CHAR};
|
||||||
|
enum term_types {CONSTANT, VARIABLE, ARRAY, FUNCTION};
|
||||||
|
|
||||||
FILE *src_file; /*Source File (Input)*/
|
FILE *src_file; /*Source File (Input)*/
|
||||||
FILE *out_file; /*Assembler File (Output)*/
|
FILE *out_file; /*Assembler File (Output)*/
|
||||||
FILE *log_file; /*Log File (Output) */
|
FILE *log_file; /*Log File (Output) */
|
||||||
|
FILE *inc_file; /*Include File Handle*/
|
||||||
|
|
||||||
char src_name[255]; /*Source File Name*/
|
char src_name[255]; /*Source File Name*/
|
||||||
char out_name[255]; /*Assembler File Name*/
|
char out_name[255]; /*Assembler File Name*/
|
||||||
char log_name[255]; /*Log File Name */
|
char log_name[255]; /*Log File Name */
|
||||||
|
char inc_name[255]; /*Include File Name */
|
||||||
|
|
||||||
int debug; /*Print Debug Info*/
|
int debug; /*Print Debug Info*/
|
||||||
|
|
||||||
int nextChar; /*Next Character of Source File to Process*/
|
int next_char; /*Next Character of Source File to Process*/
|
||||||
int curCol, curLine; /*Position in Source Code*/
|
int curCol, curLine; /*Position in Source Code*/
|
||||||
|
|
||||||
|
char comment[255]; /*Text to be printed on comment lines*/
|
||||||
|
|
||||||
|
char line[255]; /*Entire line parsed from include file*/
|
||||||
char word[255]; /*Word parsed from source file*/
|
char word[255]; /*Word parsed from source file*/
|
||||||
|
char value[255]; /*Term parsed from equation*/
|
||||||
char term[255]; /*Term parsed from equation*/
|
char term[255]; /*Term parsed from equation*/
|
||||||
char operator; /*Arithmetic or Bitwise Operator*/
|
char operator; /*Arithmetic or Bitwise Operator*/
|
||||||
|
int val_type; /*Value Type*/
|
||||||
|
int term_type; /*Term Type*/
|
||||||
|
|
||||||
char var_name[MAXVAR+1][VARLEN+1]; /*Variable Name Table*/
|
char var_name[MAXVAR+1][VARLEN+1]; /*Variable Name Table*/
|
||||||
char var_type[MAXVAR+1]; /*Variable Type Table*/
|
char var_type[MAXVAR+1]; /*Variable Type Table*/
|
||||||
|
char var_size[MAXVAR+1][4]; /*Variable Array Size*/
|
||||||
int var_count; /*Number of Variables Assigned*/
|
int var_count; /*Number of Variables Assigned*/
|
||||||
|
|
||||||
|
char var_assign[VARLEN+1]; /*Assigned Variable Name*/
|
||||||
|
char var_index[VARLEN+1] ; /*Assigned Variable Index*/
|
||||||
|
int var_indexed; /*Assigned Variable is Indexed*/
|
||||||
|
|
||||||
|
char label[LABLEN+1]; /*Most recently generated label*/
|
||||||
|
char lab_name[MAXLAB+1][LABLEN+1]; /*Label Name Table*/
|
||||||
|
int lab_count; /*Number of Labels in stack*/
|
||||||
|
int lab_next; /*Sequence of next label to be generated*/
|
||||||
|
char lab_asm[LABLEN+2]; /*Label to emit on next asm line*/
|
||||||
|
|
||||||
|
/* Print current position in file */
|
||||||
|
void print_pos()
|
||||||
|
{
|
||||||
|
printf("(%d,%d) ", curLine, curCol);
|
||||||
|
}
|
||||||
|
|
||||||
/* Error - print Source File position and exit */
|
/* Error - print Source File position and exit */
|
||||||
void exit_error(int err_no)
|
void exit_error(int err_no)
|
||||||
@ -55,50 +87,53 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
exit(err_no);
|
exit(err_no);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Error - Print perror() and exit */
|
/* Error - Print textual description of system error *
|
||||||
void exit_perror()
|
* and exit with system error code */
|
||||||
|
void exit_sys_error(char *s)
|
||||||
{
|
{
|
||||||
perror("C02");
|
perror(s);
|
||||||
exit_error(errno);
|
exit_error(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Error - print "Expected" message and exit
|
/* Error - print "Expected" error message *
|
||||||
Args: s - Expected string */
|
and exit with general failure code *
|
||||||
void expected(char* s)
|
Args: expected - Description of what was expected */
|
||||||
|
void exit_expected(char *expected)
|
||||||
{
|
{
|
||||||
printf("Expected %s\n", s);
|
printf("Expected %s, but found '%c'\n", expected, next_char);
|
||||||
exit_error(EXIT_FAILURE);
|
exit_error(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get Next Character from Source File *
|
/* Get Next Character from Source File *
|
||||||
* Uses: src_file - Source File Handle *
|
* Uses: src_file - Source File Handle *
|
||||||
* Sets: nextChar - Next Character in Source File */
|
* Sets: next_char - Next Character in Source File */
|
||||||
void getChar()
|
void get_char()
|
||||||
{
|
{
|
||||||
nextChar = fgetc(src_file);
|
next_char = fgetc(src_file);
|
||||||
if (nextChar == '\n') curCol=1; else curCol++;
|
if (next_char == '\n') curCol=1; else curCol++;
|
||||||
if (curCol == 1) curLine++;
|
if (curCol == 1) curLine++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Various tests against nextChar */
|
/* Various tests against next_char */
|
||||||
int isAlpha() {return isalpha(nextChar);}
|
int isAlpha() {return isalpha(next_char);}
|
||||||
int isAlphaNum() {return isalnum(nextChar);}
|
int isAlphaNum() {return isalnum(next_char);}
|
||||||
int isDigit() {return isdigit(nextChar);}
|
int isDigit() {return isdigit(next_char);}
|
||||||
int isNewLine() {return (nextChar == '\n' || nextChar == '\r');}
|
int isNewLine() {return (next_char == '\n' || next_char == '\r');}
|
||||||
int isSpace() {return isspace(nextChar);}
|
int isSpace() {return isspace(next_char);}
|
||||||
int match(int c) {return (nextChar == c);}
|
int match(int c) {return (next_char == c);}
|
||||||
|
|
||||||
/* Advance Source File to next printable character */
|
/* Advance Source File to next printable character */
|
||||||
void skip_spaces() {while (isSpace()) getChar();}
|
void skip_spaces() {while (isSpace()) get_char();}
|
||||||
|
|
||||||
/* Advance Source File to end of line */
|
/* Advance Source File to end of line */
|
||||||
void skip_to_eol() {while (!isNewLine()) getChar();}
|
void skip_to_eol() {while (!isNewLine()) get_char();}
|
||||||
|
|
||||||
/* Initilize Compiler Variables */
|
/* Initilize Compiler Variables */
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
DEBUG(">Initializing Compiler Variables\n",0);
|
DEBUG(">Initializing Compiler Variables\n",0);
|
||||||
var_count = 0;
|
var_count = 0;
|
||||||
|
lab_count = 0;
|
||||||
curCol = 0;
|
curCol = 0;
|
||||||
curLine = 0;
|
curLine = 0;
|
||||||
}
|
}
|
||||||
@ -106,36 +141,58 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
/* Reads next Word in Source File, where *
|
/* Reads next Word in Source File, where *
|
||||||
* a Word is a sequence of AlphaNumeric characters *
|
* a Word is a sequence of AlphaNumeric characters *
|
||||||
* Sets: word - the Word read from the source file */
|
* Sets: word - the Word read from the source file */
|
||||||
get_word()
|
void get_word()
|
||||||
{
|
{
|
||||||
int wordLen = 0;
|
int wordLen = 0;
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
if (!isAlpha()) expected("Alphabetic Character");
|
if (!isAlpha()) exit_expected("Alphabetic Character");
|
||||||
while (isAlphaNum())
|
while (isAlphaNum())
|
||||||
{
|
{
|
||||||
word[wordLen++] = nextChar;
|
word[wordLen++] = next_char;
|
||||||
getChar();
|
get_char();
|
||||||
}
|
}
|
||||||
word[wordLen] = 0;
|
word[wordLen] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reads Decimal number from source file *
|
/* Reads Decimal number from source file *
|
||||||
* a Decimal is a series of digits (0-9) *
|
* a Decimal is a series of digits (0-9) *
|
||||||
|
* Sets: word - number without leading 0's *
|
||||||
* Returns: integer value of number */
|
* Returns: integer value of number */
|
||||||
int get_decimal()
|
int get_decimal()
|
||||||
{
|
{
|
||||||
int digit;
|
int digit;
|
||||||
int number = 0;
|
int number = 0;
|
||||||
|
int wordLen = 0;
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
if (!isDigit()) expected("Digit");
|
if (!isDigit()) exit_expected("Digit");
|
||||||
while (!isDigit())
|
while (isDigit())
|
||||||
{
|
{
|
||||||
digit = nextChar - '0';
|
if (next_char != '0' || number != 0) //skip leading zeros
|
||||||
number = number * 10 + digit;
|
word[wordLen++] = next_char;
|
||||||
|
digit = next_char - '0';
|
||||||
|
number = number *
|
||||||
|
10 + digit;
|
||||||
|
get_char();
|
||||||
}
|
}
|
||||||
|
if (number == 0) word[wordLen++] = '0';
|
||||||
|
word[wordLen] = 0;
|
||||||
return(number);
|
return(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse decimal constant *
|
||||||
|
* Sets: value - the constant (as a string) */
|
||||||
|
void parse_constant() {
|
||||||
|
int constant;
|
||||||
|
val_type = CONSTANT;
|
||||||
|
constant = get_decimal();
|
||||||
|
if (constant > 255) {
|
||||||
|
printf("Out of bounds constant %d;\n", constant);
|
||||||
|
exit_error(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
strcpy(value, word);
|
||||||
|
DEBUG(">Parsed constant '%d'\n", constant);
|
||||||
|
}
|
||||||
|
|
||||||
/* if Word is s then return TRUE else return FALSE*/
|
/* if Word is s then return TRUE else return FALSE*/
|
||||||
int word_is(char *s)
|
int word_is(char *s)
|
||||||
{
|
{
|
||||||
@ -146,83 +203,246 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
void expect_char(char c)
|
void expect_char(char c)
|
||||||
{
|
{
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
if (nextChar == c) { getChar(); return; }
|
if (next_char == c) { get_char(); return; }
|
||||||
printf("Expected Character '%c' ", c);
|
printf("Expected Character '%c', but found '%c'\n", c, next_char);
|
||||||
exit_error(EXIT_FAILURE);
|
exit_error(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add identifier(s) of type t*/
|
/* Check if the next printable character is c *
|
||||||
void add_idents(int t)
|
* and advance past it if it is *
|
||||||
|
* Returns TRUE is character is found, *
|
||||||
|
* otherwise FALSE */
|
||||||
|
int lookfor_char(char c) {
|
||||||
|
int found;
|
||||||
|
skip_spaces();
|
||||||
|
found = match(c);
|
||||||
|
if (found) get_char();
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lookup variable name in variable table *
|
||||||
|
* Returns index into var_name array *
|
||||||
|
* FALSE if variable was not found */
|
||||||
|
int lookup_var(char *name) {
|
||||||
|
int i;
|
||||||
|
DEBUG(">Looking up variable %s\n", word);
|
||||||
|
for (i=0; i<var_count; i++) {
|
||||||
|
if (strcmp(var_name[i], name) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if variable has been defined */
|
||||||
|
int var_defined(char *name) {
|
||||||
|
if (lookup_var(name) == -1)
|
||||||
|
return FALSE;
|
||||||
|
else
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for variable */
|
||||||
|
/* Generates error if variable is undefined */
|
||||||
|
void check_var(char *name) {
|
||||||
|
if (!var_defined(name)) {
|
||||||
|
printf("Undeclared variable '%s' encountered\n", word);
|
||||||
|
exit_error(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_varsize() {
|
||||||
|
DEBUG(">Checking for array definition\n", 0);
|
||||||
|
if (match('[')) {
|
||||||
|
get_char();
|
||||||
|
DEBUG(">Parsing array size\n", 0);
|
||||||
|
parse_constant();
|
||||||
|
expect_char(']');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
value[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add variables(s) of type t*/
|
||||||
|
void add_vars(int t)
|
||||||
{
|
{
|
||||||
DEBUG(">Processing Identifier(s) of type %d\n", t);
|
DEBUG(">Processing variable declarations(s) of type %d\n", t);
|
||||||
|
while(TRUE) {
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
if (isAlpha())
|
if (isAlpha())
|
||||||
{
|
{
|
||||||
get_word();
|
get_word();
|
||||||
DEBUG(">adding Identifier %s\n", word);
|
if (var_defined(word)) {
|
||||||
|
printf("Duplicate declaration of variable '%s\n", word);
|
||||||
|
exit_error(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
DEBUG(">Adding variable %s\n", word);
|
||||||
strncpy(var_name[var_count], word, VARLEN);
|
strncpy(var_name[var_count], word, VARLEN);
|
||||||
var_type[var_count] = t;
|
var_type[var_count] = t;
|
||||||
|
parse_varsize();
|
||||||
|
strncpy(var_size[var_count], value, 3);
|
||||||
var_count++;
|
var_count++;
|
||||||
expect_char(';');
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
printf("Unexpected character '%c' in declaration\n", next_char);
|
||||||
|
exit_error(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (!lookfor_char(','))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expect_char(';');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* output a single line of assembly code */
|
/* output a single line of assembly code */
|
||||||
void asm_line(char *label, char *opcode, char *operand)
|
void asm_line(char *opcode, char *operand)
|
||||||
{
|
{
|
||||||
fprintf(out_file, "%-7s %-3s %s\n", label, opcode, operand);
|
strcat(lab_asm, LABSFX);
|
||||||
|
fprintf(out_file, "%-7s %-3s %s\n", lab_asm, opcode, operand);
|
||||||
|
if (debug) printf(">%-7s %-3s %s\n", lab_asm, opcode, operand);
|
||||||
|
lab_asm[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* output a single comment line */
|
||||||
|
void comment_line()
|
||||||
|
{
|
||||||
|
fprintf(out_file, "; %s\n", comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse variable *
|
||||||
|
* Sets: term - the term (as a string) */
|
||||||
|
void parse_variable() {
|
||||||
|
val_type = VARIABLE;
|
||||||
|
get_word();
|
||||||
|
if (match('(')) {
|
||||||
|
val_type = FUNCTION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
check_var(word);
|
||||||
|
strcpy(value, word);
|
||||||
|
DEBUG(">Parsed variable '%s'\n", term);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse value (constant or simple variable) *
|
||||||
|
* Sets: value - the value (as a string) */
|
||||||
|
void parse_value()
|
||||||
|
{
|
||||||
|
DEBUG("Parsing value\n", 0);
|
||||||
|
if (!isAlphaNum())
|
||||||
|
exit_expected("constant or variable");
|
||||||
|
if (isDigit())
|
||||||
|
parse_constant();
|
||||||
|
else
|
||||||
|
parse_variable();
|
||||||
|
skip_spaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for and Parse array index definition *
|
||||||
|
* Returns: TRUE or FALSE *
|
||||||
|
* Sets: value - array index or *
|
||||||
|
* "" if no index defined */
|
||||||
|
int parse_index()
|
||||||
|
{
|
||||||
|
if (match('[')) {
|
||||||
|
get_char();
|
||||||
|
parse_value();
|
||||||
|
DEBUG("Parsed array index '%s'\n", term);
|
||||||
|
expect_char(']');
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse next term in expression *
|
||||||
|
* Sets: term - the term (as a string) */
|
||||||
void parse_term()
|
void parse_term()
|
||||||
{
|
{
|
||||||
//todo: differentiate between numbers and variables
|
DEBUG(">Parsing term\n", 0);
|
||||||
//check variable name against variable table
|
parse_value();
|
||||||
if (!isAlphaNum())
|
if (val_type == FUNCTION) {
|
||||||
expected("term");
|
printf("Function call only allowed in first term of expression\n");
|
||||||
get_word();
|
exit_error(EXIT_FAILURE);
|
||||||
strcpy(term, word);
|
}
|
||||||
DEBUG(">parsing term '%s'\n", term);
|
strcpy(term, value);
|
||||||
|
term_type = val_type;
|
||||||
|
if (parse_index()) {
|
||||||
|
asm_line("LDX", value);
|
||||||
|
strcat(term, ",X");
|
||||||
|
}
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse function call in first expression */
|
||||||
|
void parse_fnterm()
|
||||||
|
{
|
||||||
|
char fnname[255]; /*Function name*/
|
||||||
|
DEBUG(">Processing expression function call '%s'...\n", term);
|
||||||
|
strcpy(fnname, term);
|
||||||
|
get_char(); //skip open paren
|
||||||
|
skip_spaces();
|
||||||
|
if (isAlphaNum()) {
|
||||||
|
parse_term();
|
||||||
|
asm_line("LDA", term);
|
||||||
|
}
|
||||||
|
expect_char(')');
|
||||||
|
term_type = FUNCTION;
|
||||||
|
asm_line("JSR", fnname);
|
||||||
|
skip_spaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse first term of expession *
|
||||||
|
* First term can include function calls *
|
||||||
|
* Emits code to load term into accumulator */
|
||||||
void first_term()
|
void first_term()
|
||||||
{
|
{
|
||||||
parse_term();
|
parse_value();
|
||||||
DEBUG(">processing term '%s'\n", term);
|
DEBUG(">Processing first term '%s'...\n", value);
|
||||||
asm_line("", "LDA", term);
|
strcpy(term, value);
|
||||||
|
term_type = val_type;
|
||||||
|
if (term_type == FUNCTION) {
|
||||||
|
parse_fnterm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parse_index()) {
|
||||||
|
term_type = ARRAY;
|
||||||
|
asm_line("LDX", value);
|
||||||
|
strcat(term, ",X");
|
||||||
|
}
|
||||||
|
asm_line("LDA", term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
void parse_operator()
|
void parse_operator()
|
||||||
{
|
{
|
||||||
if (strchr("+-&|^", nextChar) == NULL)
|
if (strchr("+-&|^", next_char) == NULL)
|
||||||
expected("operator");
|
exit_expected("operator");
|
||||||
operator = nextChar;
|
operator = next_char;
|
||||||
DEBUG(">parsing operator '%c'\n", operator);
|
DEBUG(">parsing operator '%c'\n", operator);
|
||||||
getChar();
|
get_char();
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
void process_operator()
|
void process_operator()
|
||||||
{
|
{
|
||||||
DEBUG(">processing operator '%c'\n", operator);
|
DEBUG(">Processing operator '%c'\n", operator);
|
||||||
switch(operator)
|
switch(operator)
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
asm_line("","CLC", "");
|
asm_line("CLC", "");
|
||||||
asm_line("","ADC", term);
|
asm_line("ADC", term);
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
asm_line("","SEC", "");
|
asm_line("SEC", "");
|
||||||
asm_line("","SBC", term);
|
asm_line("SBC", term);
|
||||||
break;
|
break;
|
||||||
case '&':
|
case '&':
|
||||||
asm_line("","AND", term);
|
asm_line("AND", term);
|
||||||
break;
|
break;
|
||||||
case '|':
|
case '|':
|
||||||
asm_line("","ORA", term);
|
asm_line("ORA", term);
|
||||||
break;
|
break;
|
||||||
case '^':
|
case '^':
|
||||||
asm_line("","EOR", term);
|
asm_line("EOR", term);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Unrecognized operator '%c'\n", operator);
|
printf("Unrecognized operator '%c'\n", operator);
|
||||||
@ -230,42 +450,247 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_expr()
|
/* Parse and compile expression */
|
||||||
|
void parse_expr(char terminator)
|
||||||
{
|
{
|
||||||
DEBUG(">parsing expression\n", 0);
|
DEBUG(">Parsing expression\n", 0);
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
if (match('-'))
|
if (match('-'))
|
||||||
asm_line("", "LDA", "#0"); //handle unary minus
|
asm_line("LDA", "#0"); //handle unary minus
|
||||||
else
|
else
|
||||||
first_term();
|
first_term();
|
||||||
while (!match(';'))
|
while (!match(terminator))
|
||||||
{
|
{
|
||||||
parse_operator();
|
parse_operator();
|
||||||
parse_term();
|
parse_term();
|
||||||
process_operator();
|
process_operator();
|
||||||
}
|
}
|
||||||
|
get_char(); //skip terminator
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse and compile assignment */
|
/* Parse and compile assignment */
|
||||||
void parse_assignment()
|
void parse_assignment()
|
||||||
{
|
{
|
||||||
DEBUG(">parsing assignment", 0);
|
DEBUG(">Parsing assignment of variable '%s''\n", var_assign);
|
||||||
char var_assign[VARLEN+1];
|
get_char(); //skip equals sign
|
||||||
|
parse_expr(';');
|
||||||
|
if (var_indexed) {
|
||||||
|
asm_line("LDX", var_index);
|
||||||
|
strcat(var_assign,",X");
|
||||||
|
}
|
||||||
|
asm_line("STA", var_assign);
|
||||||
|
DEBUG(">Completed assignment of variable '%s''\n", var_assign);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_postop() {
|
||||||
|
DEBUG(">Processing post operation '%c'\n", operator);
|
||||||
|
switch(operator)
|
||||||
|
{
|
||||||
|
case '+':
|
||||||
|
asm_line("INC", var_assign);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
asm_line("DEC", var_assign);
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
asm_line("ASL", var_assign);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
asm_line("LSR", var_assign);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unrecognized post operator '%c'\n", operator);
|
||||||
|
exit_error(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_postop() {
|
||||||
|
operator = next_char;
|
||||||
|
DEBUG(">Checking for post operation '%c'\n", operator);
|
||||||
|
get_char();
|
||||||
|
if (next_char == operator) {
|
||||||
|
get_char();
|
||||||
|
process_postop();
|
||||||
|
expect_char(';');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
exit_expected("post operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse function call in first expression */
|
||||||
|
void parse_fncall()
|
||||||
|
{
|
||||||
|
char fnname[255]; /*Function name*/
|
||||||
|
DEBUG(">Processing function call '%s'...\n", term);
|
||||||
|
strcpy(fnname, word);
|
||||||
|
get_char(); //skip open paren
|
||||||
|
skip_spaces();
|
||||||
|
if (match(')')) //if no arguments
|
||||||
|
get_char(); // skip close paren
|
||||||
|
else //otherwise
|
||||||
|
parse_expr(')'); //parse expression
|
||||||
|
asm_line("JSR", fnname);
|
||||||
|
expect_char(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
int encode_comparator(char c)
|
||||||
|
{
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case '=': return 1;
|
||||||
|
case '<': return 2;
|
||||||
|
case '>': return 4;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse comparison operator */
|
||||||
|
int parse_comparator()
|
||||||
|
{
|
||||||
|
int comparator, encoded;
|
||||||
|
encoded = encode_comparator(next_char);
|
||||||
|
if (encoded == 0)
|
||||||
|
exit_expected("comparison operator");
|
||||||
|
comparator = encoded;
|
||||||
|
get_char();
|
||||||
|
encoded = encode_comparator(next_char);
|
||||||
|
if (encoded != 0) {
|
||||||
|
comparator = comparator | encoded;
|
||||||
|
get_char();
|
||||||
|
}
|
||||||
|
skip_spaces();
|
||||||
|
DEBUG("Parsed comparison operator %d\n", comparator);
|
||||||
|
return comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_comparator(int comparator)
|
||||||
|
{
|
||||||
|
DEBUG("Processing comparison operator %d\n", comparator);
|
||||||
|
switch(comparator) {
|
||||||
|
case 1: // = or ==
|
||||||
|
asm_line("BNE", label);
|
||||||
|
break;
|
||||||
|
case 2: // <
|
||||||
|
break;
|
||||||
|
case 3: // <= or =<
|
||||||
|
break;
|
||||||
|
case 4: // >
|
||||||
|
break;
|
||||||
|
case 5: // >= or =>
|
||||||
|
break;
|
||||||
|
case 6: // <> or ><
|
||||||
|
asm_line("BEQ", label);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unsupported comparison operator index %d\n", comparator);
|
||||||
|
exit_error(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse and compile condition */
|
||||||
|
void parse_condition(char terminator)
|
||||||
|
{
|
||||||
|
DEBUG("Parsing condition\n", 0);
|
||||||
|
int comparator; /*comparison operator*/
|
||||||
|
first_term();
|
||||||
|
skip_spaces();
|
||||||
|
comparator = parse_comparator();
|
||||||
|
parse_term();
|
||||||
|
asm_line("CMP", term);
|
||||||
|
process_comparator(comparator);
|
||||||
|
expect_char(terminator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate new label */
|
||||||
|
void new_label()
|
||||||
|
{
|
||||||
|
sprintf(label, LABFMT, lab_next++);
|
||||||
|
DEBUG("Generated new label '%s'\n", label);
|
||||||
|
strcpy(lab_name[lab_count++], label);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set label to emit on next line and remove from stack */
|
||||||
|
void label_line()
|
||||||
|
{
|
||||||
|
strcpy(lab_asm, lab_name[--lab_count]);
|
||||||
|
DEBUG("Set label '%s' to emit on next line\n", lab_asm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse and compile if statement */
|
||||||
|
void parse_if() {
|
||||||
|
DEBUG(">Parsing if statement '%c'\n", next_char);
|
||||||
|
expect_char('(');
|
||||||
|
new_label();
|
||||||
|
parse_condition(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse and compile if statement */
|
||||||
|
void parse_goto() {
|
||||||
|
DEBUG(">Parsing goto statement\n", 0);
|
||||||
|
get_word();
|
||||||
|
asm_line("JMP", word);
|
||||||
|
expect_char(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse and compile identifier (variable or function call) */
|
||||||
|
void parse_identifier()
|
||||||
|
{
|
||||||
|
if (match('(')) {
|
||||||
|
parse_fncall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
check_var(word);
|
||||||
strcpy(var_assign, word); //save variable to assign to
|
strcpy(var_assign, word); //save variable to assign to
|
||||||
getChar(); //skip equals sign
|
var_indexed = parse_index();
|
||||||
parse_expr();
|
if (var_indexed) {
|
||||||
asm_line("", "STA", var_assign);
|
strncpy(var_index, value, VARLEN);
|
||||||
|
}
|
||||||
|
if (strchr("+-<>", next_char))
|
||||||
|
parse_postop();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skip_spaces();
|
||||||
|
if (match('='))
|
||||||
|
parse_assignment();
|
||||||
|
else
|
||||||
|
exit_expected("=");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse label in code */
|
||||||
|
void parse_label()
|
||||||
|
{
|
||||||
|
if (strlen(lab_asm) > 0) {
|
||||||
|
printf("Label not allowed at end of block");
|
||||||
|
exit_error(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
get_char(); //skip ':'
|
||||||
|
if (strlen(word) > LABLEN) {
|
||||||
|
printf("Label '%s' exceeds maximum size", word);
|
||||||
|
exit_error(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
strncpy(lab_asm, word, LABLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse and compile program statement */
|
/* parse and compile program statement */
|
||||||
void parse_statement()
|
void parse_statement()
|
||||||
{
|
{
|
||||||
DEBUG(">parsing statement\n", 0);
|
DEBUG(">Parsing statement '%s'\n", word);
|
||||||
skip_spaces();
|
if(match(':')) {
|
||||||
if (match('='))
|
parse_label();
|
||||||
parse_assignment();
|
return;
|
||||||
|
}
|
||||||
|
if (word_is("if")) {
|
||||||
|
parse_if();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (word_is("goto"))
|
||||||
|
parse_goto();
|
||||||
else
|
else
|
||||||
expected("=");
|
parse_identifier();
|
||||||
|
if (lab_count) {
|
||||||
|
label_line();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reads and parses the next Word in Source File */
|
/* Reads and parses the next Word in Source File */
|
||||||
@ -273,45 +698,114 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
{
|
{
|
||||||
get_word();
|
get_word();
|
||||||
DEBUG(">Parsing Word '%s'\n", word);
|
DEBUG(">Parsing Word '%s'\n", word);
|
||||||
if (word_is("byte")) add_idents(BYTE);
|
if (word_is("byte")) add_vars(BYTE);
|
||||||
else if (word_is("char")) add_idents(CHAR);
|
else if (word_is("char")) add_vars(CHAR);
|
||||||
else parse_statement();
|
else parse_statement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reads next include file name from Source File *
|
||||||
|
* Sets: inc_name - the include file name */
|
||||||
|
void parse_inc_name()
|
||||||
|
{
|
||||||
|
int inc_len = 0;
|
||||||
|
expect_char('<');
|
||||||
|
while (!match('>'))
|
||||||
|
{
|
||||||
|
inc_name[inc_len++] = next_char;
|
||||||
|
get_char();
|
||||||
|
}
|
||||||
|
get_char(); //skip '>'
|
||||||
|
inc_name[inc_len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open include file *
|
||||||
|
* Uses: inc_name - Source File Name *
|
||||||
|
* Sets: inc_file - Source File Handle */
|
||||||
|
void open_inc_file()
|
||||||
|
{
|
||||||
|
DEBUG(">Opening include file '%s'\n", inc_name);
|
||||||
|
inc_file = fopen(inc_name, "r");
|
||||||
|
if (inc_file == NULL) exit_sys_error(inc_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close include file */
|
||||||
|
void close_inc_file() { fclose(inc_file); }
|
||||||
|
|
||||||
|
/* Process include file */
|
||||||
|
void include_file()
|
||||||
|
{
|
||||||
|
parse_inc_name();
|
||||||
|
DEBUG(">Processing include file '%s'\n", inc_name);
|
||||||
|
open_inc_file();
|
||||||
|
strcpy(comment, "======== Include File ");
|
||||||
|
strcat(comment, inc_name);
|
||||||
|
strcat(comment, " =======");
|
||||||
|
comment_line();
|
||||||
|
while (fgets(line, sizeof line, inc_file) != NULL) {
|
||||||
|
DEBUG(">Writing line: %s", line);
|
||||||
|
fputs(line, out_file);
|
||||||
|
}
|
||||||
|
strcpy(comment, "==========================================");
|
||||||
|
comment_line();
|
||||||
|
close_inc_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process a directive */
|
||||||
|
void process_directive()
|
||||||
|
{
|
||||||
|
get_char(); //skip '#'
|
||||||
|
get_word(); //read directive into word
|
||||||
|
DEBUG("Processing directive '%s'\n", word);
|
||||||
|
if (word_is("include")) {
|
||||||
|
include_file();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Advance Source File to end of comment *
|
/* Advance Source File to end of comment *
|
||||||
* Recognizes both C and C++ style comments */
|
* Recognizes both C and C++ style comments */
|
||||||
void skip_comment()
|
void skip_comment()
|
||||||
{
|
{
|
||||||
DEBUG(">Skipping Comment\n", 0);
|
DEBUG(">Skipping Comment\n", 0);
|
||||||
getChar();
|
get_char(); //skip initial /
|
||||||
if (match('/')) //if C style comment
|
if (match('/')) //if C style comment
|
||||||
skip_to_eol(); // skip rest of line
|
skip_to_eol(); // skip rest of line
|
||||||
else if (match('*')) //if C++ style comment
|
else if (match('*')) //if C++ style comment
|
||||||
while (TRUE) // skip to "*/"
|
while (TRUE) // skip to */
|
||||||
{
|
{
|
||||||
getChar(); if (!match('*')) continue;
|
get_char();
|
||||||
getChar(); if (!match('/')) continue;
|
if (!match('*')) continue;
|
||||||
getChar();
|
while (match('*')) get_char();
|
||||||
|
if (!match('/')) continue;
|
||||||
|
get_char();
|
||||||
break;
|
break;
|
||||||
//todo: add code to catch unterminated comment
|
//todo: add code to catch unterminated comment
|
||||||
}
|
}
|
||||||
else //if neither
|
else //if neither
|
||||||
expected("/ or *"); // error out
|
exit_expected("/ or *"); // error out
|
||||||
}
|
}
|
||||||
|
|
||||||
void asm_prolog()
|
void asm_prolog()
|
||||||
{
|
{
|
||||||
fprintf(out_file, ";Program %s\n", src_name);
|
asm_line(CPU_OP,CPU_ARG);
|
||||||
fprintf(out_file, " CPU 6502\n");
|
strcpy(comment, "Program ");
|
||||||
|
strcat(comment, src_name);
|
||||||
|
comment_line();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write Variable Table */
|
/* Write Variable Table */
|
||||||
void asm_vartbl()
|
void asm_vartbl()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<var_count; i++)
|
for (i=0; i<var_count; i++) {
|
||||||
{
|
strncpy(lab_asm, var_name[i], LABLEN);
|
||||||
asm_line(var_name[i], "DB", "0");
|
if (strlen(var_size[i]) > 0) {
|
||||||
|
DEBUG("Allocating array %s\n", var_name[i]);
|
||||||
|
asm_line(SPC_OP, var_size[i]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG("Allocating variable %s\n", var_name[i]);
|
||||||
|
asm_line(BYTE_OP, "0");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,18 +820,22 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
DEBUG(">Starting Compilation\n",0);
|
DEBUG(">Starting Compilation\n",0);
|
||||||
init();
|
init();
|
||||||
asm_prolog();
|
asm_prolog();
|
||||||
getChar();
|
get_char();
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
|
skip_spaces();
|
||||||
if (match(EOF)) break;
|
if (match(EOF)) break;
|
||||||
if (match('/'))
|
DEBUG("Checking next character '%c'\n", next_char);
|
||||||
|
if (match('#'))
|
||||||
|
process_directive();
|
||||||
|
else if (match('/'))
|
||||||
skip_comment();
|
skip_comment();
|
||||||
else if (isAlpha())
|
else if (isAlpha())
|
||||||
parse_word();
|
parse_word();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(log_file, "%c", nextChar);
|
printf("Unexpected character '%c'\n", next_char);
|
||||||
getChar();
|
exit_error(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
asm_epilog();
|
asm_epilog();
|
||||||
@ -375,7 +873,7 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
strcat(src_name, ".c02"); // add ".c02"
|
strcat(src_name, ".c02"); // add ".c02"
|
||||||
DEBUG(">opening Source File '%s'\n", src_name);
|
DEBUG(">opening Source File '%s'\n", src_name);
|
||||||
src_file = fopen(src_name, "r"); //open file
|
src_file = fopen(src_name, "r"); //open file
|
||||||
if (src_file == NULL) exit_perror();
|
if (src_file == NULL) exit_sys_error(src_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open Output File *
|
/* Open Output File *
|
||||||
@ -395,7 +893,7 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
strcat(out_name, ".asm"); // add ".asm"
|
strcat(out_name, ".asm"); // add ".asm"
|
||||||
DEBUG(">opening Output File '%s'\n", out_name);
|
DEBUG(">opening Output File '%s'\n", out_name);
|
||||||
out_file = fopen(out_name, "w"); //open file
|
out_file = fopen(out_name, "w"); //open file
|
||||||
if (out_file == NULL) exit_perror();
|
if (out_file == NULL) exit_sys_error(out_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open Log File *
|
/* Open Log File *
|
||||||
@ -409,7 +907,7 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
strcat(log_name, ".log"); //add extension ".asm"
|
strcat(log_name, ".log"); //add extension ".asm"
|
||||||
DEBUG(">Opening Log File '%s'\n", log_name);
|
DEBUG(">Opening Log File '%s'\n", log_name);
|
||||||
log_file = fopen(log_name, "w");
|
log_file = fopen(log_name, "w");
|
||||||
if (log_file == NULL) exit_perror();
|
if (log_file == NULL) exit_sys_error(log_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print Variable Table to Log File */
|
/* Print Variable Table to Log File */
|
||||||
@ -432,7 +930,6 @@ int var_count; /*Number of Variables Assigned*/
|
|||||||
/* Close Log File */
|
/* Close Log File */
|
||||||
void close_log_file() { fclose(log_file); }
|
void close_log_file() { fclose(log_file); }
|
||||||
|
|
||||||
|
|
||||||
int main (int argc, char *argv[])
|
int main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
debug = TRUE;
|
debug = TRUE;
|
||||||
@ -450,6 +947,7 @@ int main (int argc, char *argv[])
|
|||||||
|
|
||||||
close_src_file();
|
close_src_file();
|
||||||
close_out_file();
|
close_out_file();
|
||||||
|
close_log_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user