CMDscan.l and CMDgram.y - help please!
by Konrad Kiss · in Torque Game Engine · 03/14/2009 (1:05 pm) · 6 replies
I'd like Torque to be able to accept inline function definitions as parameters of another function.
Right now, we use callbacks like this:
What I'm looking for is this:
How hard would it be to modify the existing parser to allow this? Does anyone have a good solution to achieve what I'm looking for? Did anyone ever find a solution to this?
I need this very badly to not lose control over my script sources. I am about to deal with a great number of callbacks, so this would mean a lot of help to me.
I'd be very thankful to anyone who'd help me solve this! Thanks in advance, any reply is greatly appreciated!
Right now, we use callbacks like this:
function testFunction() {
%retval = myFuncCall(%variable, "callbackFunction");
}
function callbackFunction(%someparam) {
echo(%someparam);
}What I'm looking for is this:
function testFunction() {
%retval = myFuncCall(%variable, function(%someparam) {
echo(%someparam);
});
}How hard would it be to modify the existing parser to allow this? Does anyone have a good solution to achieve what I'm looking for? Did anyone ever find a solution to this?
I need this very badly to not lose control over my script sources. I am about to deal with a great number of callbacks, so this would mean a lot of help to me.
I'd be very thankful to anyone who'd help me solve this! Thanks in advance, any reply is greatly appreciated!
About the author
http://about.me/konrad.kiss
#2
03/18/2009 (7:30 pm)
Can't you add them to a list, then at the end of parsing, before you move to bytecode generation, append them to the AST? This would probably be outside the parser.
#3
My biggest problem is that I'm unable to see the parsing plan as a whole. I am now familiar with the CMDscan and CMDgram files, but I don't quite get it how these are integrated into Torque. Because of this, I am not able to tell what the scopes of the different variables are, and that made me stand in one place for a while now.
I see where the bitcode is generated, what I'm looking for is CodeBlock::compileExec, right?
I've found the parsing code in CodeBlock that will make the ConsoleParser parse the code:
(btw, really cool solution to let people use any parser for Torque)
Anyway, so that code creates my statementList. Are you saying that I should create another list like statementList, and use that to define embedded functions through appending any such code - something like this? :
And so in compileExec, I compile the new list after the normal statementList. Plus I have to modify the function definition to allow for noname functions which get registered with a generated name. So that way I don't have to ever poke the strings.
Well, at first I was gasping for air after your hint, but it did eventually lead me here, so many thanks. If I misunderstood you please let me know. I have serious doubts that I will be able to get through this, so any further hints are very welcome. Until then, I will give this a try, and see where this takes me.
Many thanks!
03/19/2009 (2:29 am)
Ben, thanks a lot for your help. To tell the truth, I'm not 100% sure I get what you mean, but I did my best to understand :)My biggest problem is that I'm unable to see the parsing plan as a whole. I am now familiar with the CMDscan and CMDgram files, but I don't quite get it how these are integrated into Torque. Because of this, I am not able to tell what the scopes of the different variables are, and that made me stand in one place for a while now.
I see where the bitcode is generated, what I'm looking for is CodeBlock::compileExec, right?
I've found the parsing code in CodeBlock that will make the ConsoleParser parse the code:
smCurrentParser->setScanBuffer(string, fileName); smCurrentParser->restart(NULL); smCurrentParser->parse();
(btw, really cool solution to let people use any parser for Torque)
Anyway, so that code creates my statementList. Are you saying that I should create another list like statementList, and use that to define embedded functions through appending any such code - something like this? :
| rwDEFINE '(' var_list_decl ')' '{' statement_list '}'
{
$$ = ConstantNode::alloc(generated_name);
inlineFnList->append(the whole function);
}And so in compileExec, I compile the new list after the normal statementList. Plus I have to modify the function definition to allow for noname functions which get registered with a generated name. So that way I don't have to ever poke the strings.
Well, at first I was gasping for air after your hint, but it did eventually lead me here, so many thanks. If I misunderstood you please let me know. I have serious doubts that I will be able to get through this, so any further hints are very welcome. Until then, I will give this a try, and see where this takes me.
Many thanks!
#4
03/19/2009 (5:20 am)
Looks like it works! Thanks Ben, I'll make a resource of this soon.
#5
(Tom Bampton did the multiparser support, one of many cool features he has added to the engine.)
03/19/2009 (12:52 pm)
Hahaha.... Awesome! I'm glad it worked out! Having anonymous functions is really useful, it's really cool to see it in Torque. Nice work, Konrad! :)(Tom Bampton did the multiparser support, one of many cool features he has added to the engine.)
#6
The resource: http://www.garagegames.com/community/blogs/view/16723
Thanks again Ben.
03/20/2009 (1:57 pm)
:) Wasn't very likely, huh?The resource: http://www.garagegames.com/community/blogs/view/16723
Thanks again Ben.
Associate Konrad Kiss
Bitgap Games
I've managed to make the parser accept an unnamed function definition as an expression. It gets a generated name that's based on an incremented U32. I can pass the name back to the function call in which the callback is defined inline. So when I call the example above, myFuncCall would actually receive the generated function name as the second parameter, so it is able to use that name - possibly in an eval.
Right now, my problem is that I still need to register the function. I saw two solutions for this:
a) I call FunctionDeclStmtNode::alloc with the generated function name, a NULL namespace, and the parameters and statements that are passed. The problem with this approach is that $$ must be a statement, while $$ is an expression where this is being parsed. So FunctionDeclStmtNode::alloc should return an expression, but it looks as if statements and expressions here are not really compatible.
b) I pass the whole function declaration to newCodeBlock->compileExec as a char *. But I have no idea how to get the currently matching nodes as a string.
| rwDEFINE '(' var_list_decl ')' '{' statement_list '}' { autoFuncID++; char * bfr = "autoFN_"; char uib[22] = ""; _itoa(autoFuncID, uib, 22); dStrcat(bfr, uib); StringTableEntry autoFnName = StringTable->insert(bfr); CodeBlock *newCodeBlock = new CodeBlock(); StringTableEntry name = StringTable->insert(autoFnName); char *scrpt = "function "; dStrcat(scrpt, bfr); dStrcat(scrpt, "("); dStrcat(scrpt, ); // this needs a string represenation dStrcat(scrpt, ") {"); dStrcat(scrpt, ); // so does this one dStrcat(scrpt, "}n"); newCodeBlock->compileExec(name, scrpt, false, 0); delete [] scrpt; $$ = ConstantNode::alloc(bfr); delete [] bfr; }If anyone could be of help here, I'd be extremely thankful.
If someone can point me in the right direction, I can throw in Cliff Construction Kit licenses as compensation.
Thanks a lot in advance,
--Konrad