shithub: hammer

ref: 469b6871283ee08925584726368cd100c4275fef
dir: /n.y/

View raw version
%{

#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 SHIFTL SHIFTR STRUCT
%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);
	}

return
:	'-' '>' TYPE
|

unary
:	NUM
|	NAME	

mulexpr
:	mulexpr '*' unary
|	mulexpr '/' unary
|	mulexpr '%' unary
|	unary


addexpr
:	addexpr '+' mulexpr
|	addexpr '-' mulexpr
|	mulexpr

compexpr
:	compexpr '>' addexpr
|	compexpr '<' addexpr
|	compexpr NOTEQ addexpr
|	addexpr


logexpr
:	logexpr OR compexpr
|	logexpr AND compexpr
|	compexpr

expr
:	
|	expr '=' logexpr
|	logexpr

stmts
:
|	stmts stmt

decl
:	NAME ':' TYPE
|	NAME ':' '=' expr

stmt
:	expr ';'
|	'{' stmts '}'
|	decl ';'

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,
	"<<", SHIFTR,
	">>", SHIFTL,
	"struct", STRUCT,
};

Biobuf *bin;

int
getch(void)
{
	int c;

	c = Bgetc(bin);
	if(c == Beof){
		goteof = 1;
		return -1;
	}
	if(c == '\n')
		lineno++;
	return c;
}

void
ungetc(void)
{
	Bungetc(bin);
}

void
wordlex(char *dst, int n)
{
	int c;

	while(--n > 0){
		c = getch();
		if((c >= Runeself)
		|| isalnum(c)){
			*dst++ = c;
			continue;
		}
		ungetc();
		break;
	}
	if(n <= 0)
		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 ',':
		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);
}