%include{
    #include "parser.h"

    // set prefix for generated parser
    #define yy wp
}

%name ParseWhatIs
%extra_argument { CParser* obj }

%parse_failure {
	obj->setError(true);
	PRINT(cerr << "parseWhatIs: Parse error" << endl);
}

%syntax_error {
	obj->setError(true);
	PRINT(cerr << "parseWhatIs: Syntax error" << endl);
}

%token_type { TokenWhatIs }
%token_prefix TOKWH_

type ::= struct(Map). {
	obj->setTypeMap(Map.map);
}

/*
	struct XY {
		...
	};
*/
struct(X) ::= STRUCT WORD BRACE_OPEN decl(Map) BRACE_CLOSE separator. {
	X.map = Map.map;
}

/*
	struct struct {
		...
	};
*/
struct(X) ::= STRUCT STRUCT BRACE_OPEN decl(Map) BRACE_CLOSE separator. {
	X.map = Map.map;
}

/*
	struct {
		...
	};
*/
struct(X) ::= STRUCT BRACE_OPEN decl(Map) BRACE_CLOSE separator. {
	X.map = Map.map;
}

decl(X) ::= . {
	   X.map = new QDict<QString>;
	   X.map->setAutoDelete(true);
}

decl(X) ::= decl(Root) line(Line). {
	X.map = Root.map;
	QString name;
	QString type;
	obj->splitType(Line.list, name, type);
	X.map->insert(name, new QString(type));
	
	delete Line.list;
	PRINT(cerr << name << " = " << type << endl);
}

/*
	struct XY var;
*/
decl(X) ::= decl(Root) STRUCT WORD(Sname) word(Member) separator. {
	X.map = Root.map;
	if (Sname.string != 0) {
		QString name;
		QString type;
		QList<QString> list;
		list.append(Sname.string);
		list.append(Member.string);
		obj->splitType(&list, name, type);
		X.map->insert(name, new QString(type));
		
		PRINT(cerr << name << " = " << type << endl);
	}
}

/*
	struct XY {
		...
	} var;
*/
decl(X) ::= decl(Root) STRUCT WORD(Sname) BRACE_OPEN decl BRACE_CLOSE word(Member) separator. {
	X.map = Root.map;
	if (Sname.string != 0) {
		QString name;
		QString type;
		QList<QString> list;
		list.append(Sname.string);
		list.append(Member.string);
		obj->splitType(&list, name, type);
		X.map->insert(name, new QString(type));
		
		PRINT(cerr << name << " = " << type << endl);
	}
}

/*
	struct {
		...
	} var;
*/
decl(X) ::= decl(Root) STRUCT BRACE_OPEN decl BRACE_CLOSE word separator. {
	// Anonymous structures will be ignored.
	X.map = Root.map;
}

/*
	enum test_t { ... } test
*/
decl(X) ::= decl(Root) ENUM WORD(Ename) BRACE_OPEN enum_content BRACE_CLOSE WORD(Member) separator. {
	X.map = Root.map;
	if (Ename.string != 0) {
		X.map->insert(*Member.string, new QString(*Ename.string));
		
		PRINT(cerr << *Member.string << " = " << Ename.string << endl);
	}
}

/*
	enum { ... } test
*/
decl(X) ::= decl(Root) ENUM BRACE_OPEN enum_content BRACE_CLOSE WORD separator. {
	X.map = Root.map;
}

/*
	A, B, C=4
*/
enum_content ::= WORD. {
}
enum_content ::= enum_content COMMA WORD. {
}
enum_content ::= enum_content EQUAL WORD. {
}


line(X) ::= ident(Root) separator. {
	X.list = Root.list;
	PRINT(cerr << "Line: " << endl);
}

ident(X) ::= WORD(Word). {
	X.list = new QList<QString>;
	X.list->append(Word.string);
}

ident(X) ::= ident(Root) word(Word). {
	X.list = Root.list;
	X.list->append(Word.string);
}

/*
	(*fkt)(x)
*/
ident(X) ::= ident(Root) PAREN_OPEN WORD(Fname) PAREN_CLOSE PAREN_OPEN nil_word(Arg) PAREN_CLOSE. {
	X.list = Root.list;
	X.list->append(new QString(QString("(*)(" + *Arg.string + ")")));
	if (Fname.string->at(0) == '*') {
		*Fname.string = Fname.string->mid(1);
	}
	X.list->append(Fname.string);
	delete Arg.string;
}

word(X) ::= WORD(A). {
	X.string = A.string;
}

word(X) ::= word(A) COLON WORD. {
	X.string = A.string;
}

/*
	foo[10]
*/
word(X) ::= word(A) BRACKET_OPEN WORD(Count) BRACKET_CLOSE. {
	X.string = new QString(*A.string + "[" + *Count.string + "]");
	delete A.string;
	delete Count.string;
}

nil_word(X) ::= . {
	X.string = new QString;
}

nil_word(X) ::= WORD(w). {
	X.string = w.string;
}

separator ::= SEP.
separator ::= separator SEP.
