|
@@ -692,7 +692,7 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
(*pos)++;
|
|
|
|
|
|
buffer_t *name = buffer_new();
|
|
|
- if (source[*pos] == '$' || source[*pos] == '{' || source[*pos] == ':')
|
|
|
+ if (source[*pos] == '$' || source[*pos] == '{' || source[*pos] == ':' || source[*pos] == '*')
|
|
|
buffer_append(name, source[(*pos)++]);
|
|
|
else {
|
|
|
if (!source[*pos] || !isalpha(source[*pos]))
|
|
@@ -1267,6 +1267,7 @@ node_t *nodeb(buffer_t *buf) {
|
|
|
typedef struct {
|
|
|
list_t *params;
|
|
|
list_t *body;
|
|
|
+ int variable;
|
|
|
} macro_t;
|
|
|
|
|
|
table_t *MACROS;
|
|
@@ -2410,7 +2411,9 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
node_t *parse_mexpr(list_t *tokens, size_t *pos);
|
|
|
|
|
|
node_t *parse_mprimary(list_t *tokens, size_t *pos) {
|
|
|
- if (MATCH(LPAR)) {
|
|
|
+ if (MATCH(STAR))
|
|
|
+ return NODET(LITERAL, token(T_NAME, strdup("*")));
|
|
|
+ else if (MATCH(LPAR)) {
|
|
|
node_t *a = parse_mexpr(tokens, pos);
|
|
|
|
|
|
EXPECT(RPAR, ")");
|
|
@@ -2452,6 +2455,12 @@ node_t *parse_mprimary(list_t *tokens, size_t *pos) {
|
|
|
}
|
|
|
|
|
|
node_t *parse_mexpr(list_t *tokens, size_t *pos) {
|
|
|
+ if (MATCH(MINUS)) {
|
|
|
+ node_t *a = parse_mexpr(tokens, pos);
|
|
|
+
|
|
|
+ return NODE1(NEGATE, a);
|
|
|
+ }
|
|
|
+
|
|
|
node_t *a = parse_mprimary(tokens, pos);
|
|
|
|
|
|
do {
|
|
@@ -2616,15 +2625,20 @@ node_t *parse_program(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
EXPECT(LPAR, "(");
|
|
|
|
|
|
+ int variable = 0;
|
|
|
list_t *params = list_new();
|
|
|
|
|
|
- if (!AT(RPAR))
|
|
|
- do {
|
|
|
- if(!AT(NAME))
|
|
|
- PARSE_ERROR("expected identifier");
|
|
|
+ if (!AT(RPAR)) {
|
|
|
+ if (MATCH(STAR))
|
|
|
+ variable = 1;
|
|
|
+ else
|
|
|
+ do {
|
|
|
+ if(!AT(NAME))
|
|
|
+ PARSE_ERROR("expected identifier");
|
|
|
|
|
|
- list_push(params, tokens->data[(*pos)++]);
|
|
|
- } while (MATCH(COMMA));
|
|
|
+ list_push(params, tokens->data[(*pos)++]);
|
|
|
+ } while (MATCH(COMMA));
|
|
|
+ }
|
|
|
|
|
|
EXPECT(RPAR, ")");
|
|
|
|
|
@@ -2654,7 +2668,8 @@ node_t *parse_program(list_t *tokens, size_t *pos) {
|
|
|
macro_t *m = malloc_checked(sizeof(macro_t));
|
|
|
m->params = params;
|
|
|
m->body = body;
|
|
|
-
|
|
|
+ m->variable = variable;
|
|
|
+
|
|
|
list_push(ms, m);
|
|
|
} else { n = parse_stmt(tokens, pos); flag = 1; }
|
|
|
|
|
@@ -3470,6 +3485,53 @@ buffer_t *HBUF;
|
|
|
list_t *MVARS;
|
|
|
node_t *YES;
|
|
|
|
|
|
+#define IS_NUMBER(n) ((n) && (n)->tag == N_LITERAL && (n)->t->tag == T_NUMBER)
|
|
|
+#define TO_DOUBLE(n) (strtod((n)->t->text, NULL))
|
|
|
+
|
|
|
+node_t *make_number(double v) {
|
|
|
+ char buf[64];
|
|
|
+ snprintf(buf, sizeof(buf), "%g", v);
|
|
|
+
|
|
|
+ return nodet(N_LITERAL, token(T_NUMBER, strdup(buf)));
|
|
|
+}
|
|
|
+
|
|
|
+node_t *mexpr_negate(node_t *a) {
|
|
|
+ if (!IS_NUMBER(a))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return make_number(-TO_DOUBLE(a));
|
|
|
+}
|
|
|
+
|
|
|
+node_t *mexpr_add(node_t *a, node_t *b) {
|
|
|
+ if (!IS_NUMBER(a))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!IS_NUMBER(b))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return make_number(TO_DOUBLE(a) + TO_DOUBLE(b));
|
|
|
+}
|
|
|
+
|
|
|
+node_t *mexpr_sub(node_t *a, node_t *b) {
|
|
|
+ if (!IS_NUMBER(a))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!IS_NUMBER(b))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return make_number(TO_DOUBLE(a) - TO_DOUBLE(b));
|
|
|
+}
|
|
|
+
|
|
|
+node_t *mexpr_mul(node_t *a, node_t *b) {
|
|
|
+ if (!IS_NUMBER(a))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!IS_NUMBER(b))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return make_number(TO_DOUBLE(a) * TO_DOUBLE(b));
|
|
|
+}
|
|
|
+
|
|
|
node_t *mf_isExpr(list_t *t) {
|
|
|
if (t->length != 1)
|
|
|
return NULL;
|
|
@@ -3500,57 +3562,52 @@ node_t *mf_newList(list_t *t) {
|
|
|
return nodel(N_LIST, t);
|
|
|
}
|
|
|
|
|
|
-struct {
|
|
|
- char *name;
|
|
|
- node_t *(*handler)(list_t *);
|
|
|
-} METAFUNCS[] = {
|
|
|
- { "isExpr", mf_isExpr },
|
|
|
- { "isList", mf_isList },
|
|
|
-
|
|
|
- { "newList", mf_newList },
|
|
|
-
|
|
|
- { NULL, NULL }
|
|
|
-};
|
|
|
+node_t *mf_len(list_t *t) {
|
|
|
+ if (t->length != 1)
|
|
|
+ return NULL;
|
|
|
|
|
|
-#define IS_NUMBER(n) ((n) && (n)->tag == N_LITERAL && (n)->t->tag == T_NUMBER)
|
|
|
-#define TO_DOUBLE(n) (strtod((n)->t->text, NULL))
|
|
|
+ node_t *a = t->data[0];
|
|
|
+ if (!a)
|
|
|
+ return NULL;
|
|
|
|
|
|
-node_t *make_number(double v) {
|
|
|
- char buf[64];
|
|
|
- snprintf(buf, sizeof(buf), "%g", v);
|
|
|
+ if (a->tag == N_LIST)
|
|
|
+ return make_number(a->l->length);
|
|
|
|
|
|
- return nodet(N_LITERAL, token(T_NUMBER, strdup(buf)));
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
-node_t *mexpr_add(node_t *a, node_t *b) {
|
|
|
- if (!IS_NUMBER(a))
|
|
|
+node_t *mf_nth(list_t *t) {
|
|
|
+ if (t->length != 2)
|
|
|
return NULL;
|
|
|
|
|
|
- if (!IS_NUMBER(b))
|
|
|
- return NULL;
|
|
|
-
|
|
|
- return make_number(TO_DOUBLE(a) + TO_DOUBLE(b));
|
|
|
-}
|
|
|
-
|
|
|
-node_t *mexpr_sub(node_t *a, node_t *b) {
|
|
|
- if (!IS_NUMBER(a))
|
|
|
+ node_t *a = t->data[0];
|
|
|
+ if (!a)
|
|
|
return NULL;
|
|
|
|
|
|
+ node_t *b = t->data[1];
|
|
|
if (!IS_NUMBER(b))
|
|
|
return NULL;
|
|
|
|
|
|
- return make_number(TO_DOUBLE(a) - TO_DOUBLE(b));
|
|
|
+ if (a->tag == N_LIST)
|
|
|
+ return list_index(a->l, TO_DOUBLE(b));
|
|
|
+
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
-node_t *mexpr_mul(node_t *a, node_t *b) {
|
|
|
- if (!IS_NUMBER(a))
|
|
|
- return NULL;
|
|
|
+struct {
|
|
|
+ char *name;
|
|
|
+ node_t *(*handler)(list_t *);
|
|
|
+} METAFUNCS[] = {
|
|
|
+ { "isExpr", mf_isExpr },
|
|
|
+ { "isList", mf_isList },
|
|
|
|
|
|
- if (!IS_NUMBER(b))
|
|
|
- return NULL;
|
|
|
+ { "newList", mf_newList },
|
|
|
|
|
|
- return make_number(TO_DOUBLE(a) * TO_DOUBLE(b));
|
|
|
-}
|
|
|
+ { "len", mf_len },
|
|
|
+ { "nth", mf_nth },
|
|
|
+
|
|
|
+ { NULL, NULL }
|
|
|
+};
|
|
|
|
|
|
macro_t *find_macro(char *name, size_t argc, int *res) {
|
|
|
list_t *ms = table_get(MACROS, name);
|
|
@@ -3562,12 +3619,15 @@ macro_t *find_macro(char *name, size_t argc, int *res) {
|
|
|
}
|
|
|
|
|
|
macro_t *m = NULL;
|
|
|
- for (ssize_t i = ms->length - 1; i >= 0; i--)
|
|
|
- if (((macro_t *)ms->data[i])->params->length == argc) {
|
|
|
- m = ms->data[i];
|
|
|
+ for (size_t i = 0; i < ms->length; i++) {
|
|
|
+ macro_t *t = ms->data[i];
|
|
|
+
|
|
|
+ if (t->variable || t->params->length == argc) {
|
|
|
+ m = t;
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
if (!m) {
|
|
|
if (res) *res = 2;
|
|
@@ -3641,33 +3701,39 @@ node_t *run_mexpr(node_t *node) {
|
|
|
if (run_mexpr(node->a) && run_mexpr(node->b))
|
|
|
return YES;
|
|
|
|
|
|
+ case N_NEGATE: {
|
|
|
+ node_t *a = run_mexpr(node->a);
|
|
|
+
|
|
|
+ return mexpr_negate(a);
|
|
|
+ }
|
|
|
+
|
|
|
case N_ADD: {
|
|
|
node_t *a = run_mexpr(node->a);
|
|
|
node_t *b = run_mexpr(node->b);
|
|
|
|
|
|
return mexpr_add(a, b);
|
|
|
- } break;
|
|
|
+ }
|
|
|
|
|
|
case N_SUB: {
|
|
|
node_t *a = run_mexpr(node->a);
|
|
|
node_t *b = run_mexpr(node->b);
|
|
|
|
|
|
return mexpr_sub(a, b);
|
|
|
- } break;
|
|
|
+ }
|
|
|
|
|
|
case N_MUL: {
|
|
|
node_t *a = run_mexpr(node->a);
|
|
|
node_t *b = run_mexpr(node->b);
|
|
|
|
|
|
return mexpr_mul(a, b);
|
|
|
- } break;
|
|
|
+ }
|
|
|
|
|
|
case N_EQUALS: {
|
|
|
node_t *a = run_mexpr(node->a);
|
|
|
node_t *b = run_mexpr(node->b);
|
|
|
|
|
|
return mexpr_equals(a, b)? YES: NULL;
|
|
|
- } break;
|
|
|
+ }
|
|
|
|
|
|
default:
|
|
|
COMPILE_ERROR("not yet implemented");
|
|
@@ -3716,9 +3782,13 @@ node_t *run_mnode(node_t *node) {
|
|
|
|
|
|
node_t *run_macro(macro_t *macro, list_t *args) {
|
|
|
table_t *mvars = list_index(MVARS, -1);
|
|
|
- for (size_t i = 0; i < args->length; i++)
|
|
|
- table_set(mvars, ((token_t *)macro->params->data[i])->text, args->data[i]);
|
|
|
-
|
|
|
+
|
|
|
+ if (macro->variable)
|
|
|
+ table_set(mvars, "*", nodel(N_LIST, args));
|
|
|
+ else
|
|
|
+ for (size_t i = 0; i < args->length; i++)
|
|
|
+ table_set(mvars, ((token_t *)macro->params->data[i])->text, args->data[i]);
|
|
|
+
|
|
|
node_t *r = NULL;
|
|
|
|
|
|
for (size_t i = 0; i < macro->body->length; i++) {
|