shithub: dfc

ref: 955e17e750cdeef05f22e7fe2be9d04211c705e6
dir: /dfc.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*);

enum{
	Big,
	Little,
};

int ordermode = Big;

enum{
	TCmplx,
	TNum,
	TUchar,
	TU16,
	TU32,
	TU64,
	TVLA,
};

typedef struct Field Field;
typedef struct Sym Sym;

struct Sym{
	char *name;
	int type;
	int val;
	char *from;
};

struct Field{
	char *name;
	int len;
	Sym sym;
};


Field	tobe[128];
int	ntobe;

Sym	defs[128];
int	ndef;

static void
mklower(char *d, char *e, char *s)
{
	assert(d <= e-1);
	for(; *s != 0 && d < e-1; s++){
		if(!isascii(*s))
			continue;
		*d++ = tolower(*s);
	}
	*d = 0;
}

static char*
size2type(int x)
{
	switch(x){
	case 1:
		return "uchar";
	case 2:
		return "u16int";
	case 3: case 4:
		return "u32int";
	case 5: case 6: case 7: case 8:
		return "u64int";
	default:
		yyerror("invalid size");
		return nil;
	}
}

static int
aligned(int x)
{
	switch(x){
	case 1:
	case 2:
	case 4:
	case 8:
		return 1;
	default:
		return 0;
	}
}

static void
byteprint(void)
{
	int x, y;
	int shift;

	if(ordermode == Big)
	for(x = 2; x <= 8; x++){
		print("#define GET%d(p) ", x);
		for(shift = 0, y = x-1; y >= 0; y--, shift += 8){
			print("(%s)(p)[%d]", size2type(x), y);
			if(shift != 0)
				print("<<%d", shift);
			if(y != 0)
				print(" | ");
		}
		print("\n");
		print("#define PUT%d(p, u) ", x);
		for(shift = 8*(x-1), y = 0; y < x; y++, shift -= 8){
			print("(p)[%d] = (u)", y);
			if(shift != 0)
				print(">>%d, ", shift);
		}
		print("\n");
	}

	if(ordermode == Little)
	for(x = 2; x <= 8; x++){
		print("#define GET%d(p) ", x);
		for(shift = 0, y = 0; y < x; y++, shift += 8){
			print("(%s)(p)[%d]", size2type(x), y);
			if(shift != 0)
				print("<<%d", shift);
			if(y != x-1)
				print(" | ");
		}
		print("\n");
		print("#define PUT%d(p, u) ", x);
		for(shift = 8*(x-1), y = x - 1; y >= 0; y--, shift -= 8){
			print("(p)[%d] = (u)", y);
			if(shift != 0)
				print(">>%d, ", shift);
		}
		print("\n");
	}
	print("\n");
}

static void
cprint(char *name)
{
	int i;
	char buf[128];

/*
	print("typedef struct %s %s;\n", name, name);
	print("struct %s{\n", name);
	for(i = 0; i < ntobe; i++){
		if(tobe[i].sym.type == TCmplx){
			print("\t%s %s;\n", tobe[i].sym.name, tobe[i].name);
			continue;
		}
		if(tobe[i].len == 0)
			print("\tuchar *%s;\n", tobe[i].name);
		else if(aligned(tobe[i].len))
			print("\t%s %s;\n", size2type(tobe[i].len), tobe[i].name);
		else
			print("\tuchar %s[%d];\n", tobe[i].name, tobe[i].len);
	}
	print("};\n\n");
*/

	mklower(buf, buf + sizeof buf - 1, name);
	print("long\nget%s(%s *ret, uchar *data)\n{\n\tlong n;\n\n\tn = 0;\n", buf, name);
	for(i = 0; i < ntobe; i++){
		switch(tobe[i].sym.type){
		case TCmplx:
			mklower(buf, buf + sizeof buf - 1, tobe[i].sym.name);
			print("\tn += get%s(&ret->%s, data+n);\n", buf, tobe[i].name);
			continue;
		case TVLA:
			print("\tret->%s = data+n;\n", tobe[i].name);
			print("\tn += ret->%s;\n", tobe[i].sym.from);
			continue;
		}
		if(tobe[i].len == 1)
			print("\tret->%s = data[n];\n", tobe[i].name);
		else if(aligned(tobe[i].len))
			print("\tret->%s = GET%d(data+n);\n", tobe[i].name, tobe[i].len);
		else
			print("\tmemcpy(ret->%s, data+n, %d);\n", tobe[i].name, tobe[i].len);
		print("\tn += %d;\n", tobe[i].len);
	}
	print("\treturn n;\n}\n\n");

	mklower(buf, buf + sizeof buf - 1, name);
	print("long\nput%s(uchar *dst, %s *src)\n{\n\tlong n;\n\n\tn = 0;\n", buf, name);
	for(i = 0; i < ntobe; i++){
		switch(tobe[i].sym.type){
		case TCmplx:
			mklower(buf, buf + sizeof buf - 1, tobe[i].sym.name);
			print("\tn += put%s(dst+n, &src->%s);\n", buf, tobe[i].name);
			continue;
		case TVLA:
			print("\tmemmove(dst+n, src->%s, src->%s);\n", tobe[i].name, tobe[i].sym.from);
			print("\tn += src->%s;\n", tobe[i].sym.from);
			continue;
		}
		if(tobe[i].len == 1)
			print("\tdst[n] = src->%s;\n", tobe[i].name);
		else if(aligned(tobe[i].len))
			print("\tPUT%d(dst+n, src->%s);\n", tobe[i].len, tobe[i].name);
		else
			print("\tmemcpy(dst+n, src->%s, %d);\n", tobe[i].name, tobe[i].len);
		print("\tn += %d;\n", tobe[i].len);
	}
	print("\treturn n;\n}\n\n");
}

