Add global variables

This commit is contained in:
zongor 2026-04-10 22:52:19 -07:00
parent 11158ba4f9
commit 9d7fdbb622
9 changed files with 477 additions and 239 deletions

View File

@ -3,74 +3,83 @@
#include <stdlib.h> #include <stdlib.h>
#define EMBED_FILE(name) \ #define EMBED_FILE(name) \
void emit_##name(const char *filename) \ void emit_##name(const char *filename) \
{ \ { \
FILE *f = fopen(filename, "wb"); \ FILE *f = fopen(filename, "wb"); \
if(f) { \ if(f) { \
fwrite(name, 1, name##_len, f); \ fwrite(name, 1, name##_len, f); \
fclose(f); \ fclose(f); \
} \ } \
} }
static char* readFile(const char* path) { static char *
FILE* file = fopen(path, "rb"); readFile(const char *path)
if (file == NULL) { {
fprintf(stderr, "Could not open file \"%s\".\n", path); FILE *file = fopen(path, "rb");
exit(74); if(file == NULL) {
} fprintf(stderr, "Could not open file \"%s\".\n", path);
exit(74);
}
fseek(file, 0L, SEEK_END); fseek(file, 0L, SEEK_END);
size_t fileSize = ftell(file); size_t fileSize = ftell(file);
rewind(file); rewind(file);
char* buffer = (char*)malloc(fileSize + 1); char *buffer = (char *)malloc(fileSize + 1);
if (buffer == NULL) { if(buffer == NULL) {
fprintf(stderr, "Not enough memory to read \"%s\".\n", path); fprintf(stderr, "Not enough memory to read \"%s\".\n", path);
exit(74); exit(74);
} }
size_t bytesRead = fread(buffer, sizeof(char), fileSize, file); size_t bytesRead = fread(buffer, sizeof(char), fileSize, file);
if (bytesRead < fileSize) { if(bytesRead < fileSize) {
fprintf(stderr, "Could not read file \"%s\".\n", path); fprintf(stderr, "Could not read file \"%s\".\n", path);
exit(74); exit(74);
} }
buffer[bytesRead] = '\0'; buffer[bytesRead] = '\0';
fclose(file); fclose(file);
return buffer; return buffer;
} }
void print_help() { void
printf("Usage: undar [options] file...\nOptions:\n\t-emit={c|u}\tEmitter output, currently C source and Uxn binary.\n\n"); print_help()
{
printf("Usage: undar [options] file...\nOptions:\n\t-emit={c|u}\tEmitter "
"output, currently C source and Uxn binary.\n\n");
} }
#define MEM_SIZE 68000
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
if (argc > 1 && (seq(argv[1], "--help") || seq(argv[1], "-h"))) { if(argc > 1 && (seq(argv[1], "--help") || seq(argv[1], "-h"))) {
print_help(); print_help();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if(argc != 3) { if(argc != 3) {
print_help(); print_help();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
Emitter e; Emitter e;
if (seq(argv[1], "-emit=c")) { if(seq(argv[1], "-emit=c")) {
e = c_emitter(); e = c_emitter();
} else if (seq(argv[1], "-emit=u")) { } else if(seq(argv[1], "-emit=u")) {
e = uxn_emitter(); e = uxn_emitter();
} else { } else {
printf("unknown emitter type\n"); printf("unknown emitter type\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
u8 tape[MEM_SIZE];
Arena a = {tape, 0, MEM_SIZE};
char* source = readFile(argv[2]); char *source = readFile(argv[2]);
compile(e, source); compile(&a, e, source);
free(source); free(source);
printf("\n"); printf("\n");
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

44
common.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef UNDAR_COMMON_H
#define UNDAR_COMMON_H
#include "libc.h"
#include "list.h"
typedef enum symbol_type_e {
SYMBOL_VOID,
SYMBOL_BOOL,
SYMBOL_BYTE,
SYMBOL_INT,
SYMBOL_NAT,
SYMBOL_REAL,
SYMBOL_STR,
SYMBOL_U8,
SYMBOL_I8,
SYMBOL_I16,
SYMBOL_U16,
SYMBOL_I32,
SYMBOL_U32,
SYMBOL_F32,
SYMBOL_ARRAY,
SYMBOL_FUNCTION,
SYMBOL_PLEX,
SYMBOL_METHOD,
SYMBOL_TRAIT,
SYMBOL_CONST
} SymbolType;
typedef struct symbol_s Symbol;
#define MAX_SYMBOL_NAME_LENGTH 64
struct symbol_s {
char name[MAX_SYMBOL_NAME_LENGTH]; /* ptr to name */
u8 name_length; /* length of the name, max 64 */
SymbolType type; /* the type for this symbol */
SymbolType secondary_type; /* return type for functions/methods, or const if type/plex */
u32 ref; /* either constant value or pointer to other thing */
u32 size; /* either size of the plex or length of the array/list/etc. */
List *args; /* function params or plex constructor args */
List *fields; /* either plex variable fields, or method signatures */
};
#endif

35
emit.h
View File

@ -1,6 +1,7 @@
#ifndef UNDAR_EMIT_H #ifndef UNDAR_EMIT_H
#define UNDAR_EMIT_H #define UNDAR_EMIT_H
#include "common.h"
#include "libc.h" #include "libc.h"
typedef enum notation_type_e { typedef enum notation_type_e {
@ -14,13 +15,17 @@ typedef enum output_type_e {
TEXT TEXT
} OutputType; } OutputType;
typedef void (*SymbolEmit)(Symbol *sym);
typedef void (*ErrorMsg)(const char *str, i32 length, i32 line);
typedef void (*VoidArgEmit)(); typedef void (*VoidArgEmit)();
typedef void (*StrArgEmit)(const char *str, i32 length); typedef void (*StrArgEmit)(const char *str, i32 length);
typedef i32 (*TypeVariableEmit)(const char *str, i32 length);
typedef struct emitter_s Emitter; typedef struct emitter_s Emitter;
struct emitter_s { struct emitter_s {
NotationType notation; NotationType notation;
OutputType output; OutputType output;
ErrorMsg error;
VoidArgEmit prolog; VoidArgEmit prolog;
VoidArgEmit epilogue; VoidArgEmit epilogue;
VoidArgEmit emit_add; VoidArgEmit emit_add;
@ -42,19 +47,19 @@ struct emitter_s {
StrArgEmit emit_real; StrArgEmit emit_real;
StrArgEmit emit_byte; StrArgEmit emit_byte;
StrArgEmit emit_str; StrArgEmit emit_str;
VoidArgEmit emit_bool_type; TypeVariableEmit emit_bool_type;
VoidArgEmit emit_byte_type; TypeVariableEmit emit_byte_type;
VoidArgEmit emit_int_type; TypeVariableEmit emit_int_type;
VoidArgEmit emit_nat_type; TypeVariableEmit emit_nat_type;
VoidArgEmit emit_real_type; TypeVariableEmit emit_real_type;
VoidArgEmit emit_str_type; TypeVariableEmit emit_str_type;
VoidArgEmit emit_u8_type; TypeVariableEmit emit_u8_type;
VoidArgEmit emit_i8_type; TypeVariableEmit emit_i8_type;
VoidArgEmit emit_i16_type; TypeVariableEmit emit_i16_type;
VoidArgEmit emit_u16_type; TypeVariableEmit emit_u16_type;
VoidArgEmit emit_i32_type; TypeVariableEmit emit_i32_type;
VoidArgEmit emit_u32_type; TypeVariableEmit emit_u32_type;
VoidArgEmit emit_f32_type; TypeVariableEmit emit_f32_type;
VoidArgEmit emit_array; VoidArgEmit emit_array;
VoidArgEmit emit_function; VoidArgEmit emit_function;
VoidArgEmit emit_plex; VoidArgEmit emit_plex;
@ -66,9 +71,11 @@ struct emitter_s {
VoidArgEmit emit_not; VoidArgEmit emit_not;
VoidArgEmit emit_open_paren; VoidArgEmit emit_open_paren;
VoidArgEmit emit_close_paren; VoidArgEmit emit_close_paren;
StrArgEmit emit_constant;
SymbolEmit emit_variable;
}; };
Emitter c_emitter(); Emitter c_emitter();
Emitter uxn_emitter(); Emitter uxn_emitter();
#endif #endif

View File

@ -1,5 +1,13 @@
#include "../../emit.h" #include "../../emit.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
void
c_emit_error(const char *str, i32 length, i32 line)
{
printf("Error at line: %d > %.*s\n ", line, length, str);
exit(1);
}
void void
c_prolog() c_prolog()
@ -106,69 +114,95 @@ c_emit_void()
{ {
} }
void i32
c_emit_bool_type() c_emit_bool_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 1;
} }
void i32
c_emit_byte_type() c_emit_byte_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 1;
} }
void i32
c_emit_int_type() c_emit_int_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 2;
} }
void i32
c_emit_nat_type() c_emit_nat_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 2;
} }
void i32
c_emit_real_type() c_emit_real_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 2;
} }
void i32
c_emit_str_type() c_emit_str_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 2;
} }
void i32
c_emit_u8_type() c_emit_u8_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 1;
} }
void i32
c_emit_i8_type() c_emit_i8_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 1;
} }
void i32
c_emit_i16_type() c_emit_i16_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 2;
} }
void i32
c_emit_u16_type() c_emit_u16_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 2;
} }
void i32
c_emit_i32_type() c_emit_i32_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 4;
} }
void i32
c_emit_u32_type() c_emit_u32_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 4;
} }
void i32
c_emit_f32_type() c_emit_f32_type(const char *str, i32 length)
{ {
printf("%.*s ", length, str);
return 4;
} }
void void
@ -249,12 +283,25 @@ c_emit_close_paren()
printf(")"); printf(")");
} }
void
c_emit_constant(const char *str, i32 length)
{
USED(str);
USED(length);
}
void
c_emit_variable(Symbol *sym) {
USED(sym);
}
Emitter Emitter
c_emitter() c_emitter()
{ {
return (Emitter){ return (Emitter){
INFIX, INFIX,
TEXT, TEXT,
c_emit_error,
c_prolog, c_prolog,
c_epilogue, c_epilogue,
c_emit_add, c_emit_add,
@ -300,5 +347,7 @@ c_emitter()
c_emit_not, c_emit_not,
c_emit_open_paren, c_emit_open_paren,
c_emit_close_paren, c_emit_close_paren,
c_emit_constant,
c_emit_variable,
}; };
} }

