finish expr parse function; cleanup allocs and error handling

This commit is contained in:
icst 2024-06-17 21:57:42 -04:00
parent 4c17bf96bf
commit f5db5076db

92
lapis.c
View file

@ -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;