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 <stdlib.h>
|
||||
#include <ctype.h>
|
||||
@ -17,36 +16,69 @@
|
||||
#define TRUE -1
|
||||
#define FALSE 0
|
||||
|
||||
#define VARLEN 7 /*Maximum Variable Length*/
|
||||
#define MAXVAR 255 /*Maximum Number of Variables*/
|
||||
#define VARLEN 7 //Maximum Variable Length
|
||||
#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};
|
||||
enum term_type {NUMBER, VARIABLE};
|
||||
#define DEBUG(s, val) if (debug) {print_pos(); printf(s, val);}
|
||||
|
||||
enum data_types {BYTE, CHAR};
|
||||
enum term_types {CONSTANT, VARIABLE, ARRAY, FUNCTION};
|
||||
|
||||
FILE *src_file; /*Source File (Input)*/
|
||||
FILE *out_file; /*Assembler File (Output)*/
|
||||
FILE *log_file; /*Log File (Output) */
|
||||
FILE *inc_file; /*Include File Handle*/
|
||||
|
||||
char src_name[255]; /*Source File Name*/
|
||||
char out_name[255]; /*Assembler File Name*/
|
||||
char log_name[255]; /*Log File Name */
|
||||
char inc_name[255]; /*Include File Name */
|
||||
|
||||
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*/
|
||||
|
||||
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 value[255]; /*Term parsed from equation*/
|
||||
char term[255]; /*Term parsed from equation*/
|
||||
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_type[MAXVAR+1]; /*Variable Type Table*/
|
||||
char var_size[MAXVAR+1][4]; /*Variable Array Size*/
|
||||
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 */
|
||||
void exit_error(int err_no)
|
||||
@ -55,50 +87,53 @@ int var_count; /*Number of Variables Assigned*/
|
||||
exit(err_no);
|
||||
}
|
||||
|
||||
/* Error - Print perror() and exit */
|
||||
void exit_perror()
|
||||
/* Error - Print textual description of system error *
|
||||
* and exit with system error code */
|
||||
void exit_sys_error(char *s)
|
||||
{
|
||||
perror("C02");
|
||||
perror(s);
|
||||
exit_error(errno);
|
||||
}
|
||||
|
||||
/* Error - print "Expected" message and exit
|
||||
Args: s - Expected string */
|
||||
void expected(char* s)
|
||||
/* Error - print "Expected" error message *
|
||||
and exit with general failure code *
|
||||
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);
|
||||
}
|
||||
|
||||
/* Get Next Character from Source File *
|
||||
* Uses: src_file - Source File Handle *
|
||||
* Sets: nextChar - Next Character in Source File */
|
||||
void getChar()
|
||||
* Sets: next_char - Next Character in Source File */
|
||||
void get_char()
|
||||
{
|
||||
nextChar = fgetc(src_file);
|
||||
if (nextChar == '\n') curCol=1; else curCol++;
|
||||
next_char = fgetc(src_file);
|
||||
if (next_char == '\n') curCol=1; else curCol++;
|
||||
if (curCol == 1) curLine++;
|
||||
}
|
||||
|
||||
/* Various tests against nextChar */
|
||||
int isAlpha() {return isalpha(nextChar);}
|
||||
int isAlphaNum() {return isalnum(nextChar);}
|
||||
int isDigit() {return isdigit(nextChar);}
|
||||
int isNewLine() {return (nextChar == '\n' || nextChar == '\r');}
|
||||
int isSpace() {return isspace(nextChar);}
|
||||
int match(int c) {return (nextChar == c);}
|
||||
/* Various tests against next_char */
|
||||
int isAlpha() {return isalpha(next_char);}
|
||||
int isAlphaNum() {return isalnum(next_char);}
|
||||
int isDigit() {return isdigit(next_char);}
|
||||
int isNewLine() {return (next_char == '\n' || next_char == '\r');}
|
||||
int isSpace() {return isspace(next_char);}
|
||||
int match(int c) {return (next_char == c);}
|
||||
|
||||
/* 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 */
|
||||
void skip_to_eol() {while (!isNewLine()) getChar();}
|
||||
void skip_to_eol() {while (!isNewLine()) get_char();}
|
||||
|
||||
/* Initilize Compiler Variables */
|
||||
void init()
|
||||
{
|
||||
DEBUG(">Initializing Compiler Variables\n",0);
|
||||
var_count = 0;
|
||||
lab_count = 0;
|
||||
curCol = 0;
|
||||
curLine = 0;
|
||||
}
|
||||
@ -106,36 +141,58 @@ int var_count; /*Number of Variables Assigned*/
|
||||
/* Reads next Word in Source File, where *
|
||||
* a Word is a sequence of AlphaNumeric characters *
|
||||
* Sets: word - the Word read from the source file */
|
||||
get_word()
|
||||
void get_word()
|
||||
{
|
||||
int wordLen = 0;
|
||||
skip_spaces();
|
||||
if (!isAlpha()) expected("Alphabetic Character");
|
||||
if (!isAlpha()) exit_expected("Alphabetic Character");
|
||||
while (isAlphaNum())
|
||||
{
|
||||
word[wordLen++] = nextChar;
|
||||
getChar();
|
||||
word[wordLen++] = next_char;
|
||||
get_char();
|
||||
}
|
||||
word[wordLen] = 0;
|
||||
}
|
||||
|
||||
/* Reads Decimal number from source file *
|
||||
* a Decimal is a series of digits (0-9) *
|
||||
* Sets: word - number without leading 0's *
|
||||
* Returns: integer value of number */
|
||||
int get_decimal()
|
||||
{
|
||||
int digit;
|
||||
int number = 0;
|
||||
int wordLen = 0;
|
||||
skip_spaces();
|
||||
if (!isDigit()) expected("Digit");
|
||||
while (!isDigit())
|
||||
if (!isDigit()) exit_expected("Digit");
|
||||
while (isDigit())
|
||||
{
|
||||
digit = nextChar - '0';
|
||||
number = number * 10 + digit;
|
||||
if (next_char != '0' || number != 0) //skip leading zeros
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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*/
|
||||
int word_is(char *s)
|
||||
{
|
||||
@ -146,83 +203,246 @@ int var_count; /*Number of Variables Assigned*/
|
||||
void expect_char(char c)
|
||||
{
|
||||
skip_spaces();
|
||||
if (nextChar == c) { getChar(); return; }
|
||||
printf("Expected Character '%c' ", c);
|
||||
if (next_char == c) { get_char(); return; }
|
||||
printf("Expected Character '%c', but found '%c'\n", c, next_char);
|
||||
exit_error(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* add identifier(s) of type t*/
|
||||
void add_idents(int t)
|
||||
/* Check if the next printable character is c *
|
||||
* 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();
|
||||
if (isAlpha())
|
||||
{
|
||||
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);
|
||||
var_type[var_count] = t;
|
||||
parse_varsize();
|
||||
strncpy(var_size[var_count], value, 3);
|
||||
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 */
|
||||
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()
|
||||
{
|
||||
//todo: differentiate between numbers and variables
|
||||
//check variable name against variable table
|
||||
if (!isAlphaNum())
|
||||
expected("term");
|
||||
get_word();
|
||||
strcpy(term, word);
|
||||
DEBUG(">parsing term '%s'\n", term);
|
||||
DEBUG(">Parsing term\n", 0);
|
||||
parse_value();
|
||||
if (val_type == FUNCTION) {
|
||||
printf("Function call only allowed in first term of expression\n");
|
||||
exit_error(EXIT_FAILURE);
|
||||
}
|
||||
strcpy(term, value);
|
||||
term_type = val_type;
|
||||
if (parse_index()) {
|
||||
asm_line("LDX", value);
|
||||
strcat(term, ",X");
|
||||
}
|
||||
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()
|
||||
{
|
||||
parse_term();
|
||||
DEBUG(">processing term '%s'\n", term);
|
||||
asm_line("", "LDA", term);
|
||||
parse_value();
|
||||
DEBUG(">Processing first term '%s'...\n", value);
|
||||
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()
|
||||
{
|
||||
if (strchr("+-&|^", nextChar) == NULL)
|
||||
expected("operator");
|
||||
operator = nextChar;
|
||||
if (strchr("+-&|^", next_char) == NULL)
|
||||
exit_expected("operator");
|
||||
operator = next_char;
|
||||
DEBUG(">parsing operator '%c'\n", operator);
|
||||
getChar();
|
||||
get_char();
|
||||
skip_spaces();
|
||||
}
|
||||
|
||||
/* */
|
||||
void process_operator()
|
||||
{
|
||||
DEBUG(">processing operator '%c'\n", operator);
|
||||
DEBUG(">Processing operator '%c'\n", operator);
|
||||
switch(operator)
|
||||
{
|
||||
case '+':
|
||||
asm_line("","CLC", "");
|
||||
asm_line("","ADC", term);
|
||||
asm_line("CLC", "");
|
||||
asm_line("ADC", term);
|
||||
break;
|
||||
case '-':
|
||||
asm_line("","SEC", "");
|
||||
asm_line("","SBC", term);
|
||||
asm_line("SEC", "");
|
||||
asm_line("SBC", term);
|
||||
break;
|
||||
case '&':
|
||||
asm_line("","AND", term);
|
||||
asm_line("AND", term);
|
||||
break;
|
||||
case '|':
|
||||
asm_line("","ORA", term);
|
||||
asm_line("ORA", term);
|
||||
break;
|
||||
case '^':
|
||||
asm_line("","EOR", term);
|
||||
asm_line("EOR", term);
|
||||
break;
|
||||
default:
|
||||
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();
|
||||
if (match('-'))
|
||||
asm_line("", "LDA", "#0"); //handle unary minus
|
||||
asm_line("LDA", "#0"); //handle unary minus
|
||||
else
|
||||
first_term();
|
||||
while (!match(';'))
|
||||
while (!match(terminator))
|
||||
{
|
||||
parse_operator();
|
||||
parse_term();
|
||||
process_operator();
|
||||
}
|
||||
get_char(); //skip terminator
|
||||
}
|
||||
|
||||
/* parse and compile assignment */
|
||||
/* Parse and compile assignment */
|
||||
void parse_assignment()
|
||||
{
|
||||
DEBUG(">parsing assignment", 0);
|
||||
char var_assign[VARLEN+1];
|
||||
DEBUG(">Parsing assignment of variable '%s''\n", var_assign);
|
||||
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
|
||||
getChar(); //skip equals sign
|
||||
parse_expr();
|
||||
asm_line("", "STA", var_assign);
|
||||
var_indexed = parse_index();
|
||||
if (var_indexed) {
|
||||
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 */
|
||||
void parse_statement()
|
||||
{
|
||||
DEBUG(">parsing statement\n", 0);
|
||||
skip_spaces();
|
||||
if (match('='))
|
||||
parse_assignment();
|
||||
DEBUG(">Parsing statement '%s'\n", word);
|
||||
if(match(':')) {
|
||||
parse_label();
|
||||
return;
|
||||
}
|
||||
if (word_is("if")) {
|
||||
parse_if();
|
||||
return;
|
||||
}
|
||||
if (word_is("goto"))
|
||||
parse_goto();
|
||||
else
|
||||
expected("=");
|
||||
parse_identifier();
|
||||
if (lab_count) {
|
||||
label_line();
|
||||
}
|
||||
}
|
||||
|
||||
/* Reads and parses the next Word in Source File */
|
||||
@ -273,45 +698,114 @@ int var_count; /*Number of Variables Assigned*/
|
||||
{
|
||||
get_word();
|
||||
DEBUG(">Parsing Word '%s'\n", word);
|
||||
if (word_is("byte")) add_idents(BYTE);
|
||||
else if (word_is("char")) add_idents(CHAR);
|
||||
if (word_is("byte")) add_vars(BYTE);
|
||||
else if (word_is("char")) add_vars(CHAR);
|
||||
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 *
|
||||
* Recognizes both C and C++ style comments */
|
||||
void skip_comment()
|
||||
{
|
||||
DEBUG(">Skipping Comment\n", 0);
|
||||
getChar();
|
||||
get_char(); //skip initial /
|
||||
if (match('/')) //if C style comment
|
||||
skip_to_eol(); // skip rest of line
|
||||
else if (match('*')) //if C++ style comment
|
||||
while (TRUE) // skip to "*/"
|
||||
while (TRUE) // skip to */
|
||||
{
|
||||
getChar(); if (!match('*')) continue;
|
||||
getChar(); if (!match('/')) continue;
|
||||
getChar();
|
||||
get_char();
|
||||
if (!match('*')) continue;
|
||||
while (match('*')) get_char();
|
||||
if (!match('/')) continue;
|
||||
get_char();
|
||||
break;
|
||||
//todo: add code to catch unterminated comment
|
||||
}
|
||||
else //if neither
|
||||
expected("/ or *"); // error out
|
||||
exit_expected("/ or *"); // error out
|
||||
}
|
||||
|
||||
void asm_prolog()
|
||||
{
|
||||
fprintf(out_file, ";Program %s\n", src_name);
|
||||
fprintf(out_file, " CPU 6502\n");
|
||||
asm_line(CPU_OP,CPU_ARG);
|
||||
strcpy(comment, "Program ");
|
||||
strcat(comment, src_name);
|
||||
comment_line();
|
||||
}
|
||||
|
||||
/* Write Variable Table */
|
||||
void asm_vartbl()
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<var_count; i++)
|
||||
{
|
||||
asm_line(var_name[i], "DB", "0");
|
||||
for (i=0; i<var_count; i++) {
|
||||
strncpy(lab_asm, var_name[i], LABLEN);
|
||||
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);
|
||||
init();
|
||||
asm_prolog();
|
||||
getChar();
|
||||
get_char();
|
||||
while (TRUE)
|
||||
{
|
||||
skip_spaces();
|
||||
if (match(EOF)) break;
|
||||
if (match('/'))
|
||||
DEBUG("Checking next character '%c'\n", next_char);
|
||||
if (match('#'))
|
||||
process_directive();
|
||||
else if (match('/'))
|
||||
skip_comment();
|
||||
else if (isAlpha())
|
||||
parse_word();
|
||||
else
|
||||
{
|
||||
fprintf(log_file, "%c", nextChar);
|
||||
getChar();
|
||||
printf("Unexpected character '%c'\n", next_char);
|
||||
exit_error(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
asm_epilog();
|
||||
@ -375,7 +873,7 @@ int var_count; /*Number of Variables Assigned*/
|
||||
strcat(src_name, ".c02"); // add ".c02"
|
||||
DEBUG(">opening Source File '%s'\n", src_name);
|
||||
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 *
|
||||
@ -395,7 +893,7 @@ int var_count; /*Number of Variables Assigned*/
|
||||
strcat(out_name, ".asm"); // add ".asm"
|
||||
DEBUG(">opening Output File '%s'\n", out_name);
|
||||
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 *
|
||||
@ -409,7 +907,7 @@ int var_count; /*Number of Variables Assigned*/
|
||||
strcat(log_name, ".log"); //add extension ".asm"
|
||||
DEBUG(">Opening Log File '%s'\n", log_name);
|
||||
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 */
|
||||
@ -432,7 +930,6 @@ int var_count; /*Number of Variables Assigned*/
|
||||
/* Close Log File */
|
||||
void close_log_file() { fclose(log_file); }
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
debug = TRUE;
|
||||
@ -450,6 +947,7 @@ int main (int argc, char *argv[])
|
||||
|
||||
close_src_file();
|
||||
close_out_file();
|
||||
close_log_file();
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user