shithub: semblance

ref: bfd97dce0cd0b532b0a6065fd1cf891169ebd204
dir: /semblance.y/

View raw version
%{
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <bio.h>
#include <geometry.h>
#include "dat.h"
#include "fns.h"
%}
%union {
	int type;
	Node node;
}
%token	PRINT
%token	<type> TYPE
%token	<node> NUMBER ID CONST BLTIN UNDEF
%type	<node> expr exprs
%type	<node> asgn asgns
%right	'='
%%
list:	/* ε */		{ fprint(2, "list: ε\n"); }
	  prog		{ fprint(2, "list: prog\n"); }
	| list prog	{ fprint(2, "list: list prog\n"); }
	;

prog:	/* ε */		{ fprint(2, "prog: ε\n"); }
	| decls		{ fprint(2, "prog: decls\n"); }
	| asgns		{ fprint(2, "prog: asgns\n"); }
	| exprs		{ fprint(2, "prog: exprs\n"); }
	| PRINT exprs
	{
		fprint(2, "prog: PRINT exprs\n");
		if($2.type == NODENUM)
			fprint(2, "%g\n", $2.num);
		if($2.type == NODESYM){
			fprint(2, "%s = ", $2.sym->name);
			switch($2.sym->type){
			case ID:
				switch($2.sym->var.type){
				case TDOUBLE: fprint(2, "%g\n", $2.sym->var.dval); break;
				case TPOINT:
				case TVECTOR:
				case TNORMAL:
				case TQUAT: fprint(2, "%V\n", $2.sym->var.pval); break;
				}
				break;
			case CONST: fprint(2, "%g\n", $2.sym->dconst); break;
			case BLTIN: fprint(2, "f()\n"); break;
			}
		}
	}
	;

decls:	  decl		{ decltype = -1; fprint(2, "decls: decl\n"); }
	| decls decl	{ decltype = -1; fprint(2, "decls: decls decl\n"); }
	;

decl:	  TYPE { decltype = $1; } idlist ';'	{ fprint(2, "decl: TYPE idlist\n"); }
	;

idlist:	  ID
	{
		fprint(2, "idlist: ID\n");

		if($1.sym->type != UNDEF)
			yyerror("variable already exists");

		if(decltype < 0)
			yyerror("no type specified");

		$1.sym->type = ID;
		$1.sym->var.type = decltype;
		print("%s %s;\n", ctypename(decltype), $1.sym->name);
	}
	| idlist ',' ID
	{
		fprint(2, "idlist: ID , idlist\n");

		if($3.sym->type != UNDEF)
			yyerror("variable already exists");

		if(decltype < 0)
			yyerror("no type specified");

		$3.sym->type = ID;
		$3.sym->var.type = decltype;
		print("%s %s;\n", ctypename(decltype), $3.sym->name);
	}
	;

asgns:	  asgn ';'		{ fprint(2, "asgns: asgn\n"); }
	| asgns asgn ';'	{ fprint(2, "asgns: asgns asgn\n"); }
	;

asgn:	 ID '=' expr
	{
		fprint(2, "asgn: ID = expr\n");

		print("%s = ", $1.sym->name);
		switch($1.sym->var.type){
		case TDOUBLE:
			if($3.type == NODENUM)
				print("%g", $3.num);
			else if($3.sym->type == CONST)
				print("%g", $3.sym->dconst);
			else if($3.sym->type == ID && $3.sym->var.type == TDOUBLE)
				print("%s", $3.sym->name);
			else
				yyerror("illegal assignment");
			break;
		case TPOINT:
		case TVECTOR:
		case TNORMAL:
		case TQUAT:
			if($3.type == NODENUM)
				print("Pt3(%g,%g,%g,%g)", $3.num, $3.num, $3.num, $3.num);
			else if($3.sym->type == CONST)
				print("Pt3(%g,%g,%g,%g)",
					$3.sym->dconst,
					$3.sym->dconst,
					$3.sym->dconst,
					$3.sym->dconst);
			else if($3.sym->type == ID)
				switch($3.sym->var.type){
				case TDOUBLE:
					print("Pt3(%g,%g,%g,%g)",
						$3.sym->var.dval,
						$3.sym->var.dval,
						$3.sym->var.dval,
						$3.sym->var.dval);
					break;
				case TPOINT:
				case TVECTOR:
				case TNORMAL:
					print("%s", $3.sym->name);
					break;
				case TQUAT:
					print("Pt3(%g,%g,%g,%g)",
						$3.sym->var.pval.y,
						$3.sym->var.pval.z,
						$3.sym->var.pval.w,
						$3.sym->var.pval.x);
					break;
				}
			else
				yyerror("illegal assignment");
			break;
		}
		print(";\n");

		$$ = $1;
		break;
	}
	;

exprs:	  expr ';'		{ fprint(2, "exprs: expr\n"); }
	| exprs expr ';'	{ fprint(2, "exprs: exprs expr\n"); }
	;

expr:	  NUMBER	{ fprint(2, "expr: NUMBER %g\n", $1.num); }
	| ID		{ fprint(2, "expr: ID\n"); }
	;
%%

int decltype = -1;
Biobuf *bin;
int lineno;

void
yyerror(char *msg)
{
	fprint(2, "%s at line %d\n", msg, lineno);
	exits("syntax error");
}

int
yylex(void)
{
	Symbol *s;
	char buf[256], *p;
	Rune r;
	int t;

	do{
		r = Bgetrune(bin);
		if(r == '\n')
			lineno++;
	}while(isspace(r));

	if(r == Beof)
		return 0;

	if(r == '.' || isdigitrune(r)){
		Bungetrune(bin);
		Bgetd(bin, &yylval.node.num);
		yylval.node.type = NODENUM;
		return NUMBER;
	}

	if(isalpharune(r)){
		p = buf;
		do{
			if(p+runelen(r) - buf >= sizeof(buf))
				return r;	/* force syntax error. */
			p += runetochar(p, &r);
		}while((r = Bgetrune(bin)) != Beof &&
			(isalpharune(r) || isdigitrune(r)));
		Bungetrune(bin);
		*p = 0;

		if(strcmp(buf, "print") == 0)
			return PRINT;

		if((t = lookuptype(buf)) >= 0){
			yylval.type = t;
			return TYPE;
		}

		if((s = lookup(buf)) == nil)
			s = install(buf, UNDEF, 0);
		yylval.node.sym = s;
		yylval.node.type = NODESYM;

		return s->type == UNDEF || s->type == CONST ? ID : s->type;
	}

	return r;
}

void
usage(void)
{
	fprint(2, "usage: %s\n", argv0);
	exits("usage");
}

void
main(int argc, char *argv[])
{
	GEOMfmtinstall();
	ARGBEGIN{
	default: usage();
	}ARGEND;
	if(argc > 0)
		usage();

	bin = Bfdopen(0, OREAD);
	if(bin == nil)
		sysfatal("Bfdopen: %r");

	lineno++;
	init();

	yyparse();
//	int n;
//	char *s, *name;
//	while((n = yylex())){
//		s =	n == NUMBER? "NUMBER":
//			n == ID? "ID":
//			n == NODENUM? "NODENUM":
//			n == NODESYM? "NODESYM":
//			n == TYPE? "TYPE":
//			n == PRINT? "PRINT":
//			n == UNDEF? "UNDEF": nil;
//		name = n == ID? yylval.node.sym->name: "";
//		print("%d: %s%C%s\n", lineno, s?s:"", s?' ':n, name);
//	}

	Bterm(bin);
	exits(nil);
}