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.c322
1 files changed, 257 insertions, 65 deletions
diff --git a/src/lib/syntax.c b/src/lib/syntax.c
index 23138ed..2a613c8 100644
--- a/src/lib/syntax.c
+++ b/src/lib/syntax.c
@@ -20,14 +20,16 @@
#include "aplwc_internal.h"
struct scan_state {
- struct string *text;
+ struct aplwc *aplwc;
+ struct string **text;
size_t offset;
int skip_number_and_identifier;
};
static void
-init_scan_state(struct scan_state *state, struct string *text)
+init_scan_state(struct scan_state *state, struct aplwc *aplwc, struct string **text)
{
+ state->aplwc = aplwc;
state->text = text;
state->offset = 0;
state->skip_number_and_identifier = 0;
@@ -54,17 +56,33 @@ is_digit(uint32_t c)
static uint32_t
peek(struct scan_state *state)
{
- return string_char(state->text, state->offset);
+ return string_char(*state->text, state->offset);
}
static uint32_t
advance(struct scan_state *state)
{
- state->offset += char_length(state->text, state->offset);
+ state->offset += char_length(*state->text, state->offset);
state->skip_number_and_identifier = 0;
return peek(state);
}
+static symbol_t
+newsym(struct scan_state *state, size_t from, size_t length)
+{
+ struct string *s;
+ symbol_t id;
+ enum aplwc_rc rc;
+
+ s = substring(state->aplwc, *state->text, from, length);
+ assert(s); /* I know this is wrong */
+
+ rc = getsym(state->aplwc, s, &id);
+ assert(rc == APLWC_OK); /* I know this is wrong */
+
+ return id;
+}
+
static void
skip_space(struct scan_state *state)
{
@@ -72,70 +90,142 @@ skip_space(struct scan_state *state)
advance(state);
}
+#define T tokens->tokens[token_index]
+
static int
-single_sym(struct scan_state *state, struct token *token)
+single_sym(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
{
uint32_t c;
+ size_t start;
+ symbol_t sym;
+
+ MEMPTRS(state->aplwc, 1);
+ MEMPTR(0, tokens);
c = peek(state);
+ start = state->offset;
switch(c){
- case 0x2190: token->tag = TOKEN_TAG_LEFT_ARROW; break;
- case 0x22C4: token->tag = TOKEN_TAG_DIAMOND; break;
- case 0x2207: token->tag = TOKEN_TAG_DEL; break;
- case 0x2336: token->tag = TOKEN_TAG_IBEAM; break;
- case 0x2395: token->tag = TOKEN_TAG_QUAD; break;
- case '\n': token->tag = TOKEN_TAG_NEWLINE; break;
- case '(': token->tag = TOKEN_TAG_LEFT_PAREN; break;
- case ')': token->tag = TOKEN_TAG_RIGHT_PAREN; break;
- default: token->tag = TOKEN_TAG_UNKNOWN_SYM; break;
+ case 0x2190: T.tag = TOKEN_TAG_LEFT_ARROW; break;
+ case 0x22C4: T.tag = TOKEN_TAG_DIAMOND; break;
+ case 0x2207: T.tag = TOKEN_TAG_DEL; break;
+ case 0x2336: T.tag = TOKEN_TAG_IBEAM; break;
+ case 0x2395: T.tag = TOKEN_TAG_QUAD; break;
+ case '\n': T.tag = TOKEN_TAG_NEWLINE; break;
+ case '(': T.tag = TOKEN_TAG_LEFT_PAREN; break;
+ case ')': T.tag = TOKEN_TAG_RIGHT_PAREN; break;
+ default:
+ T.tag = TOKEN_TAG_UNKNOWN_SYM;
+ if(!check_only){
+ sym = newsym(state, start, 1);
+ T.data.symbol = sym;
+ }
+ break;
}
advance(state);
+ MEMPTRS_EXIT(state->aplwc);
return 1;
}
static int
-identifier(struct scan_state *state, struct token *token)
+identifier(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
{
uint32_t c;
+ size_t start, len;
+ int ok;
+ symbol_t sym;
+
+ MEMPTRS(state->aplwc, 1);
+ MEMPTR(0, tokens);
+
+ ok = 0;
+
if(state->skip_number_and_identifier || (!is_letter(peek(state))))
- return 0;
+ goto end;
- do
+ start = state->offset;
+ len = 0;
+ do{
c = advance(state);
- while(is_letter(c) || is_digit(c) || (c == '_'));
+ len++;
+ }while(is_letter(c) || is_digit(c) || (c == '_'));
+
+ T.tag = TOKEN_TAG_IDENTIFIER;
+ if(!check_only){
+ sym = newsym(state, start, len);
+ T.data.symbol = sym;
+ }
- token->tag = TOKEN_TAG_IDENTIFIER;
state->skip_number_and_identifier = 1;
- return 1;
+ ok = 1;
+end:
+ MEMPTRS_EXIT(state->aplwc);
+ return ok;
}
static int
-keyword(struct scan_state *state, struct token *token)
+keyword(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
{
uint32_t c;
+ size_t start, len;
+ int ok;
+ symbol_t sym;
+ enum keyword kw;
+
+ MEMPTRS(state->aplwc, 1);
+ MEMPTR(0, tokens);
+
+ ok = 0;
+
if(peek(state) != ':')
- return 0;
+ goto end;
+ c = advance(state);
- do
+ start = state->offset;
+ len = 0;
+ do{
c = advance(state);
- while(is_letter(c));
+ len++;
+ }while(is_letter(c));
- token->tag = TOKEN_TAG_KEYWORD;
- return 1;
+ T.tag = TOKEN_TAG_KEYWORD;
+ if(!check_only){
+ sym = newsym(state, start, len);
+
+ for(kw = 0; kw < N_KWDS; kw++){
+ if(sym == state->aplwc->keyword_symbols[kw]){
+ T.data.keyword = kw;
+ break;
+ }
+ }
+ if(kw == N_KWDS)
+ ok = 0;
+
+ }
+
+ ok = 1;
+end:
+ MEMPTRS_EXIT(state->aplwc);
+ return ok;
}
static int
-number(struct scan_state *state, struct token *token)
+number(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
{
uint32_t c;
- int has_digits;
+ int has_digits, ok;
+
+ MEMPTRS(state->aplwc, 1);
+ MEMPTR(0, tokens);
+ UNUSED_PARAMETER(check_only);
+
+ ok = 0;
c = peek(state);
if(state->skip_number_and_identifier)
- return 0;
+ goto end;
has_digits = 0;
@@ -161,21 +251,31 @@ number(struct scan_state *state, struct token *token)
}
if(has_digits == 0)
- return 0;
+ goto end;
- token->tag = TOKEN_TAG_NUMBER;
+ T.tag = TOKEN_TAG_NUMBER;
state->skip_number_and_identifier = 1;
- return 1;
+ ok = 1;
+end:
+ MEMPTRS_EXIT(state->aplwc);
+ return ok;
}
static int
-text(struct scan_state *state, struct token *token)
+text(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
{
uint32_t c;
+ int ok;
+
+ MEMPTRS(state->aplwc, 1);
+ MEMPTR(0, tokens);
+ UNUSED_PARAMETER(check_only);
+
+ ok = 0;
c = peek(state);
if(c != '\'')
- return 0;
+ goto end;
do
c = advance(state);
@@ -184,34 +284,48 @@ text(struct scan_state *state, struct token *token)
if(c == '\'')
advance(state);
else
- return 0;
+ goto end;
- token->tag = TOKEN_TAG_TEXT;
- return 1;
+ T.tag = TOKEN_TAG_TEXT;
+ ok = 1;
+end:
+ MEMPTRS_EXIT(state->aplwc);
+ return ok;
}
static int
-comment(struct scan_state *state, struct token *token)
+comment(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
{
uint32_t c;
+ int ok;
+ MEMPTRS(state->aplwc, 1);
+ MEMPTR(0, tokens);
+
+ UNUSED_PARAMETER(check_only);
+
+ ok = 0;
c = peek(state);
if(c != 0x235D)
- return 0;
+ goto end;
do
c = advance(state);
while(c != '\n');
- token->tag = TOKEN_TAG_COMMENT;
- return 1;
+ T.tag = TOKEN_TAG_COMMENT;
+ ok = 1;
+end:
+ MEMPTRS_EXIT(state->aplwc);
+ return ok;
}
static enum aplwc_rc
-next_token(struct scan_state *state, struct token *token)
+next_token(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
{
+ enum aplwc_rc rc;
size_t i;
- int (*scans[])(struct scan_state *, struct token *token) = {
+ int (*scans[])(struct scan_state *, struct token_list *, size_t, int) = {
identifier,
keyword,
number,
@@ -219,55 +333,76 @@ next_token(struct scan_state *state, struct token *token)
comment,
single_sym /* Must be last */
};
+ MEMPTRS(state->aplwc, 1);
+ MEMPTR(0, tokens);
skip_space(state);
- token->start = state->offset;
+ T.start = state->offset;
for(i = 0; i < NELEM(scans); i++){
- if(scans[i](state, token))
+ if(scans[i](state, tokens, token_index, check_only))
break;
- state->offset = token->start;
+ state->offset = tokens->tokens[token_index].start;
}
- token->end = state->offset;
+ T.end = state->offset;
skip_space(state);
- if(token->start == token->end)
- return APLWC_INVALID_SYNTAX;
- else
- return APLWC_OK;
+ rc = (T.start == T.end) ? APLWC_INVALID_SYNTAX : APLWC_OK;
+ MEMPTRS_EXIT(state->aplwc);
+ return rc;
}
+#undef T
+
static enum aplwc_rc
-check(struct string *text, size_t *n)
+check(struct aplwc *aplwc, struct string *text, size_t *n)
{
struct scan_state state;
- struct token token;
+ struct token_list *tokens;
enum aplwc_rc ret;
size_t count;
- init_scan_state(&state, text);
+ MEMPTRS(aplwc, 2);
+ MEMPTR(0, text);
+
+ if((tokens = memory_alloc_token_list(aplwc, 1)) == NULL){
+ ret = aplwc->last_error;
+ goto end;
+ }
+ MEMPTR(1, tokens);
+
+ init_scan_state(&state, aplwc, &text);
for(count = 0; peek(&state); count++){
- ret = next_token(&state, &token);
+ ret = next_token(&state, tokens, 0, 1);
if(ret != APLWC_OK)
- return ret;
+ goto end;
}
*n = count;
- return APLWC_OK;
+ ret = APLWC_OK;
+end:
+ MEMPTRS_EXIT(aplwc);
+ return ret;
}
static void
-scan(struct string *text, struct token_list *tokens)
+scan(struct aplwc *aplwc, struct string *text, struct token_list *tokens)
{
struct scan_state state;
enum aplwc_rc ret;
size_t count;
- init_scan_state(&state, text);
+ MEMPTRS(aplwc, 2);
+ MEMPTR(0, text);
+ MEMPTR(1, tokens);
+
+ init_scan_state(&state, aplwc, &text);
for(count = 0; peek(&state); count++){
- ret = next_token(&state, &tokens->tokens[count]);
+ ret = next_token(&state, tokens, count, 0);
assert(ret == APLWC_OK);
}
+
+ MEMPTRS_EXIT(aplwc);
}
struct token_list *
@@ -277,11 +412,11 @@ scan_string(struct aplwc *aplwc, struct string *text, int oneline)
struct token_list *tokens;
size_t n, i;
- MEMPTRS(aplwc, 1);
+ MEMPTRS(aplwc, 2);
MEMPTR(0, text);
tokens = NULL;
- rc = check(text, &n);
+ rc = check(aplwc, text, &n);
if(rc != APLWC_OK)
goto end;
@@ -290,9 +425,11 @@ scan_string(struct aplwc *aplwc, struct string *text, int oneline)
rc = aplwc->last_error;
goto end;
}
+ MEMPTR(1, tokens);
+
tokens->text = text;
tokens->length = n;
- scan(text, tokens);
+ scan(aplwc, text, tokens);
for(i = 0; oneline && (i < n); i++){
if(tokens->tokens[i].tag != TOKEN_TAG_NEWLINE)
@@ -313,8 +450,34 @@ end:
return tokens;
}
+static void
+resolve_unknown(struct aplwc_module *module, struct token *t)
+{
+ symbol_t s;
+ struct module_member *m;
+
+ assert(t && (t->tag == TOKEN_TAG_UNKNOWN_SYM));
+ if(module == NULL)
+ return;
+
+ s = t->data.symbol;
+
+ for(m = module->members; m; m = m->link){
+ if(m->name == s){
+found:
+ t->tag = TOKEN_TAG_IDENTIFIER;
+ return;
+ }
+ }
+
+ for(m = module->imports; m; m = m->link){
+ if(m->name == s)
+ goto found;
+ }
+}
+
enum aplwc_rc
-check_tokens(struct token_list *tokens)
+check_tokens(struct aplwc_module *module, struct token_list *tokens)
{
size_t i;
enum aplwc_rc rc;
@@ -322,7 +485,9 @@ check_tokens(struct token_list *tokens)
for(i = 0, rc = APLWC_OK; (rc == APLWC_OK) && (i < tokens->length); i++){
switch(tokens->tokens[i].tag){
case TOKEN_TAG_UNKNOWN_SYM:
- rc = APLWC_INVALID_SYNTAX;
+ resolve_unknown(module, &tokens->tokens[i]);
+ if(tokens->tokens[i].tag == TOKEN_TAG_UNKNOWN_SYM)
+ return APLWC_INVALID_SYNTAX;
break;
default:
break;
@@ -331,3 +496,30 @@ check_tokens(struct token_list *tokens)
return rc;
}
+
+enum aplwc_rc
+keyword_init(struct aplwc *aplwc)
+{
+ enum keyword kw;
+ const char *cstr;
+ struct string *str;
+ symbol_t sym;
+
+ aplwc->last_error = APLWC_OK;
+ for(kw = 0; kw < N_KWDS; kw++){
+ switch(kw){
+ case KW_MODULE: cstr = "module"; break;
+ case KW_SYMBOL: cstr = "symbol"; break;
+ case KW_EXPORT: cstr = "export"; break;
+ case N_KWDS: assert(0); break;
+ }
+
+ if((str = chars_to_string(aplwc, cstr, -1)) == NULL)
+ break;
+ if(getsym(aplwc, str, &sym) != APLWC_OK)
+ break;
+ aplwc->keyword_symbols[kw] = sym;
+ }
+
+ return aplwc->last_error;
+}