Browse Source

Added if statements, added TYPE_BOOL

- Bug fixes in uasm.c, including tryTypeCast()
- added a couple of new tokens, TOKEN_IF, TOKEN_ELSE, and TOKEN_BOOL
- Refactoring as well as some bug fixes int uparse.c
remotes/origin/HEAD
Seth Stubbs 5 months ago
parent
commit
df52827b72
  1. 4
      src/main.c
  2. 64
      src/uasm.c
  3. 1
      src/uasm.h
  4. 5
      src/ulex.c
  5. 3
      src/ulex.h
  6. 44
      src/uparse.c
  7. 8
      src/uparse.h

4
src/main.c

@ -3,7 +3,9 @@
int main() {
UASTRootNode *tree = UP_parseSource(
"prntint 0xFF;"
"int a = 2 * 4;"
"if (a == 8)\n"
"prntint 0xFFFF;\n"
);
UA_genTal(tree, fopen("bin/out.tal", "w"));

64
src/uasm.c

@ -7,6 +7,7 @@ typedef struct {
UScope *scopes[MAX_SCOPES];
int sCount;
int pushed; /* current bytes on the stack */
int jmpID;
} UCompState;
static const char preamble[] =
@ -114,7 +115,7 @@ void writeByteLit(UCompState *state, uint8_t lit) {
uint16_t getSize(UCompState *state, UVar *var) {
switch(var->type) {
case TYPE_CHAR: return 1;
case TYPE_CHAR: case TYPE_BOOL: return 1;
case TYPE_INT: return 2;
default:
cError(state, "unknown type! [%d]", var->type);
@ -217,15 +218,24 @@ int tryTypeCast(UCompState *state, UVarType from, UVarType to) {
return 1;
switch(to) {
case TYPE_CHAR:
switch(from) {
case TYPE_INT: fprintf(state->out, "SWP POP\n"); state->pushed -= 1; break; /* moves the most significant byte to the front and pops it */
case TYPE_BOOL: break; /* TYPE_BOOL is already the same size */
default: return 0;
}
break;
case TYPE_INT:
switch(from) {
case TYPE_CHAR: fprintf(state->out, "SWP POP\n"); state->pushed -= 1; break; /* moves the most significant byte to the front and pops it */
/* the process to convert TYPE_CHAR & TYPE_BOOL to TYPE_INT is the same */
case TYPE_BOOL: case TYPE_CHAR: fprintf(state->out, "#00 SWP\n"); state->pushed += 1; break; /* pushes an empty byte to the stack and moves it to the most significant byte */
default: return 0;
}
break;
case TYPE_CHAR:
case TYPE_BOOL: /* do a comparison if the value is not equal to zero */
switch(from) {
case TYPE_INT: fprintf(state->out, "#00 SWP\n"); state->pushed += 1; break; /* pushes an empty byte to the stack and moves it to the most significant byte */
case TYPE_INT: fprintf(state->out, "#0000 NEQ2\n"); state->pushed -= 1; break;
case TYPE_CHAR: fprintf(state->out, "#00 NEQ\n"); break;
default: return 0;
}
break;
@ -255,7 +265,7 @@ void pop(UCompState *state, int size) {
void dupValue(UCompState *state, UVarType type) {
switch(type) {
case TYPE_INT: fprintf(state->out, "DUP2\n"); state->pushed+=SIZE_INT; break;
case TYPE_CHAR: fprintf(state->out, "DUP\n"); state->pushed+=SIZE_CHAR; break;
case TYPE_CHAR: case TYPE_BOOL: fprintf(state->out, "DUP\n"); state->pushed+=SIZE_CHAR; break;
default:
cError(state, "Unknown variable type! [%d]", type);
}
@ -281,14 +291,15 @@ void doComp(UCompState *state, const char *instr, UVarType type) {
fprintf(state->out, "%s2\n", instr);
state->pushed -= SIZE_INT*2; /* pop the two shorts */
break;
case TYPE_CHAR:
case TYPE_CHAR: /* char and bool are the same size */
case TYPE_BOOL:
fprintf(state->out, "%s\n", instr);
state->pushed -= SIZE_CHAR*2; /* pop the two chars */
state->pushed -= SIZE_CHAR*2; /* pop the two bytes */
break;
default:
cError(state, "Unknown variable type! [%d]", type);
}
state->pushed += SIZE_CHAR;
state->pushed += SIZE_BOOL;
}
UVarType compileAssignment(UCompState *state, UASTNode *node) {
@ -333,8 +344,8 @@ UVarType compileExpression(UCompState *state, UASTNode *node) {
case NODE_SUB: doArith(state, "SUB", lType); break;
case NODE_MUL: doArith(state, "MUL", lType); break;
case NODE_DIV: doArith(state, "DIV", lType); break;
case NODE_EQUAL: doComp(state, "EQU", lType); return TYPE_CHAR;
case NODE_NOTEQUAL: doComp(state, "NEQ", lType); return TYPE_CHAR;
case NODE_EQUAL: doComp(state, "EQU", lType); return TYPE_BOOL;
case NODE_NOTEQUAL: doComp(state, "NEQ", lType); return TYPE_BOOL;
case NODE_INTLIT: writeIntLit(state, ((UASTIntNode*)node)->num); return TYPE_INT;
case NODE_VAR: return compileVar(state, node); break;
default:
@ -358,7 +369,7 @@ void compileDeclaration(UCompState *state, UASTNode *node) {
/* if there's no assignment, the default value will be scary undefined memory :O */
if (node->left) {
type = compileExpression(state, node->left);
if (compareVarTypes(state, type, rawVar->type))
if (!compareVarTypes(state, type, rawVar->type))
cErrorNode(state, node, "Cannot assign type '%s' to %.*s of type '%s'", getTypeName(type), rawVar->len, rawVar->name, getTypeName(rawVar->type));
setIntVar(state, var->scope, var->var);
}
@ -374,20 +385,48 @@ void compileScope(UCompState *state, UASTNode *node) {
popScope(state);
}
void compileIf(UCompState *state, UASTNode *node) {
UASTIfNode *ifNode = (UASTIfNode*)node;
int jmpID = state->jmpID++;
/* compile conditional */
UVarType type = compileExpression(state, node->left);
if (!tryTypeCast(state, type, TYPE_BOOL))
cErrorNode(state, (UASTNode*)ifNode, "Cannot cast type '%s' to type '%s'", getTypeName(type), getTypeName(TYPE_BOOL));
/* write comparison jump, if the flag is not equal to true, skip the true statements */
fprintf(state->out, "#01 NEQ ;jmp%d JCN2\n", jmpID);
state->pushed -= SIZE_BOOL;
compileAST(state, ifNode->block);
if (ifNode->elseBlock) {
int tmpJmp = jmpID;
fprintf(state->out, ";jmp%d JMP2\n", jmpID = state->jmpID++);
fprintf(state->out, "@jmp%d\n", tmpJmp);
compileAST(state, ifNode->elseBlock);
}
fprintf(state->out, "@jmp%d\n", jmpID);
}
void compileAST(UCompState *state, UASTNode *node) {
/* STATE nodes hold the expression in node->left, and the next expression in node->right */
while (node) {
int startPushed = state->pushed;
switch(node->type) {
case NODE_STATE_PRNT: compilePrintInt(state, node); break;
case NODE_STATE_DECLARE_VAR: compileDeclaration(state, node); break;
case NODE_STATE_EXPR: compileExpression(state, node->left); break;
case NODE_STATE_SCOPE: compileScope(state, node); break;
case NODE_STATE_IF: compileIf(state, node); break;
default:
cError(state, "unknown statement node!! [%d]\n", node->type);
}
/* clean the stack */
pop(state, state->pushed);
pop(state, state->pushed - startPushed);
/* move to the next statement */
node = node->right;
@ -398,6 +437,7 @@ void UA_genTal(UASTRootNode *tree, FILE *out) {
UCompState state;
state.sCount = 0;
state.pushed = 0;
state.jmpID = 0;
state.out = out;
/* first, write the preamble */

1
src/uasm.h

@ -9,6 +9,7 @@
#define SIZE_INT 2
#define SIZE_CHAR 1
#define SIZE_BOOL 1
#include <stdio.h>

5
src/ulex.c

@ -11,7 +11,10 @@ UReservedWord reservedWords[] = {
{TOKEN_CHAR, "char", 4},
{TOKEN_INT, "int", 3},
{TOKEN_VOID, "void", 4},
{TOKEN_PRINTINT, "prntint", 7}
{TOKEN_BOOL, "bool", 4},
{TOKEN_PRINTINT, "prntint", 7},
{TOKEN_IF, "if", 2},
{TOKEN_ELSE, "else", 4},
};
void UL_initLexState(ULexState *state, const char *src) {

3
src/ulex.h

@ -6,7 +6,10 @@ typedef enum {
TOKEN_CHAR,
TOKEN_INT,
TOKEN_VOID,
TOKEN_BOOL,
TOKEN_PRINTINT,
TOKEN_IF,
TOKEN_ELSE,
/* literals */
TOKEN_IDENT,

44
src/uparse.c

@ -26,8 +26,8 @@ ParseRule ruleTable[];
/* ==================================[[ generic helper functions ]]================================== */
void errorAt(UToken *token, int line, const char *fmt, va_list args) {
printf("Syntax error at '%.*s' on line %d\n\t", token->len, token->str, line);
void errorAt(UToken *token, const char *fmt, va_list args) {
printf("Syntax error at '%.*s' on line %d\n\t", token->len, token->str, token->line);
vprintf(fmt, args);
printf("\n");
exit(EXIT_FAILURE);
@ -36,7 +36,7 @@ void errorAt(UToken *token, int line, const char *fmt, va_list args) {
void error(UParseState *state, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
errorAt(&state->previous, state->lstate.line, fmt, args);
errorAt(&state->previous, fmt, args);
va_end(args);
}
@ -219,7 +219,10 @@ ParseRule ruleTable[] = {
{NULL, NULL, PREC_NONE}, /* TOKEN_CHAR */
{NULL, NULL, PREC_NONE}, /* TOKEN_INT */
{NULL, NULL, PREC_NONE}, /* TOKEN_VOID */
{NULL, NULL, PREC_NONE}, /* TOKEN_BOOL */
{NULL, NULL, PREC_NONE}, /* TOKEN_PRINTINT */
{NULL, NULL, PREC_NONE}, /* TOKEN_IF */
{NULL, NULL, PREC_NONE}, /* TOKEN_ELSE */
/* literals */
{identifer, NULL, PREC_LITERAL}, /* TOKEN_IDENT */
@ -301,7 +304,7 @@ UASTNode* printStatement(UParseState *state) {
return newNode(state, tkn, NODE_STATE_PRNT, expression(state), NULL);
}
UASTNode* intStatement(UParseState *state) {
UASTNode* varTypeStatement(UParseState *state, UVarType type) {
UASTVarNode *node;
int var;
@ -310,7 +313,7 @@ UASTNode* intStatement(UParseState *state) {
error(state, "Expected identifer!");
/* define the variable */
var = newVar(state, TYPE_INT, state->previous.str, state->previous.len);
var = newVar(state, type, state->previous.str, state->previous.len);
/* if it's assigned a value, evaluate the expression & set the left node, if not set it to NULL */
node = (UASTVarNode*)newBaseNode(state, state->previous, sizeof(UASTVarNode), NODE_STATE_DECLARE_VAR, (match(state, TOKEN_EQUAL)) ? expression(state) : NULL, NULL);
@ -333,6 +336,26 @@ UASTNode* scopeStatement(UParseState *state) {
return (UASTNode*)node;
}
UASTNode* ifStatement(UParseState *state) {
UASTIfNode *node = (UASTIfNode*)newBaseNode(state, state->previous, sizeof(UASTIfNode), NODE_STATE_IF, NULL, NULL);
if (!match(state, TOKEN_LEFT_PAREN))
error(state, "Expected '(' to start if conditional!");
/* set the expression */
node->_node.left = expression(state);
if (!match(state, TOKEN_RIGHT_PAREN))
error(state, "Expected ')' to end if conditional!");
/* parse the true block */
node->block = statement(state);
/* if there's an else block, parse it too */
node->elseBlock = match(state, TOKEN_ELSE) ? statement(state) : NULL;
return (UASTNode*)node;
}
UASTNode* expression(UParseState *state) {
UASTNode *node = parsePrecedence(state, NULL, PREC_ASSIGNMENT);
@ -349,9 +372,14 @@ UASTNode* statement(UParseState *state) {
if (match(state, TOKEN_PRINTINT)) {
node = printStatement(state);
} else if (match(state, TOKEN_INT)) {
node = intStatement(state);
node = varTypeStatement(state, TYPE_INT);
} else if (match(state, TOKEN_BOOL)) {
node = varTypeStatement(state, TYPE_BOOL);
/* the statements below don't require a colon, they directly return skipping that check */
} else if (match(state, TOKEN_LEFT_BRACE)) {
node = scopeStatement(state);
return scopeStatement(state);
} else if (match(state, TOKEN_IF)) {
return ifStatement(state);
} else {
UToken tkn = state->previous;
/* no statement match was found, just parse the expression */
@ -377,6 +405,7 @@ void printNode(UASTNode *node) {
case NODE_STATE_PRNT: printf("PRNT"); break;
case NODE_STATE_SCOPE: printf("SCPE"); break;
case NODE_STATE_DECLARE_VAR: printf("NVAR"); break;
case NODE_STATE_IF: printf("IF"); break;
case NODE_VAR: printf("VAR[%d]", ((UASTVarNode*)node)->var); break;
case NODE_STATE_EXPR: printf("EXPR"); break;
default: break;
@ -398,6 +427,7 @@ const char* getTypeName(UVarType type) {
switch(type) {
case TYPE_INT: return "int";
case TYPE_CHAR: return "char";
case TYPE_BOOL: return "bool";
default:
return "<errtype>";
}

8
src/uparse.h

@ -29,12 +29,14 @@ typedef enum {
NODE_STATE_DECLARE_VAR,
NODE_STATE_DECLARE_FUNC,
NODE_STATE_EXPR,
NODE_STATE_IF,
/* scopes are different, node->left holds the statement tree for the scope, node->right holds the next statement */
NODE_STATE_SCOPE,
} UASTNodeType;
typedef enum {
TYPE_CHAR,
TYPE_BOOL,
TYPE_INT,
TYPE_NONE
} UVarType;
@ -81,6 +83,12 @@ typedef struct {
UScope scope;
} UASTScopeNode;
typedef struct {
COMMON_NODE_HEADER;
UASTNode *block;
UASTNode *elseBlock;
} UASTIfNode;
typedef struct {
/* lexer related info */
ULexState lstate;

Loading…
Cancel
Save