2018-02-10 22:40:34 -08:00
|
|
|
#include "parser.h"
|
2018-02-11 22:32:42 -08:00
|
|
|
#include "util.h"
|
|
|
|
#include "result.h"
|
2018-02-10 22:40:34 -08:00
|
|
|
#include "lexer.h"
|
|
|
|
#include <stdlib.h>
|
2018-02-11 13:42:05 -08:00
|
|
|
#include <string.h>
|
2018-02-10 22:40:34 -08:00
|
|
|
|
2018-02-10 22:17:08 -08:00
|
|
|
struct parser_state {
|
|
|
|
ll_node* current_node;
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_lexer_match* current_match;
|
2018-02-10 22:17:08 -08:00
|
|
|
const char* string;
|
2018-02-11 22:23:02 -08:00
|
|
|
libab_table* base_table;
|
2018-02-10 22:17:08 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
void _parser_state_update(struct parser_state* state) {
|
|
|
|
state->current_match = state->current_node ? state->current_node->data : NULL;
|
|
|
|
}
|
|
|
|
|
2018-02-11 22:23:02 -08:00
|
|
|
void _parser_state_init(struct parser_state* state,
|
|
|
|
ll* tokens, const char* string, libab_table* table) {
|
2018-02-10 22:17:08 -08:00
|
|
|
state->current_node = tokens->head;
|
|
|
|
state->string = string;
|
2018-02-11 22:23:02 -08:00
|
|
|
state->base_table = table;
|
2018-02-10 22:17:08 -08:00
|
|
|
_parser_state_update(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _parser_state_step(struct parser_state* state) {
|
|
|
|
if(state->current_node) {
|
|
|
|
state->current_node = state->current_node->next;
|
|
|
|
}
|
|
|
|
_parser_state_update(state);
|
|
|
|
}
|
2018-02-10 22:40:34 -08:00
|
|
|
|
|
|
|
int _parser_is_char(struct parser_state* state, char to_expect) {
|
|
|
|
return (state->current_match && state->current_match->type == TOKEN_CHAR &&
|
|
|
|
state->string[state->current_match->from] == to_expect);
|
|
|
|
}
|
|
|
|
|
2018-02-11 21:09:41 -08:00
|
|
|
int _parser_is_type(struct parser_state* state, libab_lexer_token to_expect) {
|
2018-02-10 23:06:37 -08:00
|
|
|
return (state->current_match && state->current_match->type == to_expect);
|
|
|
|
}
|
|
|
|
|
2018-02-10 22:40:34 -08:00
|
|
|
int _parser_eof(struct parser_state* state) {
|
|
|
|
return state->current_match == NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
libab_result _parser_consume_char(struct parser_state* state, char to_consume) {
|
|
|
|
libab_result result = LIBAB_SUCCESS;
|
|
|
|
if(state->current_match == NULL) {
|
|
|
|
result = LIBAB_EOF;
|
|
|
|
} else if(state->current_match->type != TOKEN_CHAR ||
|
|
|
|
state->string[state->current_match->from] != to_consume) {
|
|
|
|
result = LIBAB_UNEXPECTED;
|
|
|
|
} else {
|
|
|
|
_parser_state_step(state);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_result _parse_block(struct parser_state*, libab_tree**, int);
|
2018-02-10 23:06:37 -08:00
|
|
|
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_result _parser_extract_token(struct parser_state* state, char** into, libab_lexer_match* match) {
|
2018-02-11 13:42:05 -08:00
|
|
|
libab_result result = LIBAB_SUCCESS;
|
|
|
|
size_t string_size = match->to - match->from;
|
|
|
|
if((*into = malloc(string_size + 1))) {
|
|
|
|
strncpy(*into, state->string + match->from, string_size);
|
|
|
|
(*into)[string_size] = '\0';
|
|
|
|
} else {
|
|
|
|
result = LIBAB_MALLOC;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-02-15 23:11:25 -08:00
|
|
|
int _parser_match_is_op(libab_lexer_match* match) {
|
|
|
|
return match->type == TOKEN_OP_INFIX ||
|
|
|
|
match->type == TOKEN_OP_PREFIX ||
|
|
|
|
match->type == TOKEN_OP_POSTFIX;
|
|
|
|
}
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_result _parse_expression(struct parser_state* state, libab_tree** store_into) {
|
2018-02-10 23:06:37 -08:00
|
|
|
libab_result result = LIBAB_SUCCESS;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_result _parse_statement(struct parser_state* state, libab_tree** store_into) {
|
2018-02-10 23:06:37 -08:00
|
|
|
libab_result result = LIBAB_SUCCESS;
|
|
|
|
|
|
|
|
if(_parser_is_char(state, '{')) result = _parse_block(state, store_into, 1);
|
|
|
|
else if(_parser_is_type(state, TOKEN_ID) ||
|
|
|
|
_parser_is_type(state, TOKEN_NUM) ||
|
|
|
|
_parser_is_type(state, TOKEN_STR) ||
|
|
|
|
_parser_is_type(state, TOKEN_CHAR_LIT) ||
|
|
|
|
_parser_is_type(state, TOKEN_TRUE) ||
|
|
|
|
_parser_is_type(state, TOKEN_FALSE) ||
|
|
|
|
_parser_is_char(state, '(') ||
|
|
|
|
_parser_is_type(state, TOKEN_OP_PREFIX)) {
|
|
|
|
result = _parse_expression(state, store_into);
|
|
|
|
if(result == LIBAB_SUCCESS) result = _parser_consume_char(state, ';');
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-02-10 22:40:34 -08:00
|
|
|
libab_result _parse_block(struct parser_state* state,
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_tree** store_into, int expect_braces) {
|
2018-02-10 22:40:34 -08:00
|
|
|
libab_result result = LIBAB_SUCCESS;
|
2018-02-10 23:06:37 -08:00
|
|
|
if((*store_into = malloc(sizeof(**store_into))) == NULL) result = LIBAB_MALLOC;
|
2018-02-10 22:40:34 -08:00
|
|
|
|
|
|
|
if(expect_braces && result == LIBAB_SUCCESS) result = _parser_consume_char(state, '{');
|
|
|
|
|
|
|
|
while(result == LIBAB_SUCCESS &&
|
|
|
|
!_parser_eof(state) &&
|
|
|
|
!(expect_braces && _parser_is_char(state, '}'))) {
|
2018-02-10 23:06:37 -08:00
|
|
|
|
2018-02-10 22:40:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if(expect_braces && result == LIBAB_SUCCESS) result = _parser_consume_char(state, '}');
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-02-11 22:23:02 -08:00
|
|
|
void libab_parser_init(libab_parser* parser, libab_table* table) {
|
|
|
|
parser->base_table = table;
|
|
|
|
}
|
|
|
|
libab_result libab_parser_parse(libab_parser* parser, ll* tokens,
|
|
|
|
const char* string, libab_tree** store_into) {
|
2018-02-10 22:17:08 -08:00
|
|
|
libab_result result = LIBAB_SUCCESS;
|
|
|
|
struct parser_state state;
|
2018-02-11 22:23:02 -08:00
|
|
|
_parser_state_init(&state, tokens, string, parser->base_table);
|
2018-02-10 22:17:08 -08:00
|
|
|
|
2018-02-10 22:40:34 -08:00
|
|
|
result = _parse_block(&state, store_into, 0);
|
|
|
|
if(result == LIBAB_SUCCESS) {
|
|
|
|
(*store_into)->variant = BASE;
|
|
|
|
}
|
|
|
|
|
2018-02-10 22:17:08 -08:00
|
|
|
return result;
|
|
|
|
}
|
2018-02-11 22:23:02 -08:00
|
|
|
void libab_parser_free(libab_parser* parser) {
|
|
|
|
parser->base_table = NULL;
|
|
|
|
}
|