%}

%union
{
	char *sval;
	long ival;
	Sym yval;
}

%type	<sval>	name
%type	<ival>	num
%type	<yval>	type

%left '{' '}' '[' ']' ';' '=' '(' ')' '.'

%token STRUCT TYPEDEF UCHAR U16 U32 U64
%token <sval>	NAME NUM CHAR
%token <ival>	VAR CMPLX

%%

prog:
	prog top
|	top
|

name:
	NAME
	{
		$$ = $1;
	}

num:
	NUM
	{
		$$ = atoi($1);
	}
|	VAR
	{
		$$ = defs[$1].val;
	}

type:
	UCHAR
	{
		$$.type = TUchar;
		$$.val = 1;
	}
|	U16
	{
		$$.type = TU16;
		$$.val = 2;
	}
|	U32
	{
		$$.type = TU32;	
		$$.val = 4;
	}
|	U64
	{
		$$.type = TU64;
		$$.val = 8;
	}
|	CMPLX
	{
		$$ = defs[$1];
	}

sem:
	sem ';'
|	';'

top:
	TYPEDEF STRUCT name name sem
|	STRUCT name '{' members '}' sem
	{
		cprint($2);
		defs[ndef].name = $2;
		defs[ndef].type = TCmplx;
		defs[ndef].val = -1;
		ntobe = 0;
		ndef++;
	}
|	name '=' num sem
	{
		defs[ndef].name = $1;
		defs[ndef].type = TNum;
		defs[ndef].val = $3;
		ndef++;
	}

members:
	members member
|	member

member:
	type name sem
	{
		tobe[ntobe].name = $2;
		tobe[ntobe].len = $1.val;
		tobe[ntobe].sym = $1;
		ntobe++;
	}
|	type name '[' num ']' sem
	{
		tobe[ntobe].name = $2;
		tobe[ntobe].len = $4;
		tobe[ntobe].sym = $1;
		ntobe++;
	}
|	type name '[' '.' name ']' sem
	{

		tobe[ntobe].name = $2;
		tobe[ntobe].len = 0;
		$1.type = TVLA;
		$1.from = $5;
		tobe[ntobe].sym = $1;
		ntobe++;
	}

%%

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
yyerror(char *s)
{
	fprint(2, "%d: %s\n", lineno, s);
	exits(s);
}

int
yylex(void)
{
	static char buf[200];
	char *p;
	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;
	case '#':
		while((c = getch()) > 0)
			if(c == '\n')
				break;
		goto Loop;
	}

	switch(c){
	case ';': case '=':
	case '{': case '}':
	case '[': case ']':
	case '(': case ')':
	case '.':
		return c;
	}

	ungetc();
	p = buf;
	for(;;){
		c = getch();
		if((c >= Runeself)
		|| (c == '_')
		|| (c == ':')
		|| (c >= 'a' && c <= 'z')
		|| (c >= 'A' && c <= 'Z')
		|| (c >= '0' && c <= '9')){
			*p++ = c;
			continue;
		}
		ungetc();
		break;
	}
	*p = '\0';

	if(strcmp(buf, "struct") == 0)
		return STRUCT;
	if(strcmp(buf, "typedef") == 0)
		return TYPEDEF;
	if(strcmp(buf, "uchar") == 0)
		return UCHAR;
	if(strcmp(buf, "u16int") == 0)
		return U16;
	if(strcmp(buf, "u32int") == 0)
		return U32;
	if(strcmp(buf, "u64int") == 0)
		return U64;

	for(i = 0; i < ndef; i++){
		if(strcmp(buf, defs[i].name) != 0)
			continue;
		yylval.ival = i;
		return defs[i].type == TNum ? VAR : CMPLX;
	}

	yylval.sval = strdup(buf);
	return (buf[0] >= '0' && buf[0] <= '9') ? NUM : NAME;
}

void
usage(void)
{
	fprint(2, "usage: %s [-lb] dat.h\n", argv0);
	exits("usage");
}

void
main(int argc, char **argv)
{
	ARGBEGIN{
	case 'l':
		ordermode = Little;
		break;
	case 'b':
		ordermode = Big;
		break;
	default:
		usage();
		break;
	}ARGEND;
	if(argc != 1)
		usage();
	bin = Bopen(argv[0], OREAD);
	goteof = 0;
	print("#include <u.h>\n#include <libc.h>\n#include \"%s\"\n\n", argv[0]);
	byteprint();
	while(!goteof)
		yyparse();
	Bterm(bin);
	exits(nil);
}