ref: a89ada0279a41c1bd6664dc385044702f78fffb4
dir: /lexer.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <geometry.h>
#include "dat.h"
#include "fns.h"
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);
return l->tok.type;
}
int
peek(Lexer *l)
{
if(l->peektok.type <= 0)
l->peektok = scan(l);
return l->peektok.type;
}
int
expect(Lexer *l, int t)
{
if(lex(l) != t){
werrstr("expected '%C', got '%C' (%s)",
t, l->tok.type, gettokenname(&l->tok));
return 0;
}
return 1;
}
int
gottype(Lexer *l)
{
switch(peek(l)){
case TDOUBLE:
case TPT2:
case TPT3:
case TVEC2:
case TVEC3:
case TNORMAL2:
case TNORMAL3:
case TQUAT:
case TMAT3:
case TMAT4:
lex(l);
return 1;
}
return 0;
}