From 8e430a9d4652e40dd6cbe9792d0b5230a6b31902 Mon Sep 17 00:00:00 2001 From: zongor Date: Wed, 8 Apr 2026 22:29:47 -0700 Subject: [PATCH] merge emitters, add uxn emitter, update c emitter, update simple to use raw ascii for example --- arch/linux/main.c | 29 +++- build | 10 +- emit.h | 118 ++++++++-------- emit/c/emit.c | 164 +++++++++++++-------- emit/uxn/emit.c | 346 +++++++++++++++++++++++++++++++++++++++++++++ emit/uxntal/emit.c | 257 --------------------------------- lexer.c | 5 +- parser.c | 96 ++++++++----- parser.h | 5 +- test/simple.ul | 2 +- 10 files changed, 600 insertions(+), 432 deletions(-) create mode 100644 emit/uxn/emit.c delete mode 100644 emit/uxntal/emit.c diff --git a/arch/linux/main.c b/arch/linux/main.c index a1815aa..fe6c0ce 100644 --- a/arch/linux/main.c +++ b/arch/linux/main.c @@ -40,14 +40,37 @@ static char* readFile(const char* path) { return buffer; } +void print_help() { + printf("Usage: undar [options] file...\nOptions:\n\t-emit={c|u}\tEmitter output, currently C source and Uxn binary.\n\n"); +} + int main(int argc, char **argv) { - if(argc != 2) return EXIT_FAILURE; + if (argc > 1 && (seq(argv[1], "--help") || seq(argv[1], "-h"))) { + print_help(); + return EXIT_SUCCESS; + } - char* source = readFile(argv[1]); - compile(source); + if(argc != 3) { + print_help(); + return EXIT_FAILURE; + } + + Emitter e; + if (seq(argv[1], "-emit=c")) { + e = c_emitter(); + } else if (seq(argv[1], "-emit=u")) { + e = uxn_emitter(); + } else { + printf("unknown emitter type\n"); + return EXIT_FAILURE; + } + + char* source = readFile(argv[2]); + compile(e, source); free(source); + printf("\n"); return EXIT_SUCCESS; } diff --git a/build b/build index 1e95c7d..958a7d2 100755 --- a/build +++ b/build @@ -10,10 +10,6 @@ if [ -z $MODE ]; then MODE='debug' fi -if [ -z $EMIT ]; then - EMIT='c' -fi - case $ARCH in "linux") if [ -z $CC ]; then @@ -27,7 +23,7 @@ esac # setup dirs SRC_DIR=./arch/$ARCH -BUILD_DIR=./out/$EMIT/$ARCH +BUILD_DIR=./out/$ARCH GEN_DIR=$BUILD_DIR/gen TOOL_SRC=tools/file2header.c TOOL_EXE=$BUILD_DIR/file2header @@ -85,10 +81,10 @@ ${CC} -c parser.c -o $BUILD_DIR/parser.o $VM_BUILD_FLAGS # Set up the final build command case $ARCH in "linux") - BUILD_CMD="$CC -o $BUILD_DIR/undar $SRC_DIR/main.c emit/$EMIT/emit.c $LINK_FLAGS $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/parser.o $BUILD_FLAGS $LINK_FLAGS" + BUILD_CMD="$CC -o $BUILD_DIR/undar $SRC_DIR/main.c emit/c/emit.c emit/uxn/emit.c $LINK_FLAGS $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/parser.o $BUILD_FLAGS $LINK_FLAGS" ;; "web") - BUILD_CMD="$CC $SRC_DIR/main.c emit/$EMIT/emit.c $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/parser.o -o $BUILD_DIR/undar.html $BUILD_FLAGS $LINK_FLAGS" + BUILD_CMD="$CC $SRC_DIR/main.c emit/c/emit.c emit/uxn/emit.c $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/parser.o -o $BUILD_DIR/undar.html $BUILD_FLAGS $LINK_FLAGS" ;; esac diff --git a/emit.h b/emit.h index 1002f6d..f600d86 100644 --- a/emit.h +++ b/emit.h @@ -3,74 +3,72 @@ #include "libc.h" -typedef enum expression_config_e { +typedef enum notation_type_e { PREFIX, INFIX, POSTFIX -} ExpressionConfig; +} NotationType; -typedef enum output_config_e { +typedef enum output_type_e { BINARY, TEXT -} OutputConfig; +} OutputType; -ExpressionConfig expression_config(); -OutputConfig output_config(); +typedef void (*VoidArgEmit)(); +typedef void (*StrArgEmit)(const char *str, i32 length); -/** - * Prolog is for all of the "setup" boilerplate - */ -void prolog(); +typedef struct emitter_s Emitter; +struct emitter_s { + NotationType notation; + OutputType output; + VoidArgEmit prolog; + VoidArgEmit epilogue; + VoidArgEmit emit_add; + VoidArgEmit emit_sub; + VoidArgEmit emit_mul; + VoidArgEmit emit_div; + VoidArgEmit emit_lt; + VoidArgEmit emit_le; + VoidArgEmit emit_gt; + VoidArgEmit emit_ge; + VoidArgEmit emit_ne; + VoidArgEmit emit_eq; + VoidArgEmit emit_false; + VoidArgEmit emit_true; + VoidArgEmit emit_nil; + VoidArgEmit emit_void; + StrArgEmit emit_int; + StrArgEmit emit_nat; + StrArgEmit emit_real; + StrArgEmit emit_byte; + StrArgEmit emit_str; + VoidArgEmit emit_bool_type; + VoidArgEmit emit_byte_type; + VoidArgEmit emit_int_type; + VoidArgEmit emit_nat_type; + VoidArgEmit emit_real_type; + VoidArgEmit emit_str_type; + VoidArgEmit emit_u8_type; + VoidArgEmit emit_i8_type; + VoidArgEmit emit_i16_type; + VoidArgEmit emit_u16_type; + VoidArgEmit emit_i32_type; + VoidArgEmit emit_u32_type; + VoidArgEmit emit_f32_type; + VoidArgEmit emit_array; + VoidArgEmit emit_function; + VoidArgEmit emit_plex; + VoidArgEmit emit_method; + VoidArgEmit emit_trait; + VoidArgEmit emit_const; + VoidArgEmit emit_print; + VoidArgEmit emit_neg; + VoidArgEmit emit_not; + VoidArgEmit emit_open_paren; + VoidArgEmit emit_close_paren; +}; -/** - * Prolog is for all of the "cleanup" boilerplate - */ -void epilogue(); - -/** - * Emitters - */ -void emit_add(); -void emit_sub(); -void emit_mul(); -void emit_div(); -void emit_lt(); -void emit_le(); -void emit_gt(); -void emit_ge(); -void emit_ne(); -void emit_eq(); -void emit_false(); -void emit_true(); -void emit_nil(); -void emit_void(); -void emit_int(const char *str, i32 length); -void emit_nat(const char *str, i32 length); -void emit_real(const char *str, i32 length); -void emit_str(const char *str, i32 length); -void emit_bool_type(); -void emit_byte_type(); -void emit_int_type(); -void emit_nat_type(); -void emit_real_type(); -void emit_str_type(); -void emit_u8_type(); -void emit_i8_type(); -void emit_i16_type(); -void emit_u16_type(); -void emit_i32_type(); -void emit_u32_type(); -void emit_f32_type(); -void emit_array(); -void emit_function(); -void emit_plex(); -void emit_method(); -void emit_trait(); -void emit_const(); -void emit_print(); -void emit_neg(); -void emit_not(); -void emit_open_paren(); -void emit_close_paren(); +Emitter c_emitter(); +Emitter uxn_emitter(); #endif \ No newline at end of file diff --git a/emit/c/emit.c b/emit/c/emit.c index 31ad2c4..362a979 100644 --- a/emit/c/emit.c +++ b/emit/c/emit.c @@ -1,258 +1,304 @@ #include "../../emit.h" #include -ExpressionConfig -expression_config() +void +c_prolog() { - return INFIX; -} - -OutputConfig -output_config() -{ - return TEXT; } void -prolog() +c_epilogue() { - } void -epilogue() -{ - -} - -void -emit_add() +c_emit_add() { printf("+ "); } void -emit_sub() +c_emit_sub() { printf("- "); } void -emit_mul() +c_emit_mul() { printf("* "); } void -emit_div() +c_emit_div() { printf("/ "); } void -emit_lt() +c_emit_lt() { printf("< "); } void -emit_le() +c_emit_le() { printf("<= "); } void -emit_gt() +c_emit_gt() { printf("> "); } void -emit_ge() +c_emit_ge() { printf(">= "); } void -emit_ne() +c_emit_ne() { printf("!= "); } void -emit_eq() +c_emit_eq() { printf("== "); } void -emit_false() +c_emit_false() { printf("false "); } void -emit_true() +c_emit_true() { printf("true "); } void -emit_nil() +c_emit_nil() { printf("NULL "); } void -emit_neg() +c_emit_neg() { printf("-"); } void -emit_not() +c_emit_not() { printf("!"); } void -emit_void() +c_emit_void() { } void -emit_bool_type() +c_emit_bool_type() { } void -emit_byte_type() +c_emit_byte_type() { } void -emit_int_type() +c_emit_int_type() { } void -emit_nat_type() +c_emit_nat_type() { } void -emit_real_type() +c_emit_real_type() { } void -emit_str_type() +c_emit_str_type() { } void -emit_u8_type() +c_emit_u8_type() { } void -emit_i8_type() +c_emit_i8_type() { } void -emit_i16_type() +c_emit_i16_type() { } void -emit_u16_type() +c_emit_u16_type() { } void -emit_i32_type() +c_emit_i32_type() { } void -emit_u32_type() +c_emit_u32_type() { } void -emit_f32_type() +c_emit_f32_type() { } void -emit_int(const char *str, i32 length) +c_emit_int(const char *str, i32 length) { printf("%.*s ", length, str); } void -emit_nat(const char *str, i32 length) +c_emit_nat(const char *str, i32 length) { printf("%.*s ", length, str); } void -emit_real(const char *str, i32 length) +c_emit_real(const char *str, i32 length) { printf("%.*s ", length, str); } void -emit_str(const char *str, i32 length) +c_emit_byte(const char *str, i32 length) { printf("%.*s ", length, str); } void -emit_array() +c_emit_str(const char *str, i32 length) +{ + printf("%.*s ", length, str); +} + +void +c_emit_array() { } void -emit_function() +c_emit_function() { } void -emit_plex() +c_emit_plex() { } void -emit_method() +c_emit_method() { } void -emit_trait() +c_emit_trait() { } void -emit_const() +c_emit_const() { } void -emit_print() +c_emit_print() { printf("printf(\"%%s\", "); } void -emit_open_paren() +c_emit_open_paren() { printf("("); } void -emit_close_paren() +c_emit_close_paren() { printf(")"); } + +Emitter +c_emitter() +{ + return (Emitter){ + INFIX, + TEXT, + c_prolog, + c_epilogue, + c_emit_add, + c_emit_sub, + c_emit_mul, + c_emit_div, + c_emit_lt, + c_emit_le, + c_emit_gt, + c_emit_ge, + c_emit_ne, + c_emit_eq, + c_emit_false, + c_emit_true, + c_emit_nil, + c_emit_void, + c_emit_int, + c_emit_nat, + c_emit_real, + c_emit_byte, + c_emit_str, + c_emit_bool_type, + c_emit_byte_type, + c_emit_int_type, + c_emit_nat_type, + c_emit_real_type, + c_emit_str_type, + c_emit_u8_type, + c_emit_i8_type, + c_emit_i16_type, + c_emit_u16_type, + c_emit_i32_type, + c_emit_u32_type, + c_emit_f32_type, + c_emit_array, + c_emit_function, + c_emit_plex, + c_emit_method, + c_emit_trait, + c_emit_const, + c_emit_print, + c_emit_neg, + c_emit_not, + c_emit_open_paren, + c_emit_close_paren, + }; +} \ No newline at end of file diff --git a/emit/uxn/emit.c b/emit/uxn/emit.c new file mode 100644 index 0000000..a24ddfa --- /dev/null +++ b/emit/uxn/emit.c @@ -0,0 +1,346 @@ +#include "../../emit.h" +#include +#include + +#define UXN_OP_2 (1 << 5) +#define UXN_OP_R (1 << 6) +#define UXN_OP_K (1 << 7) + +enum uxn_opcode { + /* Stack I */ /* Logic */ /* Memory I */ /* Arithmetic*/ + BRK = 0x00, EQU = 0x08, LDZ = 0x10, 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 */ + SWP = 0x04, JMP = 0x0C, LDA = 0x14, 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, +}; + +/* +https://rosettacode.org/wiki/Bitwise_operations#Uxntal + +%not { #ff EOR } +%and { AND } +%or { ORA } +%xor { EOR } +%shl { #40 SFT SFT } +%shr { SFT } +%rol { #40 SFT #00 ROT ROT SFT2 ORA } +%ror { SWP #00 ROT SFT2 ORA } +*/ + +void +uxn_prolog() +{ + +} + +void +uxn_epilogue() +{ + +} + +void +uxn_emit_add() +{ + printf("ADD2 "); +} + +void +uxn_emit_sub() +{ + printf("SUB2 "); +} + +void +uxn_emit_mul() +{ + printf("MUL2 "); +} + +void +uxn_emit_div() +{ + printf("DIV2 "); +} + +void +uxn_emit_lt() +{ + printf("LTH2 "); +} + +void +uxn_emit_le() +{ + printf("ROT SWP LTH ?{ LTH #00 EQU JMPr } GTH JMPr "); +} + +void +uxn_emit_gt() +{ + printf("GTH2 "); +} + +void +uxn_emit_ge() +{ + printf("ROT SWP GTH ?{ GTH #00 EQU JMPr } LTH JMPr "); +} + +void +uxn_emit_ne() +{ + printf("NEQ2 "); +} + +void +uxn_emit_eq() +{ + printf("EQU2 "); +} + +void +uxn_emit_false() +{ + printf("#0000 "); +} + +void +uxn_emit_true() +{ + printf("#0001 "); +} + +void +uxn_emit_nil() +{ + printf("#0000 "); +} + +void +uxn_emit_neg() +{ + printf("#0000 SUB2 "); +} + +void +uxn_emit_not() +{ + printf("#FFFF EOR2 "); +} + +void +uxn_emit_void() +{ +} + +void +uxn_emit_bool_type() +{ +} + +void +uxn_emit_byte_type() +{ +} + +void +uxn_emit_int_type() +{ +} + +void +uxn_emit_nat_type() +{ +} + +void +uxn_emit_real_type() +{ +} + +void +uxn_emit_str_type() +{ +} + +void +uxn_emit_u8_type() +{ +} + +void +uxn_emit_i8_type() +{ +} + +void +uxn_emit_i16_type() +{ +} + +void +uxn_emit_u16_type() +{ +} + +void +uxn_emit_i32_type() +{ +} + +void +uxn_emit_u32_type() +{ +} + +void +uxn_emit_f32_type() +{ +} + +void +uxn_emit_int(const char *str, i32 length) +{ + i32 i = (i32)strtol(str, nil, 10); + printf("#%04x ", i); + USED(length); +} + +void +uxn_emit_nat(const char *str, i32 length) +{ + u32 i = (u32)strtol(str, nil, 10); + printf("#%04x ", i); + USED(length); +} + +void +uxn_emit_real(const char *str, i32 length) +{ + USED(str); + USED(length); + /// TODO: implement this +} + +void +uxn_emit_byte(const char *str, i32 length) +{ + u8 i = (u8)strtol(str, nil, 10); + printf("#%04x ", i); + USED(length); +} + +void +uxn_emit_str(const char *str, i32 length) +{ + printf("\"%.*s ", length, str); +} + +void +uxn_emit_array() +{ +} + +void +uxn_emit_function() +{ +} + +void +uxn_emit_plex() +{ +} + +void +uxn_emit_method() +{ +} + +void +uxn_emit_trait() +{ +} + +void +uxn_emit_const() +{ +} + +void +uxn_emit_print() +{ + printf("#18 DEO "); +} + +void +uxn_emit_open_paren() +{ + +} +void +uxn_emit_close_paren() +{ + +} + +Emitter +uxn_emitter() +{ + return (Emitter){ + POSTFIX, + BINARY, + uxn_prolog, + uxn_epilogue, + uxn_emit_add, + uxn_emit_sub, + uxn_emit_mul, + uxn_emit_div, + uxn_emit_lt, + uxn_emit_le, + uxn_emit_gt, + uxn_emit_ge, + uxn_emit_ne, + uxn_emit_eq, + uxn_emit_false, + uxn_emit_true, + uxn_emit_nil, + uxn_emit_void, + uxn_emit_int, + uxn_emit_nat, + uxn_emit_real, + uxn_emit_byte, + uxn_emit_str, + uxn_emit_bool_type, + uxn_emit_byte_type, + uxn_emit_int_type, + uxn_emit_nat_type, + uxn_emit_real_type, + uxn_emit_str_type, + uxn_emit_u8_type, + uxn_emit_i8_type, + uxn_emit_i16_type, + uxn_emit_u16_type, + uxn_emit_i32_type, + uxn_emit_u32_type, + uxn_emit_f32_type, + uxn_emit_array, + uxn_emit_function, + uxn_emit_plex, + uxn_emit_method, + uxn_emit_trait, + uxn_emit_const, + uxn_emit_print, + uxn_emit_neg, + uxn_emit_not, + uxn_emit_open_paren, + uxn_emit_close_paren, + }; +} \ No newline at end of file diff --git a/emit/uxntal/emit.c b/emit/uxntal/emit.c deleted file mode 100644 index 70054e4..0000000 --- a/emit/uxntal/emit.c +++ /dev/null @@ -1,257 +0,0 @@ -#include "../../emit.h" -#include - -ExpressionConfig -expression_config() -{ - return POSTFIX; -} - -OutputConfig -output_config() -{ - return TEXT; -} - -void -prolog() -{ - -} - -void -epilogue() -{ - -} - -void -emit_add() -{ - printf("+ "); -} - -void -emit_sub() -{ - printf("- "); -} - -void -emit_mul() -{ - printf("* "); -} - -void -emit_div() -{ - printf("/ "); -} - -void -emit_lt() -{ - printf("< "); -} - -void -emit_le() -{ - printf("<= "); -} - -void -emit_gt() -{ - printf("> "); -} - -void -emit_ge() -{ - printf(">= "); -} - -void -emit_ne() -{ - printf("!= "); -} - -void -emit_eq() -{ - printf("== "); -} - -void -emit_false() -{ - printf("false "); -} - -void -emit_true() -{ - printf("true "); -} - -void -emit_nil() -{ - printf("NULL "); -} - -void -emit_neg() -{ - printf("-"); -} - -void -emit_not() -{ - printf("!"); -} - -void -emit_void() -{ -} - -void -emit_bool_type() -{ -} - -void -emit_byte_type() -{ -} - -void -emit_int_type() -{ -} - -void -emit_nat_type() -{ -} - -void -emit_real_type() -{ -} - -void -emit_str_type() -{ -} - -void -emit_u8_type() -{ -} - -void -emit_i8_type() -{ -} - -void -emit_i16_type() -{ -} - -void -emit_u16_type() -{ -} - -void -emit_i32_type() -{ -} - -void -emit_u32_type() -{ -} - -void -emit_f32_type() -{ -} - -void -emit_int(const char *str, i32 length) -{ - printf("%.*s ", length, str); -} - -void -emit_nat(const char *str, i32 length) -{ - printf("%.*s ", length, str); -} - -void -emit_real(const char *str, i32 length) -{ - printf("%.*s ", length, str); -} - -void -emit_str(const char *str, i32 length) -{ - printf("%.*s ", length, str); -} - -void -emit_array() -{ -} - -void -emit_function() -{ -} - -void -emit_plex() -{ -} - -void -emit_method() -{ -} - -void -emit_trait() -{ -} - -void -emit_const() -{ -} - -void -emit_print() -{ - printf("printf(\"%%s\", "); -} - -void -emit_open_paren() -{ - printf("("); -} -void -emit_close_paren() -{ - printf(")"); -} diff --git a/lexer.c b/lexer.c index 41c00e2..05061d2 100644 --- a/lexer.c +++ b/lexer.c @@ -132,8 +132,9 @@ skip_whitespace() static TokenType check_keyword(i32 start, i32 length, const char *rest, TokenType type) { - if(lexer.current - lexer.start == start + length && - sleq(lexer.start + start, rest, length) == 0) { + i32 s1 = lexer.current - lexer.start; + i32 s2 = start + length; + if(s1 == s2 && sleq(lexer.start + start, rest, length)) { return type; } diff --git a/parser.c b/parser.c index 814d590..1fab57b 100644 --- a/parser.c +++ b/parser.c @@ -1,6 +1,7 @@ #include "parser.h" #include "emit.h" +Emitter emitter; Parser parser; /**************************************************** @@ -116,43 +117,48 @@ binary() TokenType operatorType = parser.previous.type; ParseRule *rule = get_rule(operatorType); + if (emitter.notation == POSTFIX) { + parse_precedence((Precedence)(rule->precedence + 1)); + } + switch(operatorType) { case TOKEN_BANG_EQ: - emit_ne(); + emitter.emit_ne(); break; case TOKEN_EQ_EQ: - emit_eq(); + emitter.emit_eq(); break; case TOKEN_GT: - emit_ge(); + emitter.emit_ge(); break; case TOKEN_GTE: - emit_ge(); + emitter.emit_ge(); break; case TOKEN_LT: - emit_lt(); + emitter.emit_lt(); break; case TOKEN_LTE: - emit_le(); + emitter.emit_le(); break; case TOKEN_PLUS: - emit_add(); + emitter.emit_add(); break; case TOKEN_MINUS: - emit_sub(); + emitter.emit_sub(); break; case TOKEN_STAR: - emit_mul(); + emitter.emit_mul(); break; case TOKEN_SLASH: - emit_div(); + emitter.emit_div(); break; default: return; } - /* Move to above switch statement for postfix */ - parse_precedence((Precedence)(rule->precedence + 1)); + if (emitter.notation == INFIX) { + parse_precedence((Precedence)(rule->precedence + 1)); + } } static void @@ -160,13 +166,13 @@ literal() { switch(parser.previous.type) { case TOKEN_KEYWORD_FALSE: - emit_false(); + emitter.emit_false(); break; case TOKEN_KEYWORD_TRUE: - emit_true(); + emitter.emit_true(); break; case TOKEN_KEYWORD_NIL: - emit_nil(); + emitter.emit_nil(); break; default: return; @@ -183,25 +189,25 @@ static void declaration() { if(match(TOKEN_TYPE_INT)) { - emit_int_type(); + emitter.emit_int_type(); } else if(match(TOKEN_TYPE_NAT)) { - emit_nat_type(); + emitter.emit_nat_type(); } else if(match(TOKEN_TYPE_REAL)) { - emit_real_type(); + emitter.emit_real_type(); } else if(match(TOKEN_TYPE_STR)) { - emit_str_type(); + emitter.emit_str_type(); } else if(match(TOKEN_TYPE_BOOL)) { - emit_bool_type(); + emitter.emit_bool_type(); } else if(match(TOKEN_TYPE_BYTE)) { - emit_byte_type(); + emitter.emit_byte_type(); } else if(match(TOKEN_TYPE_U8)) { - emit_u8_type(); + emitter.emit_u8_type(); } else if(match(TOKEN_TYPE_I8)) { - emit_i8_type(); + emitter.emit_i8_type(); } else if(match(TOKEN_TYPE_U16)) { - emit_u16_type(); + emitter.emit_u16_type(); } else if(match(TOKEN_TYPE_I16)) { - emit_i16_type(); + emitter.emit_i16_type(); } else if(match(TOKEN_IDENTIFIER)) { /** * maybe a Plex? @@ -213,56 +219,67 @@ declaration() statement(); } +static void print_statement() { + expression(); + consume(TOKEN_SEMICOLON); + emitter.emit_print(); +} + static void statement() { - if(match(TOKEN_KEYWORD_PRINT)) - emit_print(); - else + if(match(TOKEN_KEYWORD_PRINT)) { + print_statement(); + } else { expression(); + } } static void grouping() { - emit_open_paren(); + emitter.emit_open_paren(); expression(); - emit_close_paren(); + emitter.emit_close_paren(); consume(TOKEN_RPAREN); } static void number() { - emit_int(parser.previous.start, parser.previous.length); + emitter.emit_int(parser.previous.start, parser.previous.length); } static void string() { - emit_str(parser.previous.start, parser.previous.length); + emitter.emit_str(parser.previous.start, parser.previous.length); } static void unary() { TokenType operatorType = parser.previous.type; + if (emitter.notation == POSTFIX) { + parse_precedence(PREC_UNARY); + } switch(operatorType) { case TOKEN_MINUS: - emit_neg(); + emitter.emit_neg(); break; case TOKEN_BANG: - emit_not(); + emitter.emit_not(); break; default: return; } - /* Move to above switch statement for postfix */ - parse_precedence(PREC_UNARY); + if (emitter.notation == INFIX) { + parse_precedence(PREC_UNARY); + } } ParseRule rules[] = { @@ -375,16 +392,17 @@ get_rule(TokenType type) } bool -compile(char *source) +compile(Emitter e, char *source) { + emitter = e; init_lexer(source); advance(); - prolog(); + emitter.prolog(); while(!match(TOKEN_EOF)) declaration(); - epilogue(); + emitter.epilogue(); return true; } diff --git a/parser.h b/parser.h index 52435b8..2ceb573 100644 --- a/parser.h +++ b/parser.h @@ -79,9 +79,6 @@ struct parser_s { Token previous; }; -bool compile(char *source); - -extern void emit_return(); -extern void emit_constant(); +bool compile(Emitter e, char *source); #endif diff --git a/test/simple.ul b/test/simple.ul index 6b38962..2ae047b 100755 --- a/test/simple.ul +++ b/test/simple.ul @@ -1 +1 @@ -print((1.0 + 1.0) as str); +print((122 - 32)); // prints ascii `Z`