예제 #1
0
void convert_async(Lex& lex, const char *class_name, FILE *h, FILE *cpp)
{
	int		t, l;
	const char	*s, *e;
	Param		*params, *last, *next;
	bool		keep_params, timed_async, dynamic_event;

	keep_params = false;
	timed_async = false;
	dynamic_event = false;

	// we can have multiple dynamic as long as each have a different
	// function name; also, we need to mark them as being timed if
	// the timed flag is also specified
	lex.StartDynamic();

// first we parse the function
	// skip spaces
	do {
		t = lex.GetToken();
	} while(isspace(t) || t == '\n');
	if(t == '\0') {
eof:
		fprintf(stderr, "%s:%ld: error: EOF reached within an async declaration\n", lex.Filename(), lex.Line());
		g_errcnt++;
		return;
	}

	if(t != Lex::IDENTIFIER) {
		fprintf(stderr, "%s:%ld: error: async not followed by an identifier\n", lex.Filename(), lex.Line());
		g_errcnt++;
		return;
	}

	// we expect the name of the function
	s = lex.GetStart();
	e = lex.GetEnd();
	l = static_cast<int>(e - s);
	char* name = new char[l + 1];
	str_keeper sk(name);
	memcpy(name, s, l);
	name[l] = '\0';

	do {
		t = lex.GetToken();
	} while(isspace(t) || t == '\n');
	if(t == '\0') {
		goto eof;
	}

	if(t != '(') {
		fprintf(stderr, "%s:%ld: error: async function name not followed by (\n", lex.Filename(), lex.Line());
		g_errcnt++;
		return;
	}

	// now we read the parameters
	last = params = 0;
	do {
		t = get_param(lex, next);
		if(next != 0) {
			if(last != 0) {
				last->f_next = next;
			}
			if(params == 0) {
				params = next;
			}
			last = next;
		}
	} while(t != ')' && t != '\0');
	if(t == '\0') {
		goto eof;
	}

	// right after the ')' we can have a dynamic attribute!
	// the syntax is:
	//	__attribute__ ((dynamic[([<identifier>])]))
	do {
		 t = lex.GetToken();
	} while(isspace(t) || t == '\n');
	if(t != Lex::IDENTIFIER) {
		goto no_attribute;
	}
	s = lex.GetStart();
	e = lex.GetEnd();
	l = static_cast<int>(e - s);
	if(l != 13 || memcmp(s, "__attribute__", l) != 0) {
		fprintf(stderr, "%s:%ld: error: the keyword __attribute__ or = 0 was expected\n", lex.Filename(), lex.Line());
		g_errcnt++;
		goto skip_attr;
	}
	do {
		 t = lex.GetToken();
	} while(isspace(t) || t == '\n');
	if(t != '(') {
		fprintf(stderr, "%s:%ld: error: the keyword __attribute__ is expected to be followed by two '('\n", lex.Filename(), lex.Line());
		g_errcnt++;
		goto skip_attr;
	}
	do {
		 t = lex.GetToken();
	} while(isspace(t) || t == '\n');
	if(t != '(') {
		fprintf(stderr, "%s:%ld: error: the keyword __attribute__ is expected to be followed by two '('\n", lex.Filename(), lex.Line());
		g_errcnt++;
		goto skip_attr;
	}
more_attributes:
	do {
		 t = lex.GetToken();
	} while(isspace(t) || t == '\n');
	if(t != Lex::IDENTIFIER) {
		goto empty_attribute;
	}
	s = lex.GetStart();
	e = lex.GetEnd();
	l = static_cast<int>(e - s);
	if(l == 5 && memcmp(s, "timed", l) == 0) {
		timed_async = true;
		do {
			 t = lex.GetToken();
		} while(isspace(t) || t == '\n');
		goto empty_attribute;
	}
	else if(l == 13 && memcmp(s, "dynamic_event", l) == 0) {
		dynamic_event = true;
		do {
			 t = lex.GetToken();
		} while(isspace(t) || t == '\n');
		goto empty_attribute;
	}
	else if(l != 7 || memcmp(s, "dynamic", l) != 0) {
		fprintf(stderr, "%s:%ld: error: only one of 'timed' or 'dynamic' is supported as an attribute\n", lex.Filename(), lex.Line());
		g_errcnt++;
		do {
			 t = lex.GetToken();
		} while(isspace(t) || t == '\n');
		goto empty_attribute;
	}
	do {
		 t = lex.GetToken();
	} while(isspace(t) || t == '\n');
	if(t == '(') {
		// a user name may be specified!
		do {
			 t = lex.GetToken();
		} while(isspace(t) || t == '\n');
		if(t == Lex::IDENTIFIER) {
			s = lex.GetStart();
			e = lex.GetEnd();
			l = static_cast<int>(e - s);
			char* dname = new char[l + 1];
			str_keeper sk(dname);
			memcpy(dname, s, l);
			dname[l] = '\0';

// here we have (1) the name of the dynamic function
//		(2) the list of parameters for that function

			keep_params = lex.AddDynamic(params, dname, name);

			do {
				 t = lex.GetToken();
			} while(isspace(t) || t == '\n');
		}
		else {
			keep_params = lex.AddDynamic(params, "DynamicEvent", name);
		}
		if(t != ')') {
			fprintf(stderr, "%s:%ld: error: a ')' was expected after the dynamic attribute name\n", lex.Filename(), lex.Line());
			g_errcnt++;
			goto skip_attr;
		}
		do {
			 t = lex.GetToken();
		} while(isspace(t) || t == '\n');
	}
	else {
		keep_params = lex.AddDynamic(params, "DynamicEvent", name);
	}
empty_attribute:
	if(t == ',') {
		goto more_attributes;
	}
	if(t != ')') {
		fprintf(stderr, "%s:%ld: error: two ')' were expected to terminate the __attribute__\n", lex.Filename(), lex.Line());
		g_errcnt++;
		goto skip_attr;
	}
	do {
		 t = lex.GetToken();
	} while(isspace(t) || t == '\n');
	if(t != ')') {
		fprintf(stderr, "%s:%ld: error: two ')' were expected to terminate the __attribute__\n", lex.Filename(), lex.Line());
		g_errcnt++;
	}


skip_attr:
	// at the end we expect ' = 0'
	do {
		 t = lex.GetToken();
	} while(isspace(t) || t == '\n');
no_attribute:
	if(t != '=') {
		fprintf(stderr, "%s:%ld: error: = 0 is expected for all async functions\n", lex.Filename(), lex.Line());
		g_errcnt++;
	}
	else {
		do {
			t = lex.GetToken();
		} while(isspace(t) || t == '\n');
		if(t != Lex::NUMBER) {
			fprintf(stderr, "%s:%ld: error: = 0 is expected for all async functions\n", lex.Filename(), lex.Line());
			g_errcnt++;
		}
		else {
			// WARNING: we're not testing the number, we expect 0...
			t = lex.GetToken();
		}
	}

	if(t != ';') {
		fprintf(stderr, "%s:%ld: error: ; was expected at the end of a function declaration\n", lex.Filename(), lex.Line());
		g_errcnt++;
	}

// Finally, we got it all, let's convert the result...
	// declare the virtual function
	fprintf(h, "virtual void %s(", name);

	if(dynamic_event) {
		fprintf(h, "const molib::moName& __name");
	}

	next = params;
	if(next == 0) {
		if(!dynamic_event) {
			fprintf(h, "void");
		}
	}
	else {
		while(next != 0) {
			if(next != params) {
				fprintf(h, ", ");
			}
			fprintf(h, "%s", next->f_type);
			if(next->f_default_value != 0) {
				fprintf(h, " = %s", next->f_default_value);
			}
			next = next->f_next;
		}
	}
	fprintf(h, ") = 0;\n");

	// declare the static function
	fprintf(h, "\tstatic void Post%s(molib::moEventPipeBroadcast *__broadcast", name);
	fprintf(cpp, "void %s::Post%s(molib::moEventPipeBroadcast *__broadcast", class_name, name);

	if(dynamic_event) {
		fprintf(h, ", const molib::moName& __name");
		fprintf(cpp, ", const molib::moName& __name");
	}

	if(timed_async) {
		fprintf(h, ", time_t __time");
		fprintf(cpp, ", time_t __time");
	}

	next = params;
	while(next != 0) {
		fprintf(h, ", %s", next->f_type);
		fprintf(cpp, ", %s", next->f_type);
		if(next->f_default_value != 0) {
			fprintf(h, " = %s", next->f_default_value);
		}
		next = next->f_next;
	}
	fprintf(h, ");\n");

	fprintf(cpp,
")\n"
"{\n"
"\tclass __Event : public molib::moReceiversEvent\n"
"\t{\n"
"\tpublic:\n"
"\t\t__Event(");

	if(dynamic_event) {
		fprintf(cpp, "const molib::moName __name");
	}

	if(timed_async) {
		fprintf(cpp, "time_t __time");
	}

	next = params;
	if(next == 0) {
		if(!dynamic_event && !timed_async) {
			fprintf(cpp, "void");
		}
	}
	else {
		if(dynamic_event || timed_async) {
			fprintf(cpp, ", ");
		}
		fprintf(cpp, "%s", next->f_type);
		next = next->f_next;
		while(next != 0) {
			fprintf(cpp, ", %s", next->f_type);
			next = next->f_next;
		}
	}

	fprintf(cpp, ")\n"
"\t\t\t: molib::moReceiversEvent(\"%s\")",
		name);

	next = params;
	while(next != 0) {
		fprintf(cpp, ",\n"
"\t\t\t  f_%s(%s)", next->f_name, next->f_name);
		next = next->f_next;
	}

	if(dynamic_event) {
		fprintf(cpp, ",\n"
"\t\t\t  f___name(__name)");
	}

	fprintf(cpp, "\n"
"\t\t{\n");

	if(timed_async) {
		fprintf(cpp,
"\t\t\tSetTime(__time);\n"
);
	}

	fprintf(cpp,
"\t\t}\n"
"\t\t__Event(const __Event& event)\n"
"\t\t\t: molib::moReceiversEvent(event)");

	next = params;
	while(next != 0) {
		fprintf(cpp, ",\n"
"\t\t\t  f_%s(event.f_%s)", next->f_name, next->f_name);
		next = next->f_next;
	}

	if(dynamic_event) {
		fprintf(cpp, ",\n"
"\t\t\t  f___name(event.f___name)");
	}

	fprintf(cpp, "\n"
"\t\t{\n"
"\t\t}\n"
"\t\tconst char *GetClassName(void) const\n"
"\t\t{\n"
"\t\t\treturn \"molib::moBase::moEvent::__Event(%s)\";\n"
"\t\t}\n"
"\t\tvirtual molib::moEventSPtr Duplicate(void) const\n"
"\t\t{\n"
"\t\t\treturn new __Event(*this);\n"
"\t\t}\n"
"\t\tvirtual void SendToReceivers(const molib::moSortedList& receivers)\n"
"\t\t{\n"
"\t\t\tmolib::moList::position_t idx, max;\n"
"\t\t\t%s *r;\n"
"\t\t\tmax = receivers.Count();\n"
"\t\t\tfor(idx = 0; idx < max; ++idx) {\n"
"\t\t\t\tr = dynamic_cast<%s *>(receivers.Get(idx));\n"
"\t\t\t\tif(r != 0) {\n"
"\t\t\t\t\tr->%s(",
		name, class_name, class_name, name);

	if(dynamic_event) {
		fprintf(cpp, "f___name");
	}

	next = params;
	while(next != 0) {
		if(next != params || dynamic_event) {
			fprintf(cpp, ", ");
		}
		fprintf(cpp, "f_%s", next->f_name);
		next = next->f_next;
	}

	fprintf(cpp, ");\n"
"\t\t\t\t}\n"
"\t\t\t}\n"
"\t\t}\n");

	if(params != 0) {
		fprintf(cpp,
"\tprivate:\n");

		next = params;
		while(next != 0) {
			fprintf(cpp, "\t\t%s;\n", next->FType());
			next = next->f_next;
		}
	}

	if(dynamic_event) {
		fprintf(cpp, "\t\tmolib::moName f___name;\n");
	}

	fprintf(cpp,
"\t} __event");

	if(params != 0 || dynamic_event || timed_async) {
		fprintf(cpp, "(");

		if(dynamic_event) {
			fprintf(cpp, "__name");
		}

		if(timed_async) {
			fprintf(cpp, "%s__time", dynamic_event ? ", " : "");
		}

		next = params;
		if(next != 0) {
			if(dynamic_event || timed_async) {
				fprintf(cpp, ", ");
			}
			fprintf(cpp, "%s", next->f_name);
			next = next->f_next;
			while(next != 0) {
				fprintf(cpp, ", %s", next->f_name);
				next = next->f_next;
			}
		}

		fprintf(cpp, ")");
	}

	fprintf(cpp, ";\n"
"\t__broadcast->Post(__event);\n"
"}\n"
"\n");

	if(timed_async) {
		lex.TimedDynamic();
	}

	if(!keep_params) {
		delete params;
	}
}
예제 #2
0
void parse_class(Lex& lex, FILE *h, FILE *cpp)
{
	int		t, l, brackets;
	const char	*s, *e;

	do {
		t = lex.GetToken();
		lex.Write(h);
	} while(isspace(t) || t == '\n');
	if(t != Lex::IDENTIFIER) {
		// is it possible that we don't have an identifier after the keyword class?!
		fprintf(stderr, "%s:%ld: error: expected an identifier after the 'class' keyword\n", lex.Filename(), lex.Line());
		g_errcnt++;
		return;
	}
	// we got the class name!
	s = lex.GetStart();
	e = lex.GetEnd();
	l = static_cast<int>(e - s);
	char* class_name = new char[l + 1];
	str_keeper sk(class_name);
	memcpy(class_name, s, l);
	class_name[l] = '\0';

	brackets = 0;
	for(;;) {
		t = lex.GetToken();
		if(t == '\0') {
			// that's a big problem in the source file!
			return;
		}
		if(t == ';') {
			if(brackets == 0) {
				// in this special case, we don't have a full declaration
				// i.e.:   class Stuff;
				lex.Write(h);
				return;
			}
		}
		else if(t == '{') {
			brackets++;
		}
		else if(t == '}') {
			if(brackets == 0) {
				fprintf(stderr, "%s:%ld: error: could not find { in a class definition\n", lex.Filename(), lex.Line());
				g_errcnt++;
			}
			else {
				brackets--;
			}
			if(brackets == 0) {
				break;
			}
		}
		else if(t == Lex::IDENTIFIER) {
			s = lex.GetStart();
			e = lex.GetEnd();
			if(e - s == 5 && memcmp(s, "class", 5) == 0) {
				// warning: this is a recursive call...
				lex.Write(h);
				parse_class(lex, h, cpp);
			}
			else if(e - s == 5 && memcmp(s, "async", 5) == 0) {
				// we found an asynchroneous function
				convert_async(lex, class_name, h, cpp);
				continue;
			}
		}
		lex.Write(h);
	}
	// once a class is being closed, we need to put the dynamic
	// functions if any were defined
	Dynamic *d = lex.GetDynamic();
	if(d != 0) {
		fprintf(h, "public:\n");
		while(d != 0) {
			d->Output(lex, h, cpp, class_name);
			d = d->Next();
		}
	}
	lex.ClearDynamic();
	// we don't expect the lexical input to be messed up by
	// the Dynamic::Output() calls...
	lex.Write(h);
}
예제 #3
0
int get_param(Lex& lex, Param *& p)
{
	const char *s, *e;
	int t, paren;
	p = 0;
	for(;;) {
		do {
			t = lex.GetToken();
		} while(isspace(t) || t == '\n');
		if(t == '\0') {
			return t;
		}
		if(t == ',' || t == ')') {
			if(p == 0) {
				if(t == ',') {
					fprintf(stderr, "%s:%ld: error: , not expected here\n", lex.Filename(), lex.Line());
					g_errcnt++;
				}
				return t;
			}
			break;
		}
		if(p == 0) {
			p = new Param;
		}

		if(t == '=') {
			break;
		}
		s = lex.GetStart();
		if(t == '(') {
			p->f_function = true;
			paren = 1;
			do {
				t = lex.GetToken();
				if(t == '(') {
					paren++;
				}
				else if(t == ')') {
					paren--;
				}
			} while(paren != 0 && t != '\0');
		}
		e = lex.GetEnd();

		p->AppendType(s, static_cast<int>(e - s));
	}

// if the type is just 'void' and t is ')' then we don't want it
	if(strcmp(p->f_type, "void") == 0) {
		if(t != ')') {
			fprintf(stderr, "%s:%ld: error: invalid usage of type void\n", lex.Filename(), lex.Line());
			g_errcnt++;
			return t;
		}
		delete p;
		p = 0;
		return t;
	}

// compute the name of the parameter
	p->DefineName();

// special case of default values
	if(t == '=') {
		do {
			t = lex.GetToken();
		} while(isspace(t) || t == '\n');
		if(t == '\0') {
			return t;
		}
		if(t == ',') {
			fprintf(stderr, "%s:%ld: error: default value missing for parameter %s\n", lex.Filename(), lex.Line(), p->f_type);
			g_errcnt++;
			return t;
		}
		s = lex.GetStart();
		do {
			e = lex.GetEnd();
			t = lex.GetToken();
		} while(t != ',' && t != ')' && t != '\0');
		if(t == '\0') {
			return t;
		}
		p->SetDefaultValue(s, static_cast<long>(e - s));
	}

	return t;
}