2018-02-10 13:52:33 -08:00
|
|
|
#include "lexer.h"
|
2018-02-10 17:09:35 -08:00
|
|
|
#include "ll.h"
|
2018-02-11 22:32:42 -08:00
|
|
|
#include "util.h"
|
2018-02-10 17:09:35 -08:00
|
|
|
#include <ctype.h>
|
2018-04-21 14:09:01 -07:00
|
|
|
#include <stdlib.h>
|
2018-02-10 14:21:04 -08:00
|
|
|
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_result libab_lexer_init(libab_lexer* lexer) {
|
2018-02-10 14:21:04 -08:00
|
|
|
size_t i;
|
|
|
|
libab_result result = LIBAB_SUCCESS;
|
2018-04-21 14:09:01 -07:00
|
|
|
const char* words[] = {".",
|
|
|
|
"[a-zA-Z][a-zA-Z0-9_]*",
|
|
|
|
"[0-9]+(\\.[0-9]*)?",
|
|
|
|
"if",
|
|
|
|
"else",
|
|
|
|
"while",
|
|
|
|
"do",
|
|
|
|
"->",
|
|
|
|
"fun",
|
2018-06-12 23:34:18 -07:00
|
|
|
"return"};
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_lexer_token tokens[] = {
|
2018-04-21 14:09:01 -07:00
|
|
|
TOKEN_CHAR, TOKEN_ID, TOKEN_NUM, TOKEN_KW_IF,
|
|
|
|
TOKEN_KW_ELSE, TOKEN_KW_WHILE, TOKEN_KW_DO, TOKEN_KW_ARROW,
|
2018-06-12 23:34:18 -07:00
|
|
|
TOKEN_KW_FUN, TOKEN_KW_RETURN };
|
2018-04-21 14:09:01 -07:00
|
|
|
const size_t count = sizeof(tokens) / sizeof(libab_lexer_token);
|
2018-02-10 14:21:04 -08:00
|
|
|
|
|
|
|
eval_config_init(&lexer->config);
|
2018-04-21 14:09:01 -07:00
|
|
|
for (i = 0; i < count && result == LIBAB_SUCCESS; i++) {
|
2018-02-11 21:09:41 -08:00
|
|
|
result = libab_convert_lex_result(
|
2018-04-21 14:09:01 -07:00
|
|
|
eval_config_add(&lexer->config, words[i], tokens[i]));
|
2018-02-10 14:21:04 -08:00
|
|
|
}
|
|
|
|
|
2018-04-21 14:09:01 -07:00
|
|
|
if (result != LIBAB_SUCCESS) {
|
2018-03-16 23:09:11 -07:00
|
|
|
eval_config_free(&lexer->config);
|
|
|
|
}
|
|
|
|
|
2018-02-10 14:21:04 -08:00
|
|
|
return result;
|
|
|
|
}
|
2018-02-10 17:09:35 -08:00
|
|
|
|
|
|
|
struct lexer_state {
|
|
|
|
size_t line;
|
|
|
|
size_t line_from;
|
|
|
|
const char* source;
|
|
|
|
ll* matches;
|
|
|
|
};
|
|
|
|
int _lexer_foreach_convert_match(void* data, va_list args) {
|
|
|
|
libab_result result = LIBAB_SUCCESS;
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_lexer_match* new_match;
|
2018-02-10 17:09:35 -08:00
|
|
|
match* match = data;
|
|
|
|
struct lexer_state* state = va_arg(args, struct lexer_state*);
|
|
|
|
char first_char = state->source[match->from];
|
2018-04-21 14:09:01 -07:00
|
|
|
if (isspace(first_char)) {
|
2018-03-18 19:21:09 -07:00
|
|
|
/* Skip */
|
2018-04-21 14:09:01 -07:00
|
|
|
} else if (first_char == '\n') {
|
2018-02-10 17:09:35 -08:00
|
|
|
state->line++;
|
|
|
|
state->line_from = match->to;
|
2018-04-21 14:09:01 -07:00
|
|
|
} else if ((new_match = malloc(sizeof(*new_match)))) {
|
2018-02-10 17:21:32 -08:00
|
|
|
new_match->type = match->pattern;
|
2018-02-10 17:09:35 -08:00
|
|
|
new_match->from = match->from;
|
|
|
|
new_match->to = match->to;
|
|
|
|
new_match->line_from = state->line_from;
|
|
|
|
new_match->line = state->line;
|
2018-02-11 21:09:41 -08:00
|
|
|
result = libab_convert_ds_result(ll_append(state->matches, new_match));
|
2018-04-21 14:09:01 -07:00
|
|
|
if (result != LIBAB_SUCCESS) {
|
2018-02-10 17:09:35 -08:00
|
|
|
free(new_match);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result = LIBAB_MALLOC;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-04-21 14:09:01 -07:00
|
|
|
libab_result libab_lexer_lex(libab_lexer* lexer, const char* string,
|
|
|
|
ll* lex_into) {
|
2018-02-10 17:09:35 -08:00
|
|
|
libab_result result;
|
|
|
|
ll raw_matches;
|
|
|
|
struct lexer_state state;
|
|
|
|
|
|
|
|
ll_init(&raw_matches);
|
|
|
|
|
|
|
|
state.line = 0;
|
|
|
|
state.line_from = 0;
|
|
|
|
state.matches = lex_into;
|
|
|
|
state.source = string;
|
|
|
|
|
2018-02-11 21:09:41 -08:00
|
|
|
result = libab_convert_lex_result(
|
2018-04-21 14:09:01 -07:00
|
|
|
eval_all(string, 0, &lexer->config, &raw_matches));
|
2018-02-10 17:09:35 -08:00
|
|
|
|
2018-04-21 14:09:01 -07:00
|
|
|
if (result == LIBAB_SUCCESS) {
|
|
|
|
result = (libab_result)ll_foreach(&raw_matches, NULL, compare_always,
|
|
|
|
_lexer_foreach_convert_match, &state);
|
2018-02-10 17:09:35 -08:00
|
|
|
}
|
|
|
|
|
2018-04-21 14:09:01 -07:00
|
|
|
if (result != LIBAB_SUCCESS) {
|
|
|
|
ll_foreach(lex_into, NULL, compare_always,
|
|
|
|
libab_lexer_foreach_match_free);
|
2018-02-10 17:09:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ll_foreach(&raw_matches, NULL, compare_always, eval_foreach_match_free);
|
|
|
|
ll_free(&raw_matches);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2018-02-11 21:09:41 -08:00
|
|
|
libab_result libab_lexer_free(libab_lexer* lexer) {
|
|
|
|
return libab_convert_lex_result(eval_config_free(&lexer->config));
|
2018-02-10 14:21:04 -08:00
|
|
|
}
|
2018-02-11 21:09:41 -08:00
|
|
|
int libab_lexer_foreach_match_free(void* data, va_list args) {
|
2018-04-21 14:09:01 -07:00
|
|
|
free((libab_lexer_match*)data);
|
2018-02-10 17:09:35 -08:00
|
|
|
return 0;
|
|
|
|
}
|