diff options
Diffstat (limited to 'src/lib/syntax.c')
| -rw-r--r-- | src/lib/syntax.c | 153 |
1 files changed, 150 insertions, 3 deletions
diff --git a/src/lib/syntax.c b/src/lib/syntax.c index c1a5a85..504bb74 100644 --- a/src/lib/syntax.c +++ b/src/lib/syntax.c @@ -1,9 +1,156 @@ #include "aplwc_internal.h" +struct scan_state { + struct string *text; + size_t offset; +}; + +static void +init_scan_state(struct scan_state *state, struct string *text) +{ + state->text = text; + state->offset = 0; +} + +static int +is_space(uint32_t c) +{ + return c == ' '; +} + +static int +is_letter(uint32_t c) +{ + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); +} + +static int +is_digit(uint32_t c) +{ + return (c >= '0') && (c <= '9'); +} + +static uint32_t +peek(struct scan_state *state) +{ + return string_char(state->text, state->offset); +} + +static void +advance(struct scan_state *state) +{ + state->offset += char_length(state->text, state->offset); +} + +static void +skip_space(struct scan_state *state) +{ + while(is_space(peek(state))) + advance(state); +} + +static void +identifier(struct scan_state *state, struct token *token) +{ + uint32_t c; + assert(is_letter(peek(state))); + + do{ + advance(state); + c = peek(state); + }while(is_letter(c) || is_digit(c) || (c == '_')); + + token->tag = TOKEN_TAG_IDENTIFIER; +} + +static enum aplwc_rc +next_token(struct scan_state *state, struct token *token) +{ + uint32_t c; + + skip_space(state); + + c = peek(state); + if(is_letter(c)){ + identifier(state, token); + return APLWC_OK; + } + if(c == '\n'){ + advance(state); + token->tag = TOKEN_TAG_NEWLINE; + return APLWC_OK; + } + + return APLWC_INVALID_SYNTAX; +} + +static enum aplwc_rc +check(struct string *text, size_t *n) +{ + struct scan_state state; + struct token token; + enum aplwc_rc ret; + size_t count; + + init_scan_state(&state, text); + + for(count = 0; peek(&state); count++){ + ret = next_token(&state, &token); + if(ret != APLWC_OK) + return ret; + } + + *n = count; + return APLWC_OK; +} + +static void +scan(struct string *text, struct token_list *tokens) +{ + struct scan_state state; + enum aplwc_rc ret; + size_t count; + + init_scan_state(&state, text); + + for(count = 0; peek(&state); count++){ + ret = next_token(&state, &tokens->tokens[count]); + assert(ret == APLWC_OK); + } +} + struct token_list * scan_line(struct aplwc *aplwc, struct string *text) { - aplwc->last_error = APLWC_NOT_YET_IMPLEMENTED; - UNUSED_PARAMETER(text); - return NULL; + enum aplwc_rc rc; + struct token_list *tokens; + size_t n, i; + + rc = check(text, &n); + if(rc != APLWC_OK){ + aplwc->last_error = rc; + return NULL; + } + + tokens = memory_alloc_token_list(&aplwc->memory, n); + if(tokens == NULL){ + aplwc->last_error = APLWC_OUT_OF_MEMORY; + return NULL; + } + tokens->length = n; + scan(text, tokens); + + for(i = 0; i < n; i++){ + if(tokens->tokens[i].tag != TOKEN_TAG_NEWLINE) + continue; + + for(i++; i < n; i++){ + if(tokens->tokens[i].tag != TOKEN_TAG_NEWLINE){ + memory_free_token_list(&aplwc->memory, tokens); + return NULL; + } + } + } + + return tokens; } |