#include #include #include #include "apl9.h" Statement * lexline(Rune *line, int toplevel) { int offset = 0; int len = runestrlen(line); Statement *stmt = emalloc(sizeof(Statement)); stmt->ntoks = 0; stmt->toks = mallocz(sizeof(Datum) * MAX_LINE_TOKENS, 1); stmt->guard = nil; stmt->next = nil; while(offset < len){ Rune *p; if(isspacerune(line[offset])){ offset++; continue; }else if(runestrchr(L"←⋄⍝⍬", line[offset])){ switch(line[offset]){ case L'←': stmt->toks[stmt->ntoks].tag = ArrowTag; break; case L'⋄': stmt->next = lexline(&line[offset+1], toplevel); goto end; case L'⍝': goto end; case L'⍬': stmt->toks[stmt->ntoks].tag = ArrayTag; stmt->toks[stmt->ntoks].array = allocarray(AtypeInt, 1, 0); stmt->toks[stmt->ntoks].array->shape[0] = 0; break; } offset++; }else if(!toplevel && line[offset] == ':'){ Rune buf[MAX_LINE_LENGTH]; Rune *p = buf; offset++; while(line[offset] != L'⋄' && offset < len){ *p = line[offset]; p++; offset++; } *p = 0; stmt->guard = lexline(buf, toplevel); stmt->ntoks--; }else if(line[offset] == '{'){ Rune buf[MAX_LINE_LENGTH]; Rune *p = buf; offset++; while(line[offset] != '}' && offset < len){ *p = line[offset]; p++; offset++; } if(line[offset] != '}') goto syntax_error; *p = 0; offset++; stmt->toks[stmt->ntoks].tag = FunctionTag; stmt->toks[stmt->ntoks].func.type = FunctypeDfn; stmt->toks[stmt->ntoks].func.dfn = runestrdup(buf); }else if(line[offset] == '('){ int unclosed = 1; Rune buf[MAX_LINE_LENGTH]; Rune *p = buf; offset++; while((line[offset] != ')' || unclosed > 1) && offset < len){ if(line[offset] == '(') unclosed++; else if(line[offset] == ')') unclosed--; *p = line[offset]; p++; offset++; } if(line[offset] != ')') goto syntax_error; *p = 0; offset++; stmt->toks[stmt->ntoks].tag = LParTag; stmt->toks[stmt->ntoks].stmt = *lexline(buf, toplevel); stmt->ntoks++; stmt->toks[stmt->ntoks].tag = RParTag; }else if(p = runestrchr(primfuncnames, line[offset])){ stmt->toks[stmt->ntoks].tag = FunctionTag; stmt->toks[stmt->ntoks].func.type = FunctypePrim; stmt->toks[stmt->ntoks].func.code = p-primfuncnames; offset++; }else if(p = runestrchr(primmonopnames, line[offset])){ stmt->toks[stmt->ntoks].tag = MonadicOpTag; stmt->toks[stmt->ntoks].operator.type = OperatortypePrim; stmt->toks[stmt->ntoks].operator.dyadic = 0; stmt->toks[stmt->ntoks].operator.code = p-primmonopnames; offset++; }else if(p = runestrchr(primdyadopnames, line[offset])){ stmt->toks[stmt->ntoks].tag = DyadicOpTag; stmt->toks[stmt->ntoks].operator.type = OperatortypePrim; stmt->toks[stmt->ntoks].operator.dyadic = 1; stmt->toks[stmt->ntoks].operator.code = p-primdyadopnames; offset++; }else if(p = runestrchr(primhybridnames, line[offset])){ stmt->toks[stmt->ntoks].tag = HybridTag; stmt->toks[stmt->ntoks].hybrid = p-primhybridnames; offset++; }else if(isdigitrune(line[offset]) || (line[offset] == L'¯' && isdigitrune(line[offset+1]))){ char buf[64]; char *p = buf; int floating = 0; if(line[offset] == L'¯'){ *p++ = '-'; offset++; } get_digits: while(isdigitrune(line[offset])) p += runetochar(p, &line[offset++]); if(!floating && line[offset] == '.'){ p += runetochar(p, &line[offset++]); floating = 1; goto get_digits; } *p = 0; stmt->toks[stmt->ntoks].tag = ArrayTag; stmt->toks[stmt->ntoks].array = floating ? mkscalarfloat(atof(buf)) : mkscalarint(atoll(buf)); }else if(runestrchr(L"⍺⍵", line[offset])){ Rune *name = L"?"; name[0] = line[offset]; stmt->toks[stmt->ntoks].tag = NameTag; stmt->toks[stmt->ntoks].symbol = getsym(currentsymtab, name); offset++; }else if(isalpharune(line[offset])){ Rune buf[64]; Rune *p = buf; while(isalpharune(line[offset]) || isdigitrune(line[offset])){ *p = line[offset]; p++; offset++; } *p = 0; stmt->toks[stmt->ntoks].tag = NameTag; stmt->toks[stmt->ntoks].symbol = getsym(currentsymtab, buf); }else if(runestrchr(L"⎕⍞", line[offset])){ /* quad names */ Rune buf[64]; Rune *p = buf; *p++ = line[offset++]; while(isalpharune(line[offset])) *p++ = toupperrune(line[offset++]); *p = 0; int valid = 0; for(int i = 0; quadnames[i].name != nil && !valid; i++){ if(runestrcmp(buf, quadnames[i].name) != 0) continue; valid = 1; stmt->toks[stmt->ntoks] = quadnamedatum(quadnames[i]); } if(!valid){ offset -= runestrlen(buf); goto syntax_error; } }else if(line[offset] == '\''){ Rune buf[1024]; /* stupid limit on literal string lengths */ Rune *b = buf; int done = 0; offset++; while(!done && offset < len){ if(line[offset] == '\'' && line[offset+1] != '\''){ *b = 0; done = 1; }else if(line[offset] == '\'' && line[offset+1] == '\''){ *b++ = '\''; offset++; }else *b++ = line[offset]; offset++; } if(!done){ offset = offset - (b-buf); goto syntax_error; } stmt->toks[stmt->ntoks].tag = ArrayTag; if(runestrlen(buf) == 1) stmt->toks[stmt->ntoks].array = mkscalarrune(buf[0]); else stmt->toks[stmt->ntoks].array = mkrunearray(buf); }else{ Rune *err; syntax_error: err = runesmprint("Can't lex: %S", &line[offset]); free(stmt->toks); free(stmt); throwerror(err, ESyntax); } stmt->ntoks++; } end: stmt->toks = realloc(stmt->toks, sizeof(Datum) * stmt->ntoks); return stmt; }