ref: 1ed1ea5a5c5fe9701feb49382ca0912e044e2144
dir: /n.y/
%{
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
int goteof;
int lineno;
int yyparse(void);
void yyerror(char*);
struct {
char *s;
/* todo */
} typetab[1000] = {
"byte",
"int",
"long",
"vlong",
"uint",
"ulong",
"uvlong",
"float32",
"float64",
nil,
};
void
addtype(char *s)
{
int i;
for(i = 0; i < nelem(typetab)-1; i++){
if(typetab[i].s != nil)
continue;
typetab[i].s = s;
typetab[i+1].s = nil;
}
}
%}
%union
{
char *sval;
long ival;
}
%token FUNC DEF IF FOR MOD USE OR AND NOTEQ EQ SHIFTL SHIFTR STRUCT ELSE ARROWR ARROWL GTEQ LTEQ
%token TYPE NAME NUM
%token <sval> NAME TYPE;
%token <ival> NUM
%%
prog
: prog top
| top
top
: FUNC NAME '(' args ')' return '{' stmts '}'
| MOD NAME ';'
| USE NAME ';'
| def ';'
sdecls
:
| sdecls NAME ':' type ';'
def
: DEF NAME TYPE
{
addtype($2);
}
| DEF NAME STRUCT '{' sdecls '}'
{
addtype($2);
}
type
: TYPE
| type '[' ']'
| type '[' NUM ']'
| type '!'
return
: ARROWR type
|
unary
: NUM
| NAME
| ARROWL NAME
| '(' expr ')'
sufexpr
: unary '--'
| unary '++'
| unary
mulexpr
: mulexpr '*' sufexpr
| mulexpr '/' sufexpr
| mulexpr '%' sufexpr
| sufexpr
addexpr
: addexpr '+' mulexpr
| addexpr '-' mulexpr
| mulexpr
shifexpr
: shifexpr SHIFTL addexpr
| shifexpr SHIFTR addexpr
| addexpr
compexpr
: compexpr '>' shifexpr
| compexpr '<' shifexpr
| compexpr NOTEQ shifexpr
| compexpr EQ shifexpr
| compexpr LTEQ shifexpr
| compexpr GTEQ shifexpr
| shifexpr
logexpr
: logexpr OR compexpr
| logexpr AND compexpr
| compexpr
expr
:
| expr '=' logexpr
| logexpr
stmts
:
| stmts stmt
decl
: NAME ':' type
| NAME ':' '=' expr
stmt
: expr ';'
| '{' stmts '}'
| decl ';'
| FOR '(' expr ')' stmt
| FOR '(' expr ';' expr ';' expr ')' stmt
| IF '(' expr ')' stmt ELSE stmt
| IF '(' expr ')' stmt
arg
: NAME ':' type
args
:
| arg
| args ',' arg
%%
struct {
char *s;
int type;
} keytab[] = {
"fn", FUNC,
"type", DEF,
"if", IF,
"for", FOR,
"mod", MOD,
"use", USE,
"&&", AND,
"||", OR,
"!=", NOTEQ,
"==", EQ,
"<=", LTEQ,
">=", GTEQ,
"<<", SHIFTR,
">>", SHIFTL,
"struct", STRUCT,
"else", ELSE,
"->", ARROWR,
"→", ARROWR,
"<-", ARROWL,
"←", ARROWL,
};
Biobuf *bin;
int
getch(void)
{
int c;
c = Bgetrune(bin);
if(c == Beof){
goteof = 1;
return -1;
}
if(c == '\n')
lineno++;
return c;
}
void
ungetc(void)
{
Bungetrune(bin);
}
void
wordlex(char *dst, int n)
{
Rune c;
char *e;
for(e = dst + n - UTFmax; dst < e;){
c = getch();
if((c >= Runeself)
|| isalnum(c)){
dst += runetochar(dst, &c);
continue;
}
ungetc();
break;
}
if(dst > e - UTFmax*2)
yyerror("symbol buffer overrun");
*dst = '\0';
}
void
yyerror(char *s)
{
fprint(2, "%d: %s\n", lineno, s);
exits(s);
}
int
yylex2(void)
{
static char buf[200];
int c;
int i;
Loop:
c = getch();
switch(c){
case -1:
return -1;
case ' ':
case '\t':
case '\n':
goto Loop;
case '/':
if(getch() != '*'){
ungetc();
goto Loop;
}
More:
while((c = getch()) > 0)
if(c == '*')
break;
if(c != '*')
goto Loop;
if(getch() == '/')
goto Loop;
goto More;
}
switch(c){
case ';': case '=':
case '{': case '}':
case '[': case ']':
case '(': case ')':
case '+': case '-':
case '*': case '/':
case '%': case ':':
case '>': case '<':
case ',': case '.':
return c;
}
ungetc();
wordlex(buf, sizeof buf);
for(i = 0; i < nelem(keytab); i++)
if(strcmp(keytab[i].s, buf) == 0)
return keytab[i].type;
for(i = 0; i < nelem(typetab); i++){
if(typetab[i].s == nil)
break;
if(strcmp(typetab[i].s, buf) == 0){
yylval.sval = strdup(buf);
return TYPE;
}
}
if(isdigit(buf[0])){
yylval.ival = atoi(buf);
return NUM;
}
yylval.sval = strdup(buf);
return NAME;
}
int debug;
int
yylex(void)
{
int c;
c = yylex2();
if(!debug)
return c;
if(c < Runeself)
fprint(2, "%c\n", c);
else if(c == NAME)
fprint(2, "NAME %s\n", yylval.sval);
else if(c == TYPE)
fprint(2, "TYPE %s\n", yylval.sval);
else if(c == NUM)
fprint(2, "NUM %ld\n", yylval.ival);
return c;
}
void
usage(void)
{
fprint(2, "usage: [-d] %s\n", argv0);
exits("usage");
}
void
main(int argc, char **argv)
{
ARGBEGIN{
case 'd':
debug++;
break;
default:
usage();
break;
}ARGEND;
if(argc > 0)
usage();
bin = Bfdopen(0, OREAD);
goteof = 0;
while(!goteof)
yyparse();
Bterm(bin);
exits(nil);
}