ref: c1cebeee3da60bac9fdde3d8b2caac29c27ef912
dir: /lexer.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <geometry.h>
#include "dat.h"
#include "fns.h"
extern int debuglexer;
static Token Teof = {TEOF};
static Token Terr = {-1};
static int
isbasedigitrune(Rune r, int base)
{
switch(base){
case 2:
return r == '0' || r == '1';
case 8:
return r >= '0' && r <= '7';
case 16:
return isdigitrune(r)
|| (r >= 'a' && r <= 'f')
|| (r >= 'A' && r <= 'F');
}
return isdigitrune(r);
}
static Token
scan(Lexer *l)
{
Token tok;
char buf[256], *p;
Rune r;
int base;
begin:
memset(&tok, 0, sizeof(Token));
do{
r = Bgetrune(l->in);
if(r == '\n')
l->ln.line++;
}while(isspacerune(r));
if(r == Beof)
return Teof;
if(r == '/'){
switch(Bgetrune(l->in)){
case '/':
do
r = Bgetrune(l->in);
while(r != Beof && r != '\n');
Bungetrune(l->in);
goto begin;
case '*':
comment:
do{
r = Bgetrune(l->in);
if(r == Beof)
return Teof;
else if(r == '\n')
l->ln.line++;
}while(r != '*');
while(r == '*'){
r = Bgetrune(l->in);
if(r == Beof)
return Teof;
else if(r == '\n')
l->ln.line++;
else if(r == '/')
goto begin;
}
goto comment;
}
Bungetrune(l->in);
}
if(isdigitrune(r)){
if(r == '0'){
r = Bgetc(l->in);
switch(r){
case 'b': base = 2; break;
case 'o': base = 8; break;
case 'x': base = 16; break;
default:
Bungetc(l->in);
goto decimal;
}
p = buf;
while((r = Bgetrune(l->in)) != Beof && isbasedigitrune(r, base)){
if(p+runelen(r) >= buf + sizeof(buf)){
werrstr("number is too long");
return Terr;
}
p += runetochar(p, &r);
}
Bungetrune(l->in);
*p = 0;
tok.v = strtoll(buf, nil, base);
}else{
decimal:
Bungetrune(l->in);
Bgetd(l->in, &tok.v);
}
tok.type = TNUM;
}else if(isalpharune(r) || r == '_'){
p = buf;
do{
if(p+runelen(r) >= buf + sizeof(buf)){
werrstr("lexeme is too long");
return Terr;
}
p += runetochar(p, &r);
}while((r = Bgetrune(l->in)) != Beof
&& (isalpharune(r) || isdigitrune(r) || r == '_'));
Bungetrune(l->in);
*p = 0;
if((tok.type = lookupkw(buf)) < 0){
tok.s = estrdup(buf);
tok.type = TID;
}
}else if(r == '"'){
p = buf;
while((r = Bgetrune(l->in)) != Beof && r != '"' && r != '\n'){
if(p+runelen(r) >= buf + sizeof(buf)){
werrstr("string is too long");
return Terr;
}
p += runetochar(p, &r);
}
if(r != '"'){
werrstr("unterminated string");
return Terr;
}
*p = 0;
tok.s = estrdup(buf);
tok.type = TSTR;
}else if(opstart(r)){
p = buf;
p += runetochar(p, &r);
do{
r = Bgetrune(l->in);
if(p+runelen(r) >= buf + sizeof(buf)){
werrstr("op token is too long");
return Terr;
}
p += runetochar(p, &r);
*p = 0;
}while(findop(buf) >= 0);
Bungetrune(l->in);
*--p = 0;
tok.type = findop(buf);
}else
tok.type = r;
return tok;
}
int
lex(Lexer *l)
{
if(l->peektok.type > 0){
l->tok = l->peektok;
memset(&l->peektok, 0, sizeof(Token));
}else
l->tok = scan(l);
if(debuglexer)
fprint(2, "lex: '%s'\n", gettokenname(l->tok.type));
return l->tok.type;
}
int
peek(Lexer *l)
{
if(l->peektok.type <= 0)
l->peektok = scan(l);
if(debuglexer)
fprint(2, "peek: '%s'\n", gettokenname(l->peektok.type));
return l->peektok.type;
}
int
expect(Lexer *l, int t)
{
if(lex(l) != t){
werrstr("expected '%s', got '%s'",
gettokenname(t), gettokenname(l->tok.type));
return 0;
}
return 1;
}
int
expectany(Lexer *l, ...)
{
va_list a;
int t, e;
va_start(a, l);
t = lex(l);
while((e = va_arg(a, int)) != 0)
if(t == e)
return 1;
va_end(a);
werrstr("unexpected '%s'", gettokenname(t));
return 0;
}
int
gotany(Lexer *l, ...)
{
va_list a;
int t;
va_start(a, l);
while((t = va_arg(a, int)) != 0)
if(peek(l) == t){
lex(l);
return 1;
}
va_end(a);
return 0;
}
int
gottype(Lexer *l)
{
return gotany(l, TDOUBLE, TPT2, TPT3, TVEC2,
TVEC3, TNORMAL2, TNORMAL3, TQUAT,
TMAT3, TMAT4, 0);
}