summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apl9.h32
-rw-r--r--eval.c128
-rw-r--r--lexer.c22
-rw-r--r--main.c3
-rw-r--r--mkfile1
-rw-r--r--print.c12
-rw-r--r--symbol.c31
7 files changed, 181 insertions, 48 deletions
diff --git a/apl9.h b/apl9.h
index 9de7b12..ca7ed7c 100644
--- a/apl9.h
+++ b/apl9.h
@@ -15,7 +15,10 @@ typedef enum
LCurlTag,
RCurlTag,
LBracketTag,
- RBracketTag
+ RBracketTag,
+ ArrowTag,
+ AssignmentTag,
+ NameTag,
} datumTag;
typedef enum
@@ -24,12 +27,13 @@ typedef enum
AtypeArray,
} arrayDataType;
-
/* Data types */
typedef struct Array Array;
typedef struct Expr Expr;
typedef struct Function Function;
typedef struct Datum Datum;
+typedef struct Symbol Symbol;
+typedef struct Symtab Symtab;
struct Array
{
@@ -65,12 +69,25 @@ struct Datum
datumTag tag;
union {
Array *array;
- int code;
Expr expr;
Function func;
+ Symbol *symbol;
};
};
+struct Symbol
+{
+ int undefined;
+ Rune *name;
+ Datum value;
+};
+
+struct Symtab
+{
+ int nsyms;
+ Symbol **syms;
+};
+
typedef Array* (*fnmonad)(Array*);
typedef Array* (*fndyad)(Array*, Array*);
@@ -81,7 +98,7 @@ Rune *ppdatums(Datum *, int);
Rune *pparray(Array *);
/* lexer.c */
-Datum *lexline(Rune *, int *);
+Datum *lexline(Rune *, int *, Symtab *);
/* array.c */
Array *mkarray(int, int, int);
@@ -93,6 +110,10 @@ int simplescalar(Array *);
/* eval.c */
Datum *eval(Datum *, int *);
+/* symbol.c */
+Symbol *getsym(Symtab *, Rune *);
+Symtab *newsymtab(void);
+
/* Monadic functions from functions.h */
Array *fnTally(Array *);
Array *fnEnclose(Array *);
@@ -113,4 +134,5 @@ extern Rune primmonopnames[]; /* lexer.c */
extern Rune primdyadopnames[]; /* lexer.c */
extern Rune primhybridnames[]; /* lexer.c */
extern fnmonad monadfunctiondefs[]; /* function.c */
-extern fndyad dyadfunctiondefs[]; /* function.c */ \ No newline at end of file
+extern fndyad dyadfunctiondefs[]; /* function.c */
+extern Symtab *globalsymtab; /* symbol.c */ \ No newline at end of file
diff --git a/eval.c b/eval.c
index 4f228a7..f6cdb0d 100644
--- a/eval.c
+++ b/eval.c
@@ -16,42 +16,62 @@ Datum monadfun(Datum, Datum);
Datum dyadfun(Datum, Datum);
Datum lpar(Datum, Datum);
Datum rpar(Datum, Datum);
+Datum nameis(Datum, Datum);
+Datum assign(Datum, Datum);
+Datum *lookup(Datum);
-int bindingstrengths[12][12] = {
-/* A F H MO DO AF ( ) { } [ ] */
- 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* H */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* MO */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DO */
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* AF */
- 4, 4, 4, 4, 4, 4, 0, 5, 4, 4, 4, 4, /* ( */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ) */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* { */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* } */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* [ */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ] */
+int bindingstrengths[15][15] = {
+/* A F H MO DO AF ( ) { } [ ] ← IS N */
+ 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* H */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* MO */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DO */
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* AF */
+ 5, 5, 5, 5, 5, 5, 0, 6, 5, 5, 5, 5, 5, 5, 5, /* ( */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ) */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* { */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* } */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* [ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ] */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ← */
+ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* IS */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, /* N */
};
-evalfn evalfns[12][12] = {
-/* A F H MO DO AF ( ) { } [ ] */
- strand, dyadfun, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
- monadfun, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* H */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* MO */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DO */
- monadfun, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* AF */
- lpar, lpar, lpar, lpar, lpar, 0, lpar, rpar, lpar, lpar, lpar, lpar, /* ( */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ) */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* { */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* } */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* [ */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ] */
+evalfn evalfns[15][15] = {
+/* A F H MO DO AF ( ) { } [ ] ← IS N */
+ strand, dyadfun, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
+ monadfun, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* H */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* MO */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DO */
+ monadfun, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* AF */
+ lpar, lpar, lpar, lpar, lpar, 0, lpar, rpar, lpar, lpar, lpar, lpar, lpar, lpar, lpar, /* ( */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ) */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* { */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* } */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* [ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ] */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ← */
+ assign, assign, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* IS */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nameis, 0, 0, /* N */
};
Datum *
eval(Datum *tokens, int *ntoks)
{
+ errormsg = nil;
+
+ /* start by looking up first variable if needed */
+ if(*ntoks > 0 && tokens[(*ntoks)-1].tag == NameTag){
+ Datum *value = lookup(tokens[(*ntoks)-1]);
+ if(value == nil)
+ *ntoks = 0;
+ else
+ tokens[(*ntoks)-1] = *value;
+ }
+
while(*ntoks > 1){
int maxlevel = 0;
int offset;
@@ -59,6 +79,7 @@ eval(Datum *tokens, int *ntoks)
traceprint("CURRENT: %S\n", ppdatums(tokens, *ntoks));
for(offset = (*ntoks)-1; offset >= 0; offset--){
int level;
+retry:
if(offset == 0)
level = 0;
else{
@@ -66,11 +87,21 @@ eval(Datum *tokens, int *ntoks)
Datum right = tokens[offset];
level = bindingstrengths[left.tag][right.tag];
}
- if(level < maxlevel){
+
+ if(level == 0 && tokens[offset-1].tag == NameTag){
+ Datum *value = lookup(tokens[offset-1]);
+ if(value == nil){
+ *ntoks = 0;
+ return tokens;
+ }else{
+ tokens[offset-1] = *value;
+ goto retry;
+ }
+ }else if(level < maxlevel){
Datum left = tokens[offset];
Datum right = tokens[offset+1];
fn = evalfns[left.tag][right.tag];
- traceprint("Reducing %S and %S\n", ppdatum(left), ppdatum(right));
+ traceprint("Reducing %S and %S (fn=%p, level=%d, max=%d)\n", ppdatum(left), ppdatum(right), fn, level, maxlevel);
break;
}else if(level > maxlevel)
maxlevel = level;
@@ -88,10 +119,21 @@ eval(Datum *tokens, int *ntoks)
return tokens;
}
+Datum *
+lookup(Datum var)
+{
+ traceprint("VAR LOOKUP %S\n", var.symbol->name);
+ if(var.symbol->undefined){
+ errormsg = runesmprint("Variable undefined: %S\n", var.symbol->name);
+ return nil;
+ }else
+ return &var.symbol->value;
+}
+
Datum
strand(Datum left, Datum right)
{
- traceprint("Stranding\n");
+ traceprint("Stranding (%d %d)\n", left.array->stranded, right.array->stranded);
Datum result;
Array *leftarr = left.array->stranded ? left.array : fnEnclose(left.array);
Array *rightarr = right.array->stranded ? right.array : fnEnclose(right.array);
@@ -110,9 +152,9 @@ monadfun(Datum left, Datum right)
/* TODO handle undefined functions here */
if(left.func.left)
- result.array = dyadfunctiondefs[left.code](left.func.left, right.array);
+ result.array = dyadfunctiondefs[left.func.code](left.func.left, right.array);
else
- result.array = monadfunctiondefs[left.code](right.array);
+ result.array = monadfunctiondefs[left.func.code](right.array);
return result;
}
@@ -147,4 +189,24 @@ rpar(Datum left, Datum right)
Datum *result = eval(left.expr.toks, &left.expr.ntoks);
result[0].array->stranded = 0;
return result[0]; /* TODO handle error if ntoks != 1 */
+}
+
+Datum
+nameis(Datum left, Datum right)
+{
+ traceprint("NAME SYMBOL %p\n", left.symbol);
+ traceprint("NAMEIS %S←\n", left.symbol->name);
+ right.tag = AssignmentTag;
+ right.symbol = left.symbol;
+ return right;
+}
+
+Datum
+assign(Datum left, Datum right)
+{
+ left.symbol->value = right; /* TODO think about this*/
+ left.symbol->undefined = 0;
+ if(left.symbol->value.tag == ArrayTag)
+ left.symbol->value.array->stranded = 0;
+ return right;
} \ No newline at end of file
diff --git a/lexer.c b/lexer.c
index 40c7f35..bc5aa50 100644
--- a/lexer.c
+++ b/lexer.c
@@ -9,7 +9,7 @@ Rune primdyadopnames[] = L"⍣.∘⍤⍥@⍠⌺";
Rune primhybridnames[] = L"/\⌿⍀";
Datum *
-lexline(Rune *line, int *ntoks)
+lexline(Rune *line, int *ntoks, Symtab *symtab)
{
int offset = 0;
int len = runestrlen(line);
@@ -20,7 +20,7 @@ lexline(Rune *line, int *ntoks)
if(isspacerune(line[offset])){
offset++;
continue;
- }else if(runestrchr(L"(){}[]", line[offset])){
+ }else if(runestrchr(L"(){}[]←", line[offset])){
switch(line[offset]){
case '(': tokens[*ntoks].tag = LParTag; break;
case ')': tokens[*ntoks].tag = RParTag; break;
@@ -28,19 +28,20 @@ lexline(Rune *line, int *ntoks)
case '}': tokens[*ntoks].tag = RCurlTag; break;
case '[': tokens[*ntoks].tag = LBracketTag; break;
case ']': tokens[*ntoks].tag = RBracketTag; break;
+ case L'←': tokens[*ntoks].tag = ArrowTag; break;
}
offset++;
}else if(p = runestrchr(primfuncnames, line[offset])){
tokens[*ntoks].tag = FunctionTag;
- tokens[*ntoks].code = p-primfuncnames;
+ tokens[*ntoks].func.code = p-primfuncnames;
offset++;
}else if(p = runestrchr(primmonopnames, line[offset])){
tokens[*ntoks].tag = MonadicOpTag;
- tokens[*ntoks].code = p-primmonopnames;
+ tokens[*ntoks].func.code = p-primmonopnames;
offset++;
}else if(p = runestrchr(primdyadopnames, line[offset])){
tokens[*ntoks].tag = DyadicOpTag;
- tokens[*ntoks].code = p-primdyadopnames;
+ tokens[*ntoks].func.code = p-primdyadopnames;
offset++;
}else if(isdigitrune(line[offset])){
char buf[64];
@@ -52,6 +53,17 @@ lexline(Rune *line, int *ntoks)
*p = 0;
tokens[*ntoks].tag = ArrayTag;
tokens[*ntoks].array = mkscalarint(atoll(buf));
+ }else if(isalpharune(line[offset])){
+ Rune buf[64];
+ Rune *p = buf;
+ while(isalpharune(line[offset])){
+ *p = line[offset];
+ p++;
+ offset++;
+ }
+ *p = 0;
+ tokens[*ntoks].tag = NameTag;
+ tokens[*ntoks].symbol = getsym(symtab, buf);
}else{
print("Can't lex: %S\n", &line[offset]);
*ntoks = 0;
diff --git a/main.c b/main.c
index 55ab340..c5679a3 100644
--- a/main.c
+++ b/main.c
@@ -14,6 +14,7 @@ main(int argc, char *argv[])
{
int off = 0;
stdin = Bfdopen(0, OREAD);
+ globalsymtab = newsymtab();
traceeval = 0;
ARGBEGIN{
@@ -57,7 +58,7 @@ Datum *
evalline(Rune *line)
{
int ntoks;
- Datum *tokens = lexline(line, &ntoks);
+ Datum *tokens = lexline(line, &ntoks, globalsymtab);
Datum *result = eval(tokens, &ntoks);
if(ntoks == 1)
return result;
diff --git a/mkfile b/mkfile
index ce8f6ec..c5e87f7 100644
--- a/mkfile
+++ b/mkfile
@@ -8,6 +8,7 @@ OFILES=\
print.$O\
array.$O\
functions.$O\
+ symbol.$O\
HFILES=\
apl9.h\
diff --git a/print.c b/print.c
index e0443b3..588ce0a 100644
--- a/print.c
+++ b/print.c
@@ -10,16 +10,20 @@ ppdatum(Datum d)
Rune *result;
switch(d.tag){
case ArrayTag: result = pparray(d.array); break;
- case FunctionTag: result = runesmprint("%C", primfuncnames[d.code]); break;
- case HybridTag: result = runesmprint("%C", primhybridnames[d.code]); break;
- case MonadicOpTag: result = runesmprint("%C", primmonopnames[d.code]); break;
- case DyadicOpTag: result = runesmprint("%C", primdyadopnames[d.code]); break;
+ case FunctionTag: result = runesmprint("%C", primfuncnames[d.func.code]); break;
+ case HybridTag: result = runesmprint("%C", primhybridnames[d.func.code]); break;
+ case MonadicOpTag: result = runesmprint("%C", primmonopnames[d.func.code]); break;
+ case DyadicOpTag: result = runesmprint("%C", primdyadopnames[d.func.code]); break;
+ case BoundFunctionTag: result = runesmprint("%S∘%C", pparray(d.func.left), primfuncnames[d.func.code]); break;
case LParTag: result = runestrdup(L"("); break;
case RParTag: result = runestrdup(L")"); break;
case LCurlTag: result = runestrdup(L"{"); break;
case RCurlTag: result = runestrdup(L"}"); break;
case LBracketTag: result = runestrdup(L"["); break;
case RBracketTag: result = runestrdup(L"]"); break;
+ case ArrowTag: result = runestrdup(L"←"); break;
+ case AssignmentTag: result = runesmprint("%S←", d.symbol->name); break;
+ case NameTag: result = runestrdup(d.symbol->name); break;
default: result = runesmprint("<not printable %d>", d.tag);
}
return result;
diff --git a/symbol.c b/symbol.c
new file mode 100644
index 0000000..a9d1d1f
--- /dev/null
+++ b/symbol.c
@@ -0,0 +1,31 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#include "apl9.h"
+
+Symtab *globalsymtab;
+
+Symbol *
+getsym(Symtab *tab, Rune *name)
+{
+ for(int i = 0; i < tab->nsyms; i++)
+ if(runestrcmp(tab->syms[i]->name, name) == 0)
+ return tab->syms[i];
+
+ tab->nsyms++;
+ tab->syms = realloc(tab->syms, sizeof(Symbol *) * tab->nsyms);
+ tab->syms[tab->nsyms-1] = malloc(sizeof(Symbol));
+ tab->syms[tab->nsyms-1]->name = runestrdup(name);
+ tab->syms[tab->nsyms-1]->undefined = 1;
+ return tab->syms[tab->nsyms-1];
+}
+
+Symtab *
+newsymtab(void)
+{
+ Symtab *tab = malloc(sizeof(Symtab));
+ tab->nsyms = 0;
+ tab->syms = nil;
+ return tab;
+} \ No newline at end of file