#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) { 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; }