View File

@ -7,18 +7,45 @@
#define UXN_OP_K (1 << 7) #define UXN_OP_K (1 << 7)
enum uxn_opcode { enum uxn_opcode {
/* Stack I */ /* Logic */ /* Memory I */ /* Arithmetic*/ /* Stack I */ /* Logic */ /* Memory I */ /* Arithmetic*/
BRK = 0x00, EQU = 0x08, LDZ = 0x10, ADD = 0x18, BRK = 0x00,
INC = 0x01, NEQ = 0x09, STZ = 0x11, SUB = 0x19, EQU = 0x08,
POP = 0x02, GTH = 0x0A, LDR = 0x12, MUL = 0x1A, LDZ = 0x10,
NIP = 0x03, LTH = 0x0B, STR = 0x13, DIV = 0x1B, ADD = 0x18,
INC = 0x01,
NEQ = 0x09,
STZ = 0x11,
SUB = 0x19,
POP = 0x02,
GTH = 0x0A,
LDR = 0x12,
MUL = 0x1A,
NIP = 0x03,
LTH = 0x0B,
STR = 0x13,
DIV = 0x1B,
/* Stack II */ /* Stash */ /* Memory II */ /* Bitwise */ /* Stack II */ /* Stash */ /* Memory II */ /* Bitwise */
SWP = 0x04, JMP = 0x0C, LDA = 0x14, AND = 0x1C, SWP = 0x04,
ROT = 0x05, JCN = 0x0D, STA = 0x15, ORA = 0x1D, JMP = 0x0C,
DUP = 0x06, JSR = 0x0E, DEI = 0x16, EOR = 0x1E, LDA = 0x14,
OVR = 0x07, STH = 0x0F, DEO = 0x17, SFT = 0x1F, AND = 0x1C,
ROT = 0x05,
JCN = 0x0D,
STA = 0x15,
ORA = 0x1D,
DUP = 0x06,
JSR = 0x0E,
DEI = 0x16,
EOR = 0x1E,
OVR = 0x07,
STH = 0x0F,
DEO = 0x17,
SFT = 0x1F,
LIT = 0x80, JCI = 0x20, JMI = 0x40, JSI = 0x60, LIT = 0x80,
JCI = 0x20,
JMI = 0x40,
JSI = 0x60,
}; };
/* /*
@ -34,16 +61,23 @@ https://rosettacode.org/wiki/Bitwise_operations#Uxntal
%ror { SWP #00 ROT SFT2 ORA } %ror { SWP #00 ROT SFT2 ORA }
*/ */
void
uxn_emit_error(const char *str, i32 length, i32 line)
{
printf("Error at line: %d > %.*s\n ", line, length, str);
exit(1);
}
void void
uxn_prolog() uxn_prolog()
{ {
/* essentially the "main" function */
printf("|100 @on-reset ( -> )\n");
} }
void void
uxn_epilogue() uxn_epilogue()
{ {
} }
void void
@ -141,69 +175,98 @@ uxn_emit_void()
{ {
} }
void /* @global $size */
uxn_emit_bool_type() /* &local $size */
i32
uxn_emit_bool_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $1 } ", length, str);
return 1;
} }
void i32
uxn_emit_byte_type() uxn_emit_byte_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $1 } ", length, str);
return 1;
} }
void i32
uxn_emit_int_type() uxn_emit_int_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $2 } ", length, str);
return 2;
} }
void i32
uxn_emit_nat_type() uxn_emit_nat_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $2 } ", length, str);
return 2;
} }
void i32
uxn_emit_real_type() uxn_emit_real_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $2 } ", length, str);
return 2;
} }
void i32
uxn_emit_str_type() uxn_emit_str_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $2 } ", length, str);
return 2;
} }
void i32
uxn_emit_u8_type() uxn_emit_u8_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $1 } ", length, str);
return 1;
} }
void i32
uxn_emit_i8_type() uxn_emit_i8_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $1 } ", length, str);
return 1;
} }
void i32
uxn_emit_i16_type() uxn_emit_i16_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $2 } ", length, str);
return 2;
} }
void i32
uxn_emit_u16_type() uxn_emit_u16_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $2 } ", length, str);
return 2;
} }
void i32
uxn_emit_i32_type() uxn_emit_i32_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $4 } ", length, str);
return 4;
} }
void i32
uxn_emit_u32_type() uxn_emit_u32_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $4 } ", length, str);
return 4;
} }
void i32
uxn_emit_f32_type() uxn_emit_f32_type(const char *str, i32 length)
{ {
printf("!{ @%.*s $4 } ", length, str);
return 4;
} }
void void
@ -244,6 +307,12 @@ uxn_emit_str(const char *str, i32 length)
printf("\"%.*s ", length, str); printf("\"%.*s ", length, str);
} }
void
uxn_emit_constant(const char *str, i32 length)
{
printf(";%.*s STA2 ", length, str);
}
void void
uxn_emit_array() uxn_emit_array()
{ {
@ -283,12 +352,15 @@ uxn_emit_print()
void void
uxn_emit_open_paren() uxn_emit_open_paren()
{ {
} }
void void
uxn_emit_close_paren() uxn_emit_close_paren()
{ {
}
void
uxn_emit_variable(Symbol *sym) {
printf(";%.*s LDA2 ", sym->name_length, sym->name);
} }
Emitter Emitter
@ -297,6 +369,7 @@ uxn_emitter()
return (Emitter){ return (Emitter){
POSTFIX, POSTFIX,
BINARY, BINARY,
uxn_emit_error,
uxn_prolog, uxn_prolog,
uxn_epilogue, uxn_epilogue,
uxn_emit_add, uxn_emit_add,
@ -342,5 +415,7 @@ uxn_emitter()
uxn_emit_not, uxn_emit_not,
uxn_emit_open_paren, uxn_emit_open_paren,
uxn_emit_close_paren, uxn_emit_close_paren,
uxn_emit_constant,
uxn_emit_variable,
}; };
} }

