#include #include #include #include "apl9.h" #define traceprint if(traceeval)print Rune *errormsg; int traceeval; typedef Datum (*evalfn)(Datum, Datum); Datum strand(Datum, Datum); 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[13][13] = { /* A F H MO DO AF ( ) [ ] ← IS N */ 4, 3, 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, /* F */ 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, /* MO */ 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, /* AF */ 5, 5, 5, 5, 5, 5, 0, 6, 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, /* ← */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* IS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, /* N */ }; evalfn evalfns[13][13] = { /* A F H MO DO AF ( ) [ ] ← IS N */ strand, dyadfun, 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, /* F */ 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, /* MO */ 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, /* AF */ lpar, lpar, lpar, lpar, lpar, 0, lpar, rpar, 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, /* ← */ assign, assign, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* IS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nameis, 0, 0, /* N */ }; Datum * eval(Statement *stmt) { errormsg = nil; /* start by looking up first variable if needed */ if(stmt->ntoks > 0 && stmt->toks[stmt->ntoks-1].tag == NameTag){ Datum *value = lookup(stmt->toks[stmt->ntoks-1]); if(value == nil) return nil; else stmt->toks[stmt->ntoks-1] = *value; } while(stmt->ntoks > 1){ int maxlevel = 0; int offset; evalfn fn = nil; traceprint("CURRENT: %S\n", ppdatums(stmt->toks, stmt->ntoks)); for(offset = stmt->ntoks-1; offset >= 0; offset--){ int level; retry: if(offset == 0) level = 0; else{ Datum left = stmt->toks[offset-1]; Datum right = stmt->toks[offset]; level = bindingstrengths[left.tag][right.tag]; } if(level == 0 && stmt->toks[offset-1].tag == NameTag){ Datum *value = lookup(stmt->toks[offset-1]); if(value == nil) return nil; else{ stmt->toks[offset-1] = *value; goto retry; } }else if(level < maxlevel){ Datum left = stmt->toks[offset]; Datum right = stmt->toks[offset+1]; fn = evalfns[left.tag][right.tag]; 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; } if(maxlevel == 0){ errormsg = L"No reduce rule. Syntax error."; return nil; }else{ stmt->toks[offset] = fn(stmt->toks[offset],stmt->toks[offset+1]); for(int i = offset+1; i < stmt->ntoks-1; i++) stmt->toks[i] = stmt->toks[i+1]; stmt->ntoks--; } } if(stmt->ntoks == 1){ if(stmt->next) return eval(stmt->next); else return stmt->toks; }else return nil; } 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 (%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); result.tag = ArrayTag; result.array = fnCatenateFirst(leftarr, rightarr); result.array->stranded = 1; return result; } Datum monadfun(Datum left, Datum right) { traceprint("Monadic function application\n"); Datum result; result.tag = ArrayTag; result.shy = 0; if(left.func.type == FunctypeDfn){ Symtab *tmpsymtab = currentsymtab; currentsymtab = newsymtab(); if(left.func.left){ Symbol *alpha = getsym(currentsymtab, L"⍺"); alpha->value.tag = ArrayTag; alpha->value.array = left.func.left; alpha->undefined = 0; } Symbol *omega = getsym(currentsymtab, L"⍵"); omega->value = right; omega->undefined = 0; Datum *dfnres = evalline(left.func.dfn); currentsymtab = tmpsymtab; return *dfnres; /* TODO what if the evaluation failed */ }else{ /* TODO handle undefined functions here */ if(left.func.left) result.array = dyadfunctiondefs[left.func.code](left.func.left, right.array); else result.array = monadfunctiondefs[left.func.code](right.array); } return result; } Datum dyadfun(Datum left, Datum right) { traceprint("Applying left argument to function\n"); Datum result; result.tag = BoundFunctionTag, result.func = right.func; result.func.left = left.array; return result; } Datum lpar(Datum left, Datum right) { /* build up a parthenthesised expression */ left.stmt.ntoks++; left.stmt.toks = realloc(left.stmt.toks, sizeof(Datum) * left.stmt.ntoks); left.stmt.toks[left.stmt.ntoks-1] = right; traceprint("LPAR: %S\n", ppdatums(left.stmt.toks, left.stmt.ntoks)); return left; } Datum rpar(Datum left, Datum right) { /* evaluate a parenthesis expression and return the result */ USED(right); traceprint("RPAR: %S\n", ppdatums(left.stmt.toks, left.stmt.ntoks)); Datum *result = eval(&left.stmt); 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; right.shy = 1; return right; }