ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /limbo/lex.c/
#define Extern
#include "limbo.h"
#include "y.tab.h"
enum
{
Leof = -1,
Linestart = 0,
Mlower = 1,
Mupper = 2,
Munder = 4,
Malpha = Mupper|Mlower|Munder,
Mdigit = 8,
Msign = 16,
Mexp = 32,
Mhex = 64,
Mradix = 128,
HashSize = 1024,
MaxPath = 4096
};
typedef struct Keywd Keywd;
struct Keywd
{
char *name;
int token;
};
File **files; /* files making up the module, sorted by absolute line */
int nfiles;
static int lenfiles;
static int lastfile; /* index of last file looked up */
static char *incpath[MaxIncPath];
static Sym *symbols[HashSize];
static Sym *strings[HashSize];
static char map[256];
static Biobuf *bin;
static Line linestack[MaxInclude];
static int lineno;
static int linepos;
static int bstack;
static int ineof;
static int lasttok;
static YYSTYPE lastyylval;
static char srcdir[MaxPath];
static Keywd keywords[] =
{
"adt", Ladt,
"alt", Lalt,
"array", Larray,
"big", Ltid,
"break", Lbreak,
"byte", Ltid,
"case", Lcase,
"chan", Lchan,
"con", Lcon,
"continue", Lcont,
"cyclic", Lcyclic,
"do", Ldo,
"dynamic", Ldynamic,
"else", Lelse,
"exception", Lexcept,
"exit", Lexit,
"fixed", Lfix,
"fn", Lfn,
"for", Lfor,
"hd", Lhd,
"if", Lif,
"implement", Limplement,
"import", Limport,
"include", Linclude,
"int", Ltid,
"len", Llen,
"list", Llist,
"load", Lload,
"module", Lmodule,
"nil", Lnil,
"of", Lof,
"or", Lor,
"pick", Lpick,
"raise", Lraise,
"raises", Lraises,
"real", Ltid,
"ref", Lref,
"return", Lreturn,
"self", Lself,
"spawn", Lspawn,
"string", Ltid,
"tagof", Ltagof,
"tl", Ltl,
"to", Lto,
"type", Ltype,
"while", Lwhile,
0,
};
static Keywd tokwords[] =
{
"&=", Landeq,
"|=", Loreq,
"^=", Lxoreq,
"<<=", Llsheq,
">>=", Lrsheq,
"+=", Laddeq,
"-=", Lsubeq,
"*=", Lmuleq,
"/=", Ldiveq,
"%=", Lmodeq,
"**=", Lexpeq,
":=", Ldeclas,
"||", Loror,
"&&", Landand,
"::", Lcons,
"==", Leq,
"!=", Lneq,
"<=", Lleq,
">=", Lgeq,
"<<", Llsh,
">>", Lrsh,
"<-", Lcomm,
"++", Linc,
"--", Ldec,
"->", Lmdot,
"=>", Llabs,
"**", Lexp,
"EOF", Leof,
"eof", Beof,
0,
};
void
lexinit(void)
{
Keywd *k;
int i;
for(i = 0; i < 256; i++){
if(i == '_' || i > 0xa0)
map[i] |= Munder;
if(i >= 'A' && i <= 'Z')
map[i] |= Mupper;
if(i >= 'a' && i <= 'z')
map[i] |= Mlower;
if(i >= 'A' && i <= 'F' || i >= 'a' && i <= 'f')
map[i] |= Mhex;
if(i == 'e' || i == 'E')
map[i] |= Mexp;
if(i == 'r' || i == 'R')
map[i] |= Mradix;
if(i == '-' || i == '+')
map[i] |= Msign;
if(i >= '0' && i <= '9')
map[i] |= Mdigit;
}
memset(escmap, -1, sizeof(escmap));
escmap['\''] = '\'';
unescmap['\''] = '\'';
escmap['"'] = '"';
unescmap['"'] = '"';
escmap['\\'] = '\\';
unescmap['\\'] = '\\';
escmap['a'] = '\a';
unescmap['\a'] = 'a';
escmap['b'] = '\b';
unescmap['\b'] = 'b';
escmap['f'] = '\f';
unescmap['\f'] = 'f';
escmap['n'] = '\n';
unescmap['\n'] = 'n';
escmap['r'] = '\r';
unescmap['\r'] = 'r';
escmap['t'] = '\t';
unescmap['\t'] = 't';
escmap['v'] = '\v';
unescmap['\v'] = 'v';
escmap['0'] = '\0';
unescmap['\0'] = '0';
for(k = keywords; k->name != nil; k++)
enter(k->name, k->token);
}
int
cmap(int c)
{
if(c<0)
return 0;
if(c<256)
return map[c];
return Mlower;
}
void
lexstart(char *in)
{
char *p;
ineof = 0;
bstack = 0;
nfiles = 0;
lastfile = 0;
addfile(mkfile(strdup(in), 1, 0, -1, nil, 0, -1));
bin = bins[bstack];
lineno = 1;
linepos = Linestart;
secpy(srcdir, srcdir+MaxPath, in);
p = strrchr(srcdir, '/');
if(p == nil)
srcdir[0] = '\0';
else
p[1] = '\0';
}
static int
Getc(void)
{
int c;
if(ineof)
return Beof;
c = BGETC(bin);
if(c == Beof)
ineof = 1;
linepos++;
return c;
}
static void
unGetc(void)
{
if(ineof)
return;
Bungetc(bin);
linepos--;
}
static int
getrune(void)
{
int c;
if(ineof)
return Beof;
c = Bgetrune(bin);
if(c == Beof)
ineof = 1;
linepos++;
return c;
}
static void
ungetrune(void)
{
if(ineof)
return;
Bungetrune(bin);
linepos--;
}
void
addinclude(char *s)
{
int i;
for(i = 0; i < MaxIncPath; i++){
if(incpath[i] == 0){
incpath[i] = s;
return;
}
}
fatal("out of include path space");
}
File*
mkfile(char *name, int abs, int off, int in, char *act, int actoff, int sbl)
{
File *f;
f = allocmem(sizeof *f);
f->name = name;
f->abs = abs;
f->off = off;
f->in = in;
f->act = act;
f->actoff = actoff;
f->sbl = sbl;
return f;
}
int
addfile(File *f)
{
if(nfiles >= lenfiles){
lenfiles = nfiles+32;
files = reallocmem(files, lenfiles*sizeof(File*));
}
files[nfiles] = f;
return nfiles++;
}
void
includef(Sym *file)
{
Biobuf *b;
char *p, buf[MaxPath];
int i;
linestack[bstack].line = lineno;
linestack[bstack].pos = linepos;
bstack++;
if(bstack >= MaxInclude)
fatal("%L: include file depth too great", curline());
p = "";
if(file->name[0] != '/')
p = srcdir;
seprint(buf, buf+sizeof(buf), "%s%s", p, file->name);
b = Bopen(buf, OREAD);
for(i = 0; b == nil && i < MaxIncPath && incpath[i] != nil && file->name[0] != '/'; i++){
seprint(buf, buf+sizeof(buf), "%s/%s", incpath[i], file->name);
b = Bopen(buf, OREAD);
}
bins[bstack] = b;
if(bins[bstack] == nil){
yyerror("can't include %s: %r", file->name);
bstack--;
}else{
addfile(mkfile(strdup(buf), lineno+1, -lineno, lineno, nil, 0, -1));
lineno++;
linepos = Linestart;
}
bin = bins[bstack];
}
/*
* we hit eof in the current file
* revert to the file which included it.
*/
static void
popinclude(void)
{
Fline fl;
File *f;
int oline, opos, ln;
ineof = 0;
bstack--;
bin = bins[bstack];
oline = linestack[bstack].line;
opos = linestack[bstack].pos;
fl = fline(oline);
f = fl.file;
ln = fl.line;
lineno++;
linepos = opos;
addfile(mkfile(f->name, lineno, ln-lineno, f->in, f->act, f->actoff, -1));
}
/*
* convert an absolute Line into a file and line within the file
*/
Fline
fline(int absline)
{
Fline fl;
int l, r, m, s;
if(absline < files[lastfile]->abs
|| lastfile+1 < nfiles && absline >= files[lastfile+1]->abs){
lastfile = 0;
l = 0;
r = nfiles - 1;
while(l <= r){
m = (r + l) / 2;
s = files[m]->abs;
if(s <= absline){
l = m + 1;
lastfile = m;
}else
r = m - 1;
}
}
fl.file = files[lastfile];
fl.line = absline + files[lastfile]->off;
return fl;
}
/*
* read a comment
*/
static int
lexcom(void)
{
File *f;
char buf[StrSize], *s, *t, *act;
int i, n, c, actline;
i = 0;
while((c = Getc()) != '\n'){
if(c == Beof)
return -1;
if(i < sizeof(buf)-1)
buf[i++] = c;
}
buf[i] = 0;
lineno++;
linepos = Linestart;
if(strncmp(buf, "line ", 5) != 0 && strncmp(buf, "line\t", 5) != 0)
return 0;
for(s = buf+5; *s == ' ' || *s == '\t'; s++)
;
if(!(cmap(*s) & Mdigit))
return 0;
n = 0;
for(; cmap(c = *s) & Mdigit; s++)
n = n * 10 + c - '0';
for(; *s == ' ' || *s == '\t'; s++)
;
if(*s != '"')
return 0;
s++;
t = strchr(s, '"');
if(t == nil || t[1] != '\0')
return 0;
*t = '\0';
f = files[nfiles - 1];
if(n == f->off+lineno && strcmp(s, f->name) == 0)
return 1;
act = f->name;
actline = lineno + f->off;
if(f->act != nil){
actline += f->actoff;
act = f->act;
}
addfile(mkfile(strdup(s), lineno, n-lineno, f->in, act, actline - n, -1));
return 1;
}
Line
curline(void)
{
Line line;
line.line = lineno;
line.pos = linepos;
return line;
}
int
lineconv(Fmt *f)
{
Fline fl;
File *file;
Line inl, line;
char buf[StrSize], *s;
line = va_arg(f->args, Line);
if(line.line < 0)
return fmtstrcpy(f, "<noline>");
fl = fline(line.line);
file = fl.file;
s = seprint(buf, buf+sizeof(buf), "%s:%d", file->name, fl.line);
if(file->act != nil)
s = seprint(s, buf+sizeof(buf), " [ %s:%d ]", file->act, file->actoff+fl.line);
if(file->in >= 0){
inl.line = file->in;
inl.pos = 0;
seprint(s, buf+sizeof(buf), ": %L", inl);
}
return fmtstrcpy(f, buf);
}
static char*
posconv(char *s, char *e, Line line)
{
Fline fl;
if(line.line < 0)
return secpy(s, e, "nopos");
fl = fline(line.line);
return seprint(s, e, "%s:%d.%d", fl.file->name, fl.line, line.pos);
}
int
srcconv(Fmt *f)
{
Src src;
char buf[StrSize], *s;
src = va_arg(f->args, Src);
s = posconv(buf, buf+sizeof(buf), src.start);
s = secpy(s, buf+sizeof(buf), ",");
posconv(s, buf+sizeof(buf), src.stop);
return fmtstrcpy(f, buf);
}
int
lexid(int c)
{
Sym *sym;
char id[StrSize*UTFmax+1], *p;
Rune r;
int i, t;
p = id;
i = 0;
for(;;){
if(i < StrSize){
if(c < Runeself)
*p++ = c;
else{
r = c;
p += runetochar(p, &r);
}
i++;
}
c = getrune();
if(c == Beof
|| !(cmap(c) & (Malpha|Mdigit))){
ungetrune();
break;
}
}
*p = '\0';
sym = enter(id, Lid);
t = sym->token;
if(t == Lid || t == Ltid)
yylval.tok.v.idval = sym;
return t;
}
Long
strtoi(char *t, int base)
{
char *s;
Long v;
int c, neg, ck;
neg = 0;
if(t[0] == '-'){
neg = 1;
t++;
}else if(t[0] == '+')
t++;
v = 0;
for(s = t; c = *s; s++){
ck = cmap(c);
if(ck & Mdigit)
c -= '0';
else if(ck & Mlower)
c = c - 'a' + 10;
else if(ck & Mupper)
c = c - 'A' + 10;
if(c >= base){
yyerror("digit '%c' not radix %d", *s, base);
return -1;
}
v = v * base + c;
}
if(neg)
return -v;
return v;
}
static int
digit(int c, int base)
{
int cc, ck;
cc = c;
ck = cmap(c);
if(ck & Mdigit)
c -= '0';
else if(ck & Mlower)
c = c - 'a' + 10;
else if(ck & Mupper)
c = c - 'A' + 10;
else if(ck & Munder)
{}
else
return -1;
if(c >= base)
yyerror("digit '%c' not radix %d", cc, base);
return c;
}
double
strtodb(char *t, int base)
{
double num, dem;
int neg, eneg, dig, exp, c, d;
num = 0;
neg = 0;
dig = 0;
exp = 0;
eneg = 0;
c = *t++;
if(c == '-' || c == '+'){
if(c == '-')
neg = 1;
c = *t++;
}
while((d = digit(c, base)) >= 0){
num = num*base + d;
c = *t++;
}
if(c == '.')
c = *t++;
while((d = digit(c, base)) >= 0){
num = num*base + d;
dig++;
c = *t++;
}
if(c == 'e' || c == 'E'){
c = *t++;
if(c == '-' || c == '+'){
if(c == '-'){
dig = -dig;
eneg = 1;
}
c = *t++;
}
while((d = digit(c, base)) >= 0){
exp = exp*base + d;
c = *t++;
}
}
exp -= dig;
if(exp < 0){
exp = -exp;
eneg = !eneg;
}
dem = rpow(base, exp);
if(eneg)
num /= dem;
else
num *= dem;
if(neg)
return -num;
return num;
}
/*
* parse a numeric identifier
* format [0-9]+(r[0-9A-Za-z]+)?
* or ([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?
*/
int
lexnum(int c)
{
char buf[StrSize], *base;
enum { Int, Radix, RadixSeen, Frac, ExpSeen, ExpSignSeen, Exp, FracB } state;
double d;
Long v;
int i, ck;
i = 0;
buf[i++] = c;
state = Int;
if(c == '.')
state = Frac;
base = nil;
for(;;){
c = Getc();
if(c == Beof){
yyerror("end of file in numeric constant");
return Leof;
}
ck = cmap(c);
switch(state){
case Int:
if(ck & Mdigit)
break;
if(ck & Mexp){
state = ExpSeen;
break;
}
if(ck & Mradix){
base = &buf[i];
state = RadixSeen;
break;
}
if(c == '.'){
state = Frac;
break;
}
goto done;
case RadixSeen:
case Radix:
if(ck & (Mdigit|Malpha)){
state = Radix;
break;
}
if(c == '.'){
state = FracB;
break;
}
goto done;
case Frac:
if(ck & Mdigit)
break;
if(ck & Mexp)
state = ExpSeen;
else
goto done;
break;
case FracB:
if(ck & (Mdigit|Malpha))
break;
goto done;
case ExpSeen:
if(ck & Msign){
state = ExpSignSeen;
break;
}
/* fall through */
case ExpSignSeen:
case Exp:
if(ck & Mdigit){
state = Exp;
break;
}
goto done;
}
if(i < StrSize-1)
buf[i++] = c;
}
done:
buf[i] = 0;
unGetc();
switch(state){
default:
yyerror("malformed numerical constant '%s'", buf);
yylval.tok.v.ival = 0;
return Lconst;
case Radix:
*base++ = '\0';
v = strtoi(buf, 10);
if(v < 0)
break;
if(v < 2 || v > 36){
yyerror("radix '%s' must be between 2 and 36", buf);
break;
}
v = strtoi(base, v);
break;
case Int:
v = strtoi(buf, 10);
break;
case Frac:
case Exp:
d = strtod(buf, nil);
yylval.tok.v.rval = d;
return Lrconst;
case FracB:
*base++ = '\0';
v = strtoi(buf, 10);
if(v < 0)
break;
if(v < 2 || v > 36){
yyerror("radix '%s' must be between 2 and 36", buf);
break;
}
d = strtodb(base, v);
yylval.tok.v.rval = d;
return Lrconst;
}
yylval.tok.v.ival = v;
return Lconst;
}
int
escchar(void)
{
char buf[4+1];
int c, i;
c = getrune();
if(c == Beof)
return Beof;
if(c == 'u'){
for(i = 0; i < 4; i++){
c = getrune();
if(c == Beof || !(cmap(c) & (Mdigit|Mhex))){
yyerror("malformed \\u escape sequence");
ungetrune();
break;
}
buf[i] = c;
}
buf[i] = 0;
return strtoul(buf, 0, 16);
}
if(c < 256 && (i = escmap[c]) >= 0)
return i;
yyerror("unrecognized escape \\%C", c);
return c;
}
void
lexstring(int israw)
{
char *str;
int c, t, startlno;
Rune r;
int len, alloc;
alloc = 32;
len = 0;
str = allocmem(alloc * sizeof(str));
startlno = lineno;
for(;;){
c = getrune();
if(israw){
switch(c){
case '`':
yylval.tok.v.idval = enterstring(str, len);
return;
case '\n':
lineno++;
linepos = Linestart;
break;
case Beof:
t = lineno;
lineno = startlno;
yyerror("end of file in raw string constant");
lineno = t;
yylval.tok.v.idval = enterstring(str, len);
return;
}
}else{
switch(c){
case '\\':
c = escchar();
if(c != Beof)
break;
/* fall through */
case Beof:
yyerror("end of file in string constant");
yylval.tok.v.idval = enterstring(str, len);
return;
case '\n':
yyerror("newline in string constant");
lineno++;
linepos = Linestart;
yylval.tok.v.idval = enterstring(str, len);
return;
case '"':
yylval.tok.v.idval = enterstring(str, len);
return;
}
}
while(len+UTFmax+1 >= alloc){
alloc += 32;
str = reallocmem(str, alloc * sizeof(str));
}
r = c;
len += runetochar(&str[len], &r);
str[len] = '\0';
}
}
static int
lex(void)
{
int c;
loop:
yylval.tok.src.start.line = lineno;
yylval.tok.src.start.pos = linepos;
c = getrune(); /* ehg: outside switch() to avoid bug in VisualC++5.0 */
switch(c){
case Beof:
Bterm(bin);
if(bstack == 0)
return Leof;
popinclude();
break;
case '#':
if(lexcom() < 0){
Bterm(bin);
if(bstack == 0)
return Leof;
popinclude();
}
break;
case '\n':
lineno++;
linepos = Linestart;
goto loop;
case ' ':
case '\t':
case '\r':
case '\v':
case '\f':
goto loop;
case '"':
lexstring(0);
return Lsconst;
case '`':
lexstring(1);
return Lsconst;
case '\'':
c = getrune();
if(c == '\\')
c = escchar();
if(c == Beof){
yyerror("end of file in character constant");
return Beof;
}else
yylval.tok.v.ival = c;
c = Getc();
if(c != '\'') {
yyerror("missing closing '");
unGetc();
}
return Lconst;
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case ',':
case ';':
case '~':
return c;
case ':':
c = Getc();
if(c == ':')
return Lcons;
if(c == '=')
return Ldeclas;
unGetc();
return ':';
case '.':
c = Getc();
unGetc();
if(c != Beof && (cmap(c) & Mdigit))
return lexnum('.');
return '.';
case '|':
c = Getc();
if(c == '=')
return Loreq;
if(c == '|')
return Loror;
unGetc();
return '|';
case '&':
c = Getc();
if(c == '=')
return Landeq;
if(c == '&')
return Landand;
unGetc();
return '&';
case '^':
c = Getc();
if(c == '=')
return Lxoreq;
unGetc();
return '^';
case '*':
c = Getc();
if(c == '=')
return Lmuleq;
if(c == '*'){
c = Getc();
if(c == '=')
return Lexpeq;
unGetc();
return Lexp;
}
unGetc();
return '*';
case '/':
c = Getc();
if(c == '=')
return Ldiveq;
unGetc();
return '/';
case '%':
c = Getc();
if(c == '=')
return Lmodeq;
unGetc();
return '%';
case '=':
c = Getc();
if(c == '=')
return Leq;
if(c == '>')
return Llabs;
unGetc();
return '=';
case '!':
c = Getc();
if(c == '=')
return Lneq;
unGetc();
return '!';
case '>':
c = Getc();
if(c == '=')
return Lgeq;
if(c == '>'){
c = Getc();
if(c == '=')
return Lrsheq;
unGetc();
return Lrsh;
}
unGetc();
return '>';
case '<':
c = Getc();
if(c == '=')
return Lleq;
if(c == '-')
return Lcomm;
if(c == '<'){
c = Getc();
if(c == '=')
return Llsheq;
unGetc();
return Llsh;
}
unGetc();
return '<';
case '+':
c = Getc();
if(c == '=')
return Laddeq;
if(c == '+')
return Linc;
unGetc();
return '+';
case '-':
c = Getc();
if(c == '=')
return Lsubeq;
if(c == '-')
return Ldec;
if(c == '>')
return Lmdot;
unGetc();
return '-';
case '1': case '2': case '3': case '4': case '5':
case '0': case '6': case '7': case '8': case '9':
return lexnum(c);
default:
if(cmap(c) & Malpha)
return lexid(c);
yyerror("unknown character %c", c);
break;
}
goto loop;
}
int
yylex(void)
{
int t;
t = lex();
yylval.tok.src.stop.line = lineno;
yylval.tok.src.stop.pos = linepos;
lasttok = t;
lastyylval = yylval;
return t;
}
static char*
toksp(int t)
{
Keywd *k;
static char buf[256];
switch(t){
case Lconst:
snprint(buf, sizeof(buf), "%lld", lastyylval.tok.v.ival);
return buf;
case Lrconst:
snprint(buf, sizeof(buf), "%f", lastyylval.tok.v.rval);
return buf;
case Lsconst:
snprint(buf, sizeof(buf), "\"%s\"", lastyylval.tok.v.idval->name);
return buf;
case Ltid:
case Lid:
return lastyylval.tok.v.idval->name;
}
for(k = keywords; k->name != nil; k++)
if(t == k->token)
return k->name;
for(k = tokwords; k->name != nil; k++)
if(t == k->token)
return k->name;
if(t < 0 || t > 255)
fatal("bad token %d in toksp()", t);
buf[0] = t;
buf[1] = '\0';
return buf;
}
Sym*
enterstring(char *str, int n)
{
Sym *s;
char *p, *e;
ulong h;
int c, c0;
e = str + n;
h = 0;
for(p = str; p < e; p++){
c = *p;
c ^= c << 6;
h += (c << 11) ^ (c >> 1);
c = *p;
h ^= (c << 14) + (c << 7) + (c << 4) + c;
}
c0 = str[0];
h %= HashSize;
for(s = strings[h]; s != nil; s = s->next){
if(s->name[0] == c0 && s->len == n && memcmp(s->name, str, n) == 0){
free(str);
return s;
}
}
if(n == 0)
return enter("", 0);
s = allocmem(sizeof(Sym));
memset(s, 0, sizeof(Sym));
s->name = str;
s->len = n;
s->next = strings[h];
strings[h] = s;
return s;
}
int
symcmp(Sym *s, Sym *t)
{
int n, c;
n = s->len;
if(n > t->len)
n = t->len;
c = memcmp(s->name, t->name, n);
if(c == 0)
return s->len - t->len;
return c;
}
Sym*
stringcat(Sym *s, Sym *t)
{
char *str;
int n;
n = s->len + t->len;
str = allocmem(n+1);
memmove(str, s->name, s->len);
memmove(str+s->len, t->name, t->len);
str[n] = '\0';
return enterstring(str, n);
}
Sym*
enter(char *name, int token)
{
Sym *s;
char *p;
ulong h;
int c0, c, n;
c0 = name[0];
h = 0;
for(p = name; c = *p; p++){
c ^= c << 6;
h += (c << 11) ^ (c >> 1);
c = *p;
h ^= (c << 14) + (c << 7) + (c << 4) + c;
}
n = p - name;
h %= HashSize;
for(s = symbols[h]; s != nil; s = s->next)
if(s->name[0] == c0 && strcmp(s->name, name) == 0)
return s;
s = allocmem(sizeof(Sym));
memset(s, 0, sizeof(Sym));
s->hash = h;
s->name = allocmem(n+1);
memmove(s->name, name, n+1);
if(token == 0)
token = Lid;
s->token = token;
s->next = symbols[h];
s->len = n;
symbols[h] = s;
return s;
}
char*
stringpr(char *buf, char *end, Sym *sym)
{
char sb[30], *s, *p;
int i, c, n;
s = sym->name;
n = sym->len;
if(n > 10)
n = 10;
p = sb;
*p++ = '"';
for(i = 0; i < n; i++){
c = s[i];
switch(c){
case '\\':
case '"':
case '\n':
case '\r':
case '\t':
case '\b':
case '\a':
case '\v':
case '\0':
*p++ = '\\';
*p++ = unescmap[c];
break;
default:
*p++ = c;
break;
}
}
if(n != sym->len){
*p++ = '.';
*p++ = '.';
*p++ = '.';
}
*p++ = '"';
*p = 0;
return secpy(buf, end, sb);
}
void
warn(Line line, char *fmt, ...)
{
char buf[4096];
va_list arg;
if(errors || !dowarn)
return;
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
fprint(2, "%L: warning: %s\n", line, buf);
}
void
nwarn(Node *n, char *fmt, ...)
{
char buf[4096];
va_list arg;
if(errors || !dowarn)
return;
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
fprint(2, "%L: warning: %s\n", n->src.start, buf);
}
void
error(Line line, char *fmt, ...)
{
char buf[4096];
va_list arg;
errors++;
if(errors >= maxerr){
if(errors == maxerr)
fprint(2, "too many errors, stopping\n");
return;
}
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
fprint(2, "%L: %s\n", line, buf);
}
void
nerror(Node *n, char *fmt, ...)
{
char buf[4096];
va_list arg;
errors++;
if(errors >= maxerr){
if(errors == maxerr)
fprint(2, "too many errors, stopping\n");
return;
}
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
fprint(2, "%L: %s\n", n->src.start, buf);
}
void
yyerror(char *fmt, ...)
{
char buf[4096];
va_list arg;
errors++;
if(errors >= maxerr){
if(errors == maxerr)
fprint(2, "too many errors, stopping\n");
return;
}
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
if(lasttok != 0)
fprint(2, "%L: near ` %s ` : %s\n", curline(), toksp(lasttok), buf);
else
fprint(2, "%L: %s\n", curline(), buf);
}
void
fatal(char *fmt, ...)
{
char buf[4096];
va_list arg;
if(errors == 0 || isfatal){
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
fprint(2, "fatal limbo compiler error: %s\n", buf);
}
if(bout != nil)
remove(outfile);
if(bsym != nil)
remove(symfile);
if(isfatal)
abort();
exits(buf);
}
int
gfltconv(Fmt *f)
{
double d;
char buf[32];
d = va_arg(f->args, double);
g_fmt(buf, d, 'e');
return fmtstrcpy(f, buf);
}
char*
secpy(char *p, char *e, char *s)
{
int c;
if(p == e){
p[-1] = '\0';
return p;
}
for(; c = *s; s++){
*p++ = c;
if(p == e){
p[-1] = '\0';
return p;
}
}
*p = '\0';
return p;
}
char*
seprint(char *buf, char *end, char *fmt, ...)
{
va_list arg;
if(buf == end)
return buf;
va_start(arg, fmt);
buf = vseprint(buf, end, fmt, arg);
va_end(arg);
return buf;
}
void*
allocmem(ulong n)
{
void *p;
p = malloc(n != 0? n: 1);
if(p == nil)
fatal("out of memory");
return p;
}
void*
reallocmem(void *p, ulong n)
{
if(p == nil)
p = malloc(n);
else
p = realloc(p, n);
if(p == nil)
fatal("out of memory");
return p;
}