2
libc.c
View File

@ -19,7 +19,7 @@ scpy(char *to, const char *from, u32 length)
u32 i; u32 i;
if(to == nil || from == nil) return -1; if(to == nil || from == nil) return -1;
if(length == 0) return 0; if(length == 0) return 0;
for(i = 0; i < length - 1 && from[i] != '\0'; i++) to[i] = from[i]; for(i = 0; i < length && from[i] != '\0'; i++) to[i] = from[i];
to[i] = '\0'; to[i] = '\0';
return 0; return 0;
} }

223
parser.c
View File

@ -3,13 +3,14 @@
Emitter emitter; Emitter emitter;
Parser parser; Parser parser;
Arena *arena;
/**************************************************** /****************************************************
* Scope * Scope
***************************************************/ ***************************************************/
void void
scope_push(Arena *arena) scope_push()
{ {
Scope *child = aalloc(arena, sizeof(Scope)); Scope *child = aalloc(arena, sizeof(Scope));
child->symbols = new_list(arena); child->symbols = new_list(arena);
@ -41,20 +42,19 @@ scope_get_symbol(Scope *scope, const char *name, u32 name_length)
} }
Symbol * Symbol *
scope_add_symbol(Arena *arena, const char *name, u32 name_length, scope_add_symbol(const char *name, u32 name_length, SymbolType type, u32 size)
SymbolType type, u32 size)
{ {
Symbol *sym = scope_get_symbol(parser.current_scope, name, name_length); Symbol *sym = scope_get_symbol(parser.current_scope, name, name_length);
if(sym != nil) return sym; if(sym != nil) return sym;
sym = aalloc(arena, sizeof(Symbol)); sym = aalloc(arena, sizeof(Symbol));
scpy(sym->name, name, slen(name)); scpy(sym->name, name, name_length);
sym->name_length = slen(name); sym->name_length = name_length;
sym->type = type; sym->type = type;
sym->secondary_type = VOID; sym->secondary_type = SYMBOL_VOID;
sym->size = size; sym->size = size;
sym->ref = 0; sym->ref = 0;
if(type == PLEX || type == METHOD || type == TRAIT) { if(type == SYMBOL_PLEX || type == SYMBOL_METHOD || type == SYMBOL_TRAIT) {
sym->args = new_list(arena); sym->args = new_list(arena);
sym->fields = new_list(arena); sym->fields = new_list(arena);
} }
@ -64,6 +64,19 @@ scope_add_symbol(Arena *arena, const char *name, u32 name_length,
return sym; return sym;
} }
bool
is_global()
{
return parser.current_scope != nil && parser.current_scope->parent == nil;
}
bool
is_type()
{
return parser.previous.type >= TOKEN_TYPE_I8 &&
parser.previous.type <= TOKEN_TYPE_PTR;
}
/**************************************************** /****************************************************
* Parser * Parser
***************************************************/ ***************************************************/
@ -117,9 +130,8 @@ binary()
TokenType operatorType = parser.previous.type; TokenType operatorType = parser.previous.type;
ParseRule *rule = get_rule(operatorType); ParseRule *rule = get_rule(operatorType);
if (emitter.notation == POSTFIX) { if(emitter.notation == POSTFIX)
parse_precedence((Precedence)(rule->precedence + 1)); parse_precedence((Precedence)(rule->precedence + 1));
}
switch(operatorType) { switch(operatorType) {
case TOKEN_BANG_EQ: case TOKEN_BANG_EQ:
@ -156,9 +168,8 @@ binary()
return; return;
} }
if (emitter.notation == INFIX) { if(emitter.notation == INFIX)
parse_precedence((Precedence)(rule->precedence + 1)); parse_precedence((Precedence)(rule->precedence + 1));
}
} }
static void static void
@ -185,59 +196,139 @@ expression()
parse_precedence(PREC_ASSIGNMENT); parse_precedence(PREC_ASSIGNMENT);
} }
static void variable() {
Symbol *sym = scope_get_symbol(parser.current_scope, parser.previous.start, parser.previous.length);
if(sym == nil) {
emitter.error(parser.previous.start, parser.previous.length, parser.previous.line);
}
emitter.emit_variable(sym);
}
static void
variable_declaration()
{
i32 size = 0;
TokenType tt = parser.previous.type;
Token var = parser.current;
switch(tt) {
case TOKEN_TYPE_INT: {
size = emitter.emit_int_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_INT, size);
break;
}
case TOKEN_TYPE_NAT: {
size = emitter.emit_nat_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_NAT, size);
break;
}
case TOKEN_TYPE_REAL: {
size = emitter.emit_real_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_REAL, size);
break;
}
case TOKEN_TYPE_STR: {
/* FIXME: this is wrong, we need to store the size of the string, not just
* the pointer */
/* size = emitter.emit_str_type(parser.current.start, parser.current.length,
*/
/* is_global()); */
/* scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_STR, size);
*/
break;
}
case TOKEN_TYPE_BOOL: {
size = emitter.emit_bool_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_BOOL, size);
break;
}
case TOKEN_TYPE_BYTE: {
size = emitter.emit_byte_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U8, size);
break;
}
case TOKEN_TYPE_U8: {
size = emitter.emit_u8_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U8, size);
break;
}
case TOKEN_TYPE_I8: {
size = emitter.emit_i8_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_I8, size);
break;
}
case TOKEN_TYPE_U16: {
size = emitter.emit_u16_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U16, size);
break;
}
case TOKEN_TYPE_I16: {
size = emitter.emit_i16_type(parser.current.start, parser.current.length);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_I16, size);
break;
}
default: {
/* probably a variable */
break;
}
}
advance();
if(match(TOKEN_EQ)) {
expression();
emitter.emit_constant(var.start, var.length);
}
consume(TOKEN_SEMICOLON);
}
static void static void
declaration() declaration()
{ {
if(match(TOKEN_TYPE_INT)) { /**
emitter.emit_int_type(); * maybe a Plex?
} else if(match(TOKEN_TYPE_NAT)) { * lookup plex defs
emitter.emit_nat_type(); * if not then
} else if(match(TOKEN_TYPE_REAL)) { */
emitter.emit_real_type();
} else if(match(TOKEN_TYPE_STR)) {
emitter.emit_str_type();
} else if(match(TOKEN_TYPE_BOOL)) {
emitter.emit_bool_type();
} else if(match(TOKEN_TYPE_BYTE)) {
emitter.emit_byte_type();
} else if(match(TOKEN_TYPE_U8)) {
emitter.emit_u8_type();
} else if(match(TOKEN_TYPE_I8)) {
emitter.emit_i8_type();
} else if(match(TOKEN_TYPE_U16)) {
emitter.emit_u16_type();
} else if(match(TOKEN_TYPE_I16)) {
emitter.emit_i16_type();
} else if(match(TOKEN_IDENTIFIER)) {
/**
* maybe a Plex?
* lookup plex defs
* if not then
*/
}
statement(); if(is_type())
variable_declaration();
else
statement();
} }
static void print_statement() { static void
if (emitter.notation == INFIX) { print_statement()
emitter.emit_print(); {
} if(emitter.notation == INFIX) emitter.emit_print();
expression(); expression();
consume(TOKEN_SEMICOLON); consume(TOKEN_SEMICOLON);
if (emitter.notation == POSTFIX) { if(emitter.notation == POSTFIX) emitter.emit_print();
emitter.emit_print(); }
}
static void
block()
{
while(!check(TOKEN_RBRACE) && !check(TOKEN_EOF)) declaration();
consume(TOKEN_RBRACE);
} }
static void static void
statement() statement()
{ {
if(match(TOKEN_KEYWORD_PRINT)) { if(match(TOKEN_LBRACE)) {
print_statement(); scope_push();
} else { block();
scope_pop();
} else if(match(TOKEN_KEYWORD_PRINT)) {
print_statement();
} else {
expression(); expression();
} }
} }
static void static void
@ -267,9 +358,7 @@ static void
unary() unary()
{ {
TokenType operatorType = parser.previous.type; TokenType operatorType = parser.previous.type;
if (emitter.notation == POSTFIX) { if(emitter.notation == POSTFIX) parse_precedence(PREC_UNARY);
parse_precedence(PREC_UNARY);
}
switch(operatorType) { switch(operatorType) {
case TOKEN_MINUS: case TOKEN_MINUS:
@ -282,15 +371,13 @@ unary()
return; return;
} }
if (emitter.notation == INFIX) { if(emitter.notation == INFIX) parse_precedence(PREC_UNARY);
parse_precedence(PREC_UNARY);
}
} }
ParseRule rules[] = { ParseRule rules[] = {
/* 0 */ {NULL, NULL, PREC_NONE}, /* 0 */ {NULL, NULL, PREC_NONE}, /* TOKEN_ERROR */
/* 1 */ {NULL, NULL, PREC_NONE}, /* 1 */ {NULL, NULL, PREC_NONE}, /* TOKEN_EOF */
/* 2 */ {NULL, NULL, PREC_NONE}, /* 2 */ {variable, NULL, PREC_NONE}, /* TOKEN_IDENTIFIER */
/* 3 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_INT */ /* 3 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_INT */
/* 4 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_NAT */ /* 4 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_NAT */
/* 5 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_REAL */ /* 5 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_REAL */
@ -377,9 +464,7 @@ parse_precedence(Precedence precedence)
advance(); advance();
prefixRule = get_rule(parser.previous.type)->prefix; prefixRule = get_rule(parser.previous.type)->prefix;
if(prefixRule == NULL) { if(prefixRule == NULL) return;
return;
}
prefixRule(); prefixRule();
@ -397,11 +482,13 @@ get_rule(TokenType type)
} }
bool bool
compile(Emitter e, char *source) compile(Arena *a, Emitter e, char *source)
{ {
emitter = e; arena = a;
emitter = e;
init_lexer(source); init_lexer(source);
advance(); advance();
scope_push();
emitter.prolog(); emitter.prolog();

View File

@ -1,51 +1,14 @@
#ifndef UNDAR_PARSER_H #ifndef UNDAR_PARSER_H
#define UNDAR_PARSER_H #define UNDAR_PARSER_H
#include "libc.h" #include "common.h"
#include "list.h"
#include "lexer.h" #include "lexer.h"
#include "emit.h" #include "emit.h"
typedef enum symbol_type_e {
VOID,
BOOL,
BYTE,
INT,
NAT,
REAL,
STR,
U8,
I8,
I16,
U16,
I32,
U32,
F32,
ARRAY,
FUNCTION,
PLEX,
METHOD,
TRAIT,
CONST
} SymbolType;
typedef struct symbol_s Symbol;
typedef struct scope_s Scope; typedef struct scope_s Scope;
typedef struct parser_s Parser; typedef struct parser_s Parser;
typedef struct parse_rule_s ParseRule; typedef struct parse_rule_s ParseRule;
#define MAX_SYMBOL_NAME_LENGTH 64
struct symbol_s {
char name[MAX_SYMBOL_NAME_LENGTH]; /* ptr to name */
u8 name_length; /* length of the name, max 64 */
SymbolType type; /* the type for this symbol */
SymbolType secondary_type; /* return type for functions/methods, or const if type/plex */
u32 ref; /* either constant value or pointer to other thing */
u32 size; /* either size of the plex or length of the array/list/etc. */
List *args; /* function params or plex constructor args */
List *fields; /* either plex variable fields, or method signatures */
};
struct scope_s { struct scope_s {
Scope *parent; /* pointer to this scopes parent to "bubble up"*/ Scope *parent; /* pointer to this scopes parent to "bubble up"*/
List *symbols; /* list of symbols that live in this scope */ List *symbols; /* list of symbols that live in this scope */
@ -79,6 +42,6 @@ struct parser_s {
Token previous; Token previous;
}; };
bool compile(Emitter e, char *source); bool compile(Arena *a, Emitter e, char *source);
#endif #endif

4
test/vars.ul Executable file
View File

@ -0,0 +1,4 @@
int i = 122;
int j = 32;
print((i - j)); // prints ascii `Z`