summaryrefslogtreecommitdiff
path: root/src/lib/syntax.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/syntax.c')
-rw-r--r--src/lib/syntax.c153
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;
}