uint16 NTYPE_MODULE = 0 uint16 NTYPE_EXPORT = 1 uint16 NTYPE_STRUCT = 2 uint16 NTYPE_TYPE = 3 uint16 NTYPE_ID = 4 uint16 NTYPE_BIN_OP = 5 uint16 NTYPE_PRE_OP = 6 uint16 NTYPE_POST_OP = 7 uint16 NTYPE_FUNCTION = 8 uint16 NTYPE_METHOD = 9 uint16 NTYPE_TLIST = 10 uint16 NTYPE_DLIST = 11 uint16 NTYPE_ELIST = 12 uint16 NTYPE_LITERAL = 13 uint16 NTYPE_KEY_TYPE = 14 uint16 NTYPE_ENUM = 15 uint16 NTYPE_DECL = 16 uint16 NTYPE_VLIST = 17 uint16 NTYPE_VALUE = 18 uint16 NTYPE_ASM = 998 struct Node { uint16 _type, ~uint8 data, utils.Vector sub } /; method Node /; init (uint16 _type, ~uint8 data) self.data = data self._type = _type Node n self.sub.init(len n) ;/ /; end _delete(self.data) /; loop (uint i = 0; i < self.sub.count) [i++] ~Node cur = self.sub.get(i) cur`.end() ;/ self.sub.end() ;/ ;/ /; _get_closing_delim(uint8 ch) [uint8] /; if (ch == '/' || ch == ';') return ';' ;; else if (ch == '(') return ')' ;; else if (ch == '[') return ']' ;; else if (ch == '{') return '}' ;/ return 0 ;/ /; _advance_check(~utils.File fin, ~Token tok, ~uint8 eq) [bool] /; if (tok`._type !== TTYPE_ERR && tok`.eq(eq) == true) Token tmp = produce_next_token(fin, tok`) tok`.end() tok` = tmp return true ;/ return false ;/ /; _ast_print_err (~Token tok, ~uint8 msg) _printf(msg) _printf(":\n\0") _printf(" \0") print_token(tok`) _printf("\n\0") ;/ # AST values /; _op_prefix(~Token op) [bool] int l = utils.strlen(op`.data) /; if (l !== 1) return false ;/ /; if (op`.data` == '-' || op`.data` == '!' || op`.data` == '~') return true ;/ return false ;/ /; _op_order(~Token op) [int] /; if (op`._type !== TTYPE_AUG) _ast_print_err(op, "[FATAL] [CMPERR] _op_order was called on a non-aug token\0") return 999 ;/ int l = utils.strlen(op`.data) /; if (l == 1) uint8 ch = op`.data` /; if (ch == '`') return 0 ;; else if (ch == '.') return 1 ;; else if (ch == '~') return 2 ;; else if (ch == '*' || ch == '/' || ch == '%') return 5 ;; else if (ch == '+' || ch == '-') return 6 ;; else if (ch == '!' || ch == '&' || ch == '|' || ch == '^') return 7 ;; else if (ch == '<' || ch == '>') return 8 ;; else if (ch == '=') return 10 ;/ ;; else if (l == 2) /; if (op`.data{0} == op`.data{1}) uint8 ch = op`.data` /; if (ch == '+' || ch == '-') return 3 ;; else if (ch == '<' || ch == '>') return 7 ;; else if (ch == '=') return 8 ;/ return 9 ;/ /; if (op`.data{1} == '<' || op`.data{1} == '>') return 8 ;; else if (op`.data{1} == '=') return 10 ;; else if (op`.data{0} == '!') return 7 ;/ ;; else if (l == 3) /; if (op`.eq("len\0")) return 4 ;; else if (op`.data{1} == '=') return 8 ;/ return 9 ;/ _ast_print_err(op, "[FATAL] [CMPERR] _op_order: Augment not implemented in ordering\0") return 999 ;/ /; _ast_value (~utils.File fin, ~Node mod, ~Token first) /; if (first`.eq("{\0") == true) _ast_list_value(fin, mod, first) ;/ ;/ # AST types /; _type_helper_pre (~utils.File fin, ~Node mod, ~Token first) /; loop (bool run = true; first`._type !== TTYPE_ERR && run == true) /; if (first`._type == TTYPE_AUG && first`.eq("~\0") == true) # Pointer Node ptr ptr.init(NTYPE_PRE_OP, first`.data) mod`.sub.push(~ptr) first` = produce_next_token(fin, first`) ;; else if (first`._type == TTYPE_DELIM && first`.eq("{\0") == true) # Array Node arr arr.init(NTYPE_PRE_OP, first`.data) first` = produce_next_token(fin, first`) /; if (first`._type == TTYPE_LITRL && is_numeric(first`.data`) == true) Node num num.init(NTYPE_LITERAL, first`.data) arr.sub.push(~num) first` = produce_next_token(fin, first`) /; if (first`.eq("}\0") == true) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;; else _ast_print_err(first, "Expected closing '}' after integer in type declaration\0") run = false ;/ ;; else if (first`.eq("}\0") == true) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;; else _ast_print_err(first, "Expected integer or '}' to define either a fixed sized array or pointer to unknown sized array\0") run = false ;/ mod`.sub.push(~arr) ;; else run = false ;/ ;/ ;/ /; _type_helper_func (~utils.File fin, ~Node mod, ~Token first) /; if (first`.eq("(\0") == true) _ast_list_type(fin, mod, first) ;/ /; if (first.eq("[\0") == true) _ast_list_type(fin, mod, first) ;/ ;/ /; _type_helper_usertype (~utils.File fin, ~Node mod, ~Token first) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_USRWD) Node utp utp.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) mod`.sub.push(~utp) /; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false) run = false ;; else Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;; else _ast_print_err(first, "Expected identifier in fully qualified type chain\0") run = false ;/ ;/ /; if (first`._type == TTYPE_DELIM && first`.eq("(\0") == true) _ast_list_type(fin, mod, first) ;/ ;/ /; _ast_type (~utils.File fin, ~Node mod, ~Token first) Node typ typ.init(NTYPE_TYPE, utils.strcpy("\0")) # Prefix values (~, {}, {#}) _type_helper_pre(fin, ~typ, first) # Check to see if this is a function pointer type /; if (first`.eq("void\0") == true) Node ktp ktp.init(NTYPE_ID, first`.data) typ.sub.push(~ktp) first` = produce_next_token(fin, first`) _type_helper_func(fin, ~typ, first) mod`.sub.push(~typ) return ;/ # user type or keytype /; if (first`._type == TTYPE_USRWD) _type_helper_usertype(fin, ~typ, first) ;; else if (first`._type == TTYPE_KEYTP) Node ktp ktp.init(NTYPE_ID, first`.data) typ.sub.push(~ktp) first` = produce_next_token(fin, first`) ;; else _ast_print_err(first, "Expected keytype or usertype when parsing type\0") mod`.sub.push(~typ) return ;/ # The ol' reference /; if (first`.eq("`\0")) Node post post.init(NTYPE_POST_OP, first`.data) typ.sub.push(~post) first` = produce_next_token(fin, first`) ;/ mod`.sub.push(~typ) ;/ # AST lists /; _ast_list_value (~utils.File fin, ~Node mod, ~Token first) Node list list.init(NTYPE_VLIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) /; loop (first`._type !== TTYPE_ERR && first`.data` !== end) _ast_type(fin, mod, first) /; if (_advance_check(fin, first, ",\0") == false && (first`._type !== TTYPE_DELIM || first`.data` !== end)) _ast_print_err(first, "Expected ',' to continue the value list or a closing delimiter\0") mod`.sub.push(~list) return ;/ ;/ mod`.sub.push(~list) Token next = produce_next_token(fin, first`) first`.end() first` = next ;/ /; _maybe_helper_decl (~utils.File fin, ~Node mod, ~Token first) # either a continuation of prev type or a new type then an id Token next = produce_next_token(fin, first`) /; if (next._type !== TTYPE_ERR && next.eq(",\0")) # Another id Node id id.init(NTYPE_ID, first`.data) mod`.sub.push(~id) first` = next return ;/ # have to parse as a type Node tp tp.init(NTYPE_TYPE, utils.strcpy("\0")) Node utmp utmp.init(NTYPE_ID, first`.data) tp.sub.push(~utmp) first` = next bool run = true /; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false) run = false ;; else next = produce_next_token(fin, first`) first`.end() first` = next ;/ # Adapted from _type_helper_usertype /; loop (run == true && first`._type !== TTYPE_ERR) /; if (first`._type == TTYPE_USRWD) Node utp utp.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) tp.sub.push(~utp) /; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false) run = false ;; else next = produce_next_token(fin, first`) first`.end() first` = next ;/ ;; else _ast_print_err(first, "Expected identifier in fully qualified type chain\0") run = false ;/ ;/ /; if (first`._type == TTYPE_DELIM && first`.eq("(\0") == true) _ast_list_type(fin, ~tp, first) ;/ mod`.sub.push(~tp) /; if (first`._type !== TTYPE_USRWD) _ast_print_err(first, "Expected identifier after user type in type list\0") return ;/ Node id id.init(NTYPE_ID, first`.data) mod`.sub.push(~id) first` = produce_next_token(fin, first`) ;/ /; _ast_list_decl (~utils.File fin, ~Node mod, ~Token first) Node list list.init(NTYPE_DLIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) bool seen = false /; loop (first`._type !== TTYPE_ERR && first`.data` !== end) /; if (seen == false || first`._type == TTYPE_KEYTP || first`.eq("~\0") == true || first`.eq("{\0") == true) _ast_type(fin, ~list, first) /; if (first`._type !== TTYPE_USRWD) /; if (seen == false) _ast_print_err(first, "Expected type then identifier as first items in declaration list\0") ;; else _ast_print_err(first, "Expected identifier after type in params/struct def\0") ;/ mod`.sub.push(~list) return ;/ seen = true Node id id.init(NTYPE_ID, first`.data) list.sub.push(~id) first` = produce_next_token(fin, first`) ;; else if (first`._type == TTYPE_USRWD) _maybe_helper_decl(fin, ~list, first) ;; else _ast_print_err(first, "Expected type or parameter name in declaration list\0") mod`.sub.push(~list) return ;/ /; if (_advance_check(fin, first, ",\0") == false && first`._type !== TTYPE_DELIM) _ast_print_err(first, "Expected ',' to continue the declaration list or a closing delimiter\0") mod`.sub.push(~list) return ;/ ;/ mod`.sub.push(~list) Token next = produce_next_token(fin, first`) first`.end() first` = next ;/ /; _ast_list_enum (~utils.File fin, ~Node mod, ~Token first) Node list list.init(NTYPE_ELIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) /; loop (first`._type !== TTYPE_ERR && first`.data` !== end) /; if (first`._type == TTYPE_USRWD || first`._type == TTYPE_KEYTP || first`.eq("~\0") == true || first`.eq("{\0") == true) Node enum_id enum_id.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) /; if (_advance_check(fin, first, "=\0")) _ast_value(fin, ~enum_id, first) ;/ list.sub.push(~enum_id) ;; else _ast_print_err(first, "Expected identifier in body of enum declaration\0") mod`.sub.push(~list) return ;/ /; if (_advance_check(fin, first, ",\0") == false && first`._type !== TTYPE_DELIM) _ast_print_err(first, "Expected ',' to continue the type list or a closing delimiter\0") mod`.sub.push(~list) return ;/ ;/ mod`.sub.push(~list) Token next = produce_next_token(fin, first`) first`.end() first` = next ;/ /; _ast_list_type (~utils.File fin, ~Node mod, ~Token first) Node list list.init(NTYPE_TLIST, first`.data) uint8 end = _get_closing_delim(first`.data`) first` = produce_next_token(fin, first`) /; loop (first`._type !== TTYPE_ERR && first`.data` !== end) /; if (first`._type == TTYPE_USRWD || first`._type == TTYPE_KEYTP || first`.eq("~\0") == true || first`.eq("{\0") == true) _ast_type(fin, ~list, first) ;; else _ast_print_err(first, "Expected type in type list\0") mod`.sub.push(~list) return ;/ /; if (_advance_check(fin, first, ",\0") == false && (first`._type !== TTYPE_DELIM || first`.data` !== end)) _ast_print_err(first, "Expected ',' to continue the type list or a closing delimiter\0") mod`.sub.push(~list) return ;/ ;/ mod`.sub.push(~list) Token next = produce_next_token(fin, first`) first`.end() first` = next ;/ # Method and function blocks /; _ast_method (~utils.File fin, ~Node mod, ~Token first) ;/ /; _ast_function (~utils.File fin, ~Node mod, ~Token first) ;/ # Top level directives /; _ast_import (~utils.File fin, ~Node mod, ~Token first) /; if (first`._type !== TTYPE_LITRL || first`.data` !== '"') _ast_print_err(first, "Expected string or import literal after 'import'\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ ~uint8 rel = utils.unquote_str(first`.data) utils.File imp = fin`.relative(rel) _delete(rel) rel = imp.path.to_cstr('/') _printf("Importing \0") _printf(rel) _printf("\n\0") _delete(rel) _ast_file(~imp, mod) imp.end() Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ /; _ast_asm (~utils.File fin, ~Node mod, ~Token first) /; if (first`._type !== TTYPE_LITRL || first`.data` !== '"') _ast_print_err(first, "Expected string literal after 'ast'\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ Node an an.init(NTYPE_ASM, utils.unquote_str(first`.data)) mod`.sub.push(~an) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ /; _ast_struct (~utils.File fin, ~Node mod, ~Token first) # Identifier check /; if (first`._type !== TTYPE_USRWD) _ast_print_err(first, "Expected new identifier for typedef after 'struct'\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ # Root struct node Node sct sct.init(NTYPE_STRUCT, first`.data) first` = produce_next_token(fin, first`) # Check for def list /; if (first`._type !== TTYPE_DELIM || first`.data` !== '{') _ast_print_err(first, "Expected new identifier for typedef after 'struct'\0") mod`.sub.push(~sct) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ # Parse deflist and push root node into module _ast_list_decl(fin, ~sct, first) mod`.sub.push(~sct) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ /; _ast_enum (~utils.File fin, ~Node mod, ~Token first) # Identifier check /; if (first`._type !== TTYPE_USRWD) _ast_print_err(first, "Expected new identifier for def after 'enum'\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ # Root struct node Node sct sct.init(NTYPE_ENUM, first`.data) first` = produce_next_token(fin, first`) # Check for enum type /; if (first`.data` == '[') _ast_list_type(fin, ~sct, first) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ # Check for def list /; if (first`._type !== TTYPE_DELIM || first`.data` !== '{') _ast_print_err(first, "Expected new identifier for typedef after 'struct'\0") mod`.sub.push(~sct) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp return ;/ # Parse deflist and push root node into module _ast_list_enum(fin, ~sct, first) mod`.sub.push(~sct) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ /; _ast_decl (~utils.File fin, ~Node mod, ~Token first) Node decl decl.init(NTYPE_DECL, utils.strcpy("\0")) _ast_type(fin, ~decl, first) /; loop (bool run = true; run == true) /; if (first`._type == TTYPE_USRWD) Node var var.init(NTYPE_ID, first`.data) first` = produce_next_token(fin, first`) /; if (first`.eq("=\0")) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp _ast_value(fin, ~var, first) ;/ decl.sub.push(~var) /; if (first`.eq(",\0") == false) run = false ;; else Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;; else _ast_print_err(first, "Expected variable name in declaration\0") run = false Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ mod`.sub.push(~decl) ;/ /; _ast_top_block(~utils.File fin, ~Node mod, ~Token first) Token blf = first` first` = produce_next_token(fin, first`) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (first`.eq("module\0") == true || first`.eq("export\0") == true) _ast_module(fin, mod, first) ;; else if (_advance_check(fin, first, "method\0") == true) _ast_method(fin, mod, first) ;; else if (first`._type == TTYPE_USRWD) _ast_function(fin, mod, first) ;; else _ast_print_err(first, "Expected module, method, or function for top level block\0") ;/ run = _advance_check(fin, first, ";;\0") /; if (run == false && first`.eq(";/\0") == false) _ast_print_err(first, "Block being skipped. Parsing will pick up after the end\0") ;/ ;/ /; loop (int deep = 1; deep > 0 && first`._type !== TTYPE_ERR) /; if (first`.eq(";/\0")) deep = deep - 1 ;; else if (first`.eq("/;\0")) deep = deep + 1 ;/ /; if (deep > 0) Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ /; if (_advance_check(fin, first`, ";/\0") == false) _ast_print_err(~blf, "Could not find closing ;/ for top block\0") _ast_print_err(first, "^^^ Last token before previous error\0") ;/ blf.end() ;/ /; _ast_module(~utils.File fin, ~Node mod, ~Token first) uint16 nt = NTYPE_MODULE /; if (_advance_check(fin, first, "export\0") == true) /; if (_advance_check(fin, first, "module\0") == false) _ast_print_err(first, "Expected 'module' keyword after 'export'\0") return ;/ nt = NTYPE_EXPORT ;; else if (_advance_check(fin, first, "module\0") == false) _printf("[FATAL] The following issue is with the compiler, not your program.\n\0") _printf("[FATAL] Please report the following issue to tnslc upstream.\n\0") _ast_print_err(first, "[FATAL] [CMPERR] Should only call _ast_module when 'module' or 'export' are seen\0") ;/ /; if (first`._type !== TTYPE_USRWD) _ast_print_err(first, "Expected module name (identifier) after 'module'\0") ;/ Node nmod nmod.init(nt, first`.data) first` = produce_next_token(fin, first`) /; loop (bool run = true; run == true && first`._type !== TTYPE_ERR) /; if (_advance_check(fin, first, "import\0") == true) _ast_import(fin, ~nmod, first) ;; else if (_advance_check(fin, first, "struct\0") == true) _ast_struct(fin, ~nmod, first) ;; else if (_advance_check(fin, first, "enum\0") == true) _ast_enum(fin, ~nmod, first) ;; else if (_advance_check(fin, first, "asm\0") == true) _ast_asm(fin, ~nmod, first) ;; else if (first`.eq("/;\0") == true) _ast_top_block(fin, ~nmod, first) ;; else if (first`._type == TTYPE_KEYTP || first`._type == TTYPE_USRWD || first`.eq("~\0") == true || first`.eq("{\0") == true) _ast_decl(fin, ~nmod, first) ;; else if (first`.eq(";/\0") == true) run = false ;; else _ast_print_err(first, "Expected 'import', 'struct', 'asm', block, or declaration in top level\0") Token tmp = produce_next_token(fin, first`) first`.end() first` = tmp ;/ ;/ mod`.sub.push(~nmod) ;/ /; _ast_file (~utils.File fin, ~Node mod) fin`.open() Token first = produce_first_token(fin) /; loop (first._type !== TTYPE_ERR) /; if (_advance_check(fin, ~first, "import\0") == true) _ast_import(fin, mod, ~first) ;; else if (_advance_check(fin, ~first, "struct\0") == true) _ast_struct(fin, mod, ~first) ;; else if (_advance_check(fin, ~first, "enum\0") == true) _ast_enum(fin, mod, ~first) ;; else if (_advance_check(fin, ~first, "asm\0") == true) _ast_asm(fin, mod, ~first) ;; else if (first.eq("/;\0") == true) _ast_top_block(fin, mod, ~first) ;; else if (first._type == TTYPE_KEYTP || first._type == TTYPE_USRWD || first.eq("~\0") == true || first.eq("{\0") == true) _ast_decl(fin, mod, ~first) ;; else _ast_print_err(~first, "Expected 'import', 'struct', 'asm', block, or declaration in top level\0") Token tmp = produce_next_token(fin, first) first.end() first = tmp ;/ ;/ fin`.close() ;/ /; generate_ast (~utils.File fin) [Node] Node out utils.Vector v v.init(1) out.init(NTYPE_MODULE, v.as_cstr()) _ast_file(fin, ~out) return out ;/ # # Print out the AST from a specific node # /; print_node_type (~Node n) /; if (n`._type == NTYPE_MODULE) _printf("MODULE\0") ;; else if (n`._type == NTYPE_EXPORT) _printf("EXPORT\0") ;; else if (n`._type == NTYPE_STRUCT) _printf("STRUCT\0") ;; else if (n`._type == NTYPE_TYPE) _printf("TYPE\0") ;; else if (n`._type == NTYPE_ID) _printf("ID\0") ;; else if (n`._type == NTYPE_BIN_OP) _printf("BIN_OP\0") ;; else if (n`._type == NTYPE_PRE_OP) _printf("PRE_OP\0") ;; else if (n`._type == NTYPE_POST_OP) _printf("POST_OP\0") ;; else if (n`._type == NTYPE_FUNCTION) _printf("FUNCTION\0") ;; else if (n`._type == NTYPE_METHOD) _printf("METHOD\0") ;; else if (n`._type == NTYPE_TLIST) _printf("TLIST\0") ;; else if (n`._type == NTYPE_DLIST) _printf("DLIST\0") ;; else if (n`._type == NTYPE_ELIST) _printf("ELIST\0") ;; else if (n`._type == NTYPE_LITERAL) _printf("LITERAL\0") ;; else if (n`._type == NTYPE_KEY_TYPE) _printf("KEY_TYPE\0") ;; else if (n`._type == NTYPE_ENUM) _printf("ENUM\0") ;; else if (n`._type == NTYPE_DECL) _printf("DECL\0") ;; else if (n`._type == NTYPE_VLIST) _printf("VLIST\0") ;; else if (n`._type == NTYPE_VALUE) _printf("VALUE\0") ;; else if (n`._type == NTYPE_ASM) _printf("ASM\0") ;/ ;/ /; print_node_head (~Node n) _printf("{ NODE_TYPE: \0") print_node_type(n) _printf(", DATA: \0") _printf(n`.data) _printf("\n\0") ;/ /; print_ast_rec(~Node n, uint depth) /; loop (int i = 0; i < depth) [i++] _printf(" \0") ;/ print_node_head(n) /; loop (uint i = 0; i < n`.sub.count) [i++] ~Node s = n`.sub.get(i) print_ast_rec(s, depth + 1) ;/ /; loop (int i = 0; i < depth) [i++] _printf(" \0") ;/ _printf("}\n\0") ;/ /; print_ast (~Node n) print_ast_rec(n, 0) ;/