ref: 72abaa282749e37df7831959b1a344664b1827f3
dir: /n.y/
%{
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include "dat.h"
#include "fns.h"
int goteof;
int lexline;
char *lexfile = "<stdin>";
int yyparse(void);
void yyerror(char*);
%}
%union
{
char *sval;
long ival;
Typ *typ;
Nod *nod;
Nlst lst;
}
%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;
%token <ival> NUM
%type<nod> arg expr logexpr shifexpr addexpr mulexpr
%type<nod> unary sufexpr compexpr
%type<lst> args
%type<typ> type
%%
prog
: prog top
| top
top
: FUNC NAME '(' args ')' return '{' stmts '}'
| MOD NAME ';'
| USE NAME ';'
| def ';'
sdecls
:
| sdecls NAME ':' type ';'
def
: DEF NAME NAME
{
}
| DEF NAME STRUCT '{' sdecls '}'
{
}
type
: NAME { $$ = nil; }
| type '[' ']' { $$ = mktyslice($1); }
| type '[' NUM ']' { $$ = mktyarray($1, mklit($3)); }
| type '!' { $$ = $1; $$->linear = 1; }
return
: ARROWR type
|
unary
: NUM { $$ = mkexpr(Olit, mklit($1), nil); }
| NAME { $$ = mkexpr(Ovar, mksym($1), nil); }
| ARROWL unary { $$ = mkexpr(Orcv, $2, nil); }
| '(' expr ')' { $$ = $2; }
sufexpr
: unary '--' { $$ = mkexpr(Odec, $1, nil); }
| unary '++' { $$ = mkexpr(Oinc, $1, nil); }
| unary { $$ = $1; }
mulexpr
: mulexpr '*' sufexpr { $$ = mkexpr(Omul, $1, $3); }
| mulexpr '/' sufexpr { $$ = mkexpr(Odiv, $1, $3); }
| mulexpr '%' sufexpr { $$ = mkexpr(Omod, $1, $3); }
| sufexpr { $$ = $1; }
addexpr
: addexpr '+' mulexpr { $$ = mkexpr(Oadd, $1, $3); }
| addexpr '-' mulexpr { $$ = mkexpr(Osub, $1, $3); }
| mulexpr { $$ = $1; }
shifexpr
: shifexpr SHIFTL addexpr { $$ = mkexpr(Oshl, $1, $3); }
| shifexpr SHIFTR addexpr { $$ = mkexpr(Oshr, $1, $3); }
| addexpr { $$ = $1; }
compexpr
: compexpr '>' shifexpr { $$ = mkexpr(Ogt, $1, $3); }
| compexpr '<' shifexpr { $$ = mkexpr(Olt, $1, $3); }
| compexpr NOTEQ shifexpr { $$ = mkexpr(One, $1, $3); }
| compexpr EQ shifexpr { $$ = mkexpr(Oeq, $1, $3); }
| compexpr LTEQ shifexpr { $$ = mkexpr(Oge, $1, $3); }
| compexpr GTEQ shifexpr { $$ = mkexpr(Ole, $1, $3); }
| shifexpr { $$ = $1; }
logexpr
: logexpr OR compexpr { $$ = mkexpr(Olor, $1, $3); }
| logexpr AND compexpr { $$ = mkexpr(Oland, $1, $3); }
| compexpr { $$ = $1; }
expr
: { $$ = nil; }
| expr '=' logexpr { $$ = mkexpr(Oasn, $1, $3); }
| logexpr { $$ = $1; }
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 { $$ = mkdecl($1, $3, nil); }
args
: { $$ = ZL; }
| arg { $$ = append(ZL, $1); }
| args ',' arg { $$ = append($1, $3); }
%%
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')
lexline++;
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", lexline, 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;
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);
}