diff --git a/lapis.c b/lapis.c index 78cd9e8..66d1aae 100644 --- a/lapis.c +++ b/lapis.c @@ -64,6 +64,13 @@ void lapis_node_print(const lapis_node_t *nodes, size_t idx) { if ( nodes[idx].value.type == LAPIS_TTYPE_OPER ) putchar(')'); } +size_t lapis_node_count(const lapis_node_t *nodes, size_t idx) { + size_t count = 1; + if ( nodes[idx].lhs_idx != SIZE_MAX ) count += lapis_node_count(nodes, nodes[idx].lhs_idx); + if ( nodes[idx].rhs_idx != SIZE_MAX ) count += lapis_node_count(nodes, nodes[idx].rhs_idx); + return count; +} + /// Free a token's internal buffer if it has one void lapis_token_free(lapis_token_t *token) { if ( token->type == LAPIS_TTYPE_IDENT || token->type == LAPIS_TTYPE_OPER ) { @@ -239,21 +246,31 @@ ERROR: return NULL; } -void lapis_parse(FILE *f) { +lapis_node_t *lapis_parse_expr(size_t *nnodes, FILE *f) { + + lapis_token_t *tokens = NULL; + int64_t *oper_priorities = NULL; + uint8_t *oper_arg_form = NULL; + lapis_node_t *nodes = NULL; size_t ntokens=0; - lapis_token_t *tokens = lapis_parse_tokens(&ntokens, stdin); - if ( tokens == NULL ) return; + tokens = lapis_parse_tokens(&ntokens, stdin); + if ( tokens == NULL ) goto ERROR; - int64_t *oper_priorities = malloc( ntokens * sizeof(int64_t) ); - if ( oper_priorities == NULL ) return; + oper_priorities = malloc( ntokens * sizeof(int64_t) ); + if ( oper_priorities == NULL ) goto ERROR; // 0 - no args, 1 - lhs, 2 - rhs, 3 - both - uint8_t *oper_arg_form = malloc( ntokens * sizeof(uint8_t) ); - if ( oper_arg_form == NULL ) return; + oper_arg_form = malloc( ntokens * sizeof(uint8_t) ); + if ( oper_arg_form == NULL ) goto ERROR; memset(oper_arg_form, 0, ntokens); + size_t num_nodes = 0; + +#define ADD_NODE(NODE) \ + (num_nodes++, nodes = realloc(nodes, num_nodes * sizeof(lapis_node_t)), nodes[num_nodes-1] = NODE) + int64_t paren_level = 0; for (size_t n=0; n < ntokens; n++) { @@ -271,7 +288,7 @@ void lapis_parse(FILE *f) { fputs("ERROR: unknown priority for operator '", stderr); fwrite(tokens[n].str, 1, tokens[n].len, stderr); fputs("'\n", stderr); - return; + goto ERROR; case 1ul*',': oper_priorities[n] = 1; oper_arg_form[n] = 3; @@ -365,7 +382,7 @@ void lapis_parse(FILE *f) { case 1ul*')': if ( paren_level == 0 ) { fprintf(stderr, "ERROR(%d): unexpected ')'\n", __LINE__); - return; + goto ERROR; } // clear the ')' as being an operator oper_priorities[n] = -1; @@ -377,12 +394,6 @@ void lapis_parse(FILE *f) { if ( oper_priorities[n] != -1 ) oper_priorities[n] += paren_level * 16; } - size_t nnodes = 0; - lapis_node_t *nodes = NULL; - -#define ADD_NODE(NODE) \ - (nnodes++, nodes = realloc(nodes, nnodes * sizeof(lapis_node_t)), nodes[nnodes-1] = NODE) - while (1) { // seek the next highest priority operator @@ -422,14 +433,14 @@ void lapis_parse(FILE *f) { if ( n == max_prior_idx || tokens[n].type == LAPIS_TTYPE_NONE ) { printf("ERROR: bad logic line #%d\n", __LINE__); - return; + goto ERROR; } if ( tokens[n].type == LAPIS_TTYPE_OPER ) { if ( oper_priorities[n] >= -1 ) { printf("ERROR: bad logic line #%d\n", __LINE__); - return; + goto ERROR; } // This is very weird, BUT as a vile hack I encode the node index @@ -441,7 +452,7 @@ void lapis_parse(FILE *f) { if ( node_idx < 0 ) { printf("ERROR: bad logic line #%d\n", __LINE__); - return; + goto ERROR; } node.lhs_idx = node_idx; @@ -458,7 +469,7 @@ void lapis_parse(FILE *f) { }; ADD_NODE( tmpnode ); - node.lhs_idx = nnodes-1; + node.lhs_idx = num_nodes-1; } // clear token type to prevent reuse @@ -475,14 +486,14 @@ void lapis_parse(FILE *f) { if ( n == max_prior_idx || tokens[n].type == LAPIS_TTYPE_NONE ) { printf("ERROR: bad logic line #%d\n", __LINE__); - return; + goto ERROR; } if ( tokens[n].type == LAPIS_TTYPE_OPER ) { if ( oper_priorities[n] >= -1 ) { printf("ERROR: bad logic line #%d\n", __LINE__); - return; + goto ERROR; } // This is very weird, BUT as a vile hack I encode the node index @@ -494,7 +505,7 @@ void lapis_parse(FILE *f) { if ( node_idx < 0 ) { printf("ERROR: bad logic line #%d\n", __LINE__); - return; + goto ERROR; } node.rhs_idx = node_idx; @@ -511,7 +522,7 @@ void lapis_parse(FILE *f) { }; ADD_NODE( tmpnode ); - node.rhs_idx = nnodes-1; + node.rhs_idx = num_nodes-1; } // clear token type to prevent reuse @@ -519,7 +530,7 @@ void lapis_parse(FILE *f) { } ADD_NODE( node ); - int64_t idx = nnodes - 1; + int64_t idx = num_nodes - 1; printf("add oper token %lu w/ priority %ld as node %ld\n", max_prior_idx, oper_priorities[max_prior_idx], idx); @@ -533,10 +544,26 @@ void lapis_parse(FILE *f) { if ( update_rhs_idx != SIZE_MAX ) oper_priorities[update_rhs_idx] = -idx - 2; } - //TODO cleanup allocs, error handling, ';' or w/e to **separate expressions** + if ( lapis_node_count(nodes, num_nodes-1) != num_nodes ) { + // NOTE: this likely indicates a priority conflict of some kind between operators + fprintf(stderr, "ERROR[%d]: Unknown syntax error! Orphan nodes detected!\n", __LINE__); + goto ERROR; + } - lapis_node_print(nodes, nnodes-1); - putchar('\n'); + if ( tokens != NULL ) free( tokens ); + if ( oper_priorities != NULL ) free( oper_priorities ); + if ( oper_arg_form != NULL ) free( oper_arg_form ); + + *nnodes = num_nodes; + return nodes; +ERROR: + if ( tokens != NULL ) free( tokens ); + if ( oper_priorities != NULL ) free( oper_priorities ); + if ( oper_arg_form != NULL ) free( oper_arg_form ); + if ( nodes != NULL ) free( nodes ); + + *nnodes = 0; + return NULL; } int main() { @@ -564,7 +591,16 @@ int main() { } } #else - lapis_parse(stdin); + while (1) { + + size_t nnodes; + lapis_node_t *nodes = lapis_parse_expr(&nnodes, stdin); + + if ( nnodes == 0 ) break; + + lapis_node_print(nodes, nnodes-1); + putchar('\n'); + } #endif return 0;