View previous topic :: View next topic |
Author |
Message |
rko
Joined: 24 May 2006 Posts: 12
|
Posted: Mon Jun 12, 2006 6:52 am Post subject: enki question |
|
|
hi,
is possible to call add a user supplied function in a rule and call it ?? like:
test1 ::=
{
( "9100"
| "9101"
| "9103"
| "9105"
| "9106"
) AnyLine:y
myFunction(x,y) --------- user supplied
};
i like the tool very much, but it would be nice to be able to insert a .code{{{my code}}} at any point in the grammar.
________
Ford do Brasil picture
Last edited by rko on Sun Feb 06, 2011 9:45 pm; edited 1 time in total |
|
Back to top |
|
|
pragma
Joined: 28 May 2004 Posts: 607 Location: Washington, DC
|
Posted: Mon Jun 12, 2006 11:49 am Post subject: Re: enki question |
|
|
rko wrote: | hi,
is possible to call add a user supplied function in a rule and call it ?? like:
test1 ::=
{
( "9100"
| "9101"
| "9103"
| "9105"
| "9106"
) AnyLine:y
myFunction(x,y) --------- user supplied
};
i like the tool very much, but it would be nice to be able to insert a .code{{{my code}}} at any point in the grammar. |
Gotcha.
I deliberately avoided this kind of thing to help maintain the distinction between frontend, backend and supporting code - kind of like the MVC model in GUI design. Don't worry, it's easy enough to work around.
The most straightforward way is to invoke the function as the predicate for the rule itself:
Code: |
test1
= bool myFunction(x,y)
::=
{
( "9100"
| "9101"
| "9103"
| "9105"
| "9106"
):x AnyLine:y
};
|
Enki doesn't support 'void' return types for functions yet, so just have it return a bool or int for the time being. As your particular rule is wrapped in a 'zeroOrMore' expression, there is a valid grammar where neither x or y are populated. Should that be the case, be advised that x and y will be passed as the .init of whatever type they are.
Also, keep in mind that Enki doesn't prefix function calls with "this.", so the function/method/delegate/opCall doesn't have to be a part of the parser class - it just has to be within the scope of compilation.
Other methods:
1) A less elegant way is to use another rule, and take advantage of the fact that Enki's rules accept parameters. This may be useful if you want to invoke something, but not necessarily have it be in response to the parser traversing a particular point in the grammar.
Code: | Test1 ::= ... Kludge!(x,y);
Kludge(x,y) = myfunction(x,y) ::= Foo; |
Keep in mind that in order for the above to work, "Foo" must be an expression that succeeds - something like !eoi would be a good choice.
2) The @ syntax is provided to bind a user-defined identifier to a binding. However, the binding is *optional*, so it can stand alone in the syntax. You can exploit this to call a method that has no parameters - while not useful for what you're doing in this case, it might be of some help.
Code: | Test1 ::= @myFunction; |
I may expand this later to allow parameters, but for now, this is as good as it gets.
3) You may have noticed that the code-generator prefixes generated rules with "parse_" and places them as methods in the class. There is nothing keeping you from rolling your own parameterized rule and inserting it like so:
Code: |
.define("bool","MyFunction",false,"");
Test1 ::= ... MyFunction!(x,y);
.code{{{
ResultT!(bool) parse_MyFunction(String x,String y){
/* custom code goes here */
return ResultT!(bool)(true); // returns w/value so the 'rule' succeeds
}
}}}
|
The only major drawback here is that like all rules, it must return a ResultT!() of some kind. 'bool' is used here as a throwaway, but you could just as easily return a useful type (like String) and bind to it if need be. _________________ -- !Eric.t.Anderton at gmail |
|
Back to top |
|
|
rko
Joined: 24 May 2006 Posts: 12
|
Posted: Mon Jun 12, 2006 11:52 pm Post subject: |
|
|
thanx for the quick answer and the very helpful explanations.
Code: | test ::=
{
( "9100"
| "9101"
| "9103"
| "9105"
| "9106"
):x AnyLine:y myFunction!(x,y)
}; |
i decided to try method 3 first
.define("bool","myFunction","false","");
this is the generate:
/*
Code: | test
::= { ( "9100"| "9101"| "9103"| "9105"| "9106"):x AnyLine:y myFunction!(bind_x,bind_y)} ;
*/
public ResultT!(bool) parse_test(){
debug writefln("parse_test()");
uint start = position;
//no declarations
String bind_x
String bind_y
String bind_x
String bind_y
{//Expression
uint start = position;
{//ZeroOrMoreExpr
uint termPos;
loop47:
termPos = position;
{//Expression
uint start = position;
{//GroupExpr
uint start = position;
{//Expression
uint start = position;
if((terminal("9100").success) || (terminal("9101").success) || (terminal("9103").success) || (terminal("9105").success) || (terminal("9106").success)){
clearErrors();
}else{
position = start;
goto mismatch50;
}
}
smartAssign!(String,String)(bind_x,sliceData(start,position));
}
if(!(parse_AnyLine().assign!(String)(bind_y))){
goto mismatch50;
}
if(!(parse_myFunction(bind_x,bind_y).success)){
goto mismatch50;
}
goto match49;
mismatch50:
position = start;
goto loopend48;
match49:
clearErrors();
goto loop47;
}
loopend48:
{}
}
goto match45;
mismatch46:
position = start;
goto mismatch44;
match45:
clearErrors();
goto match43;
}
match43:
debug writefln("parse_test() PASS");
return ResultT!(bool)(true);
mismatch44:
position = start;
return ResultT!(bool)(false);
} |
the variables String bind_x and String bind_y are generated to often. i might misunderstand the bool as throwaway, but should the failure of "parse_myFunction" return a false from test?
the very first of the possibilities:
Code: | test = bool myFunction(x,y) ::=
{
( "9100"
| "9101"
| "9103"
| "9105"
| "9106"
):x AnyLine:y
}; |
this is the generate:
Code: | public ResultT!(bool) parse_test(){
debug writefln("parse_test()");
uint start = position;
String bind_x;
String bind_y;
{//Expression
uint start = position;
{//ZeroOrMoreExpr
uint termPos;
loop49:
termPos = position;
{//Expression
uint start = position;
{//GroupExpr
uint start = position;
{//Expression
uint start = position;
if((terminal("9100").success) || (terminal("9101").success) || (terminal("9103").success) || (terminal("9105").success) || (terminal("9106").success)){
clearErrors();
}else{
position = start;
goto mismatch52;
}
}
smartAssign!(String,String)(bind_x,sliceData(start,position));
}
if(!(parse_AnyLine().assign!(String)(bind_y))){
goto mismatch52;
}
goto match51;
mismatch52:
position = start;
goto loopend50;
match51:
clearErrors();
goto loop49;
}
loopend50:
{}
}
goto match47;
mismatch48:
position = start;
goto mismatch46;
match47:
clearErrors();
goto match45;
}
match45:
debug writefln("parse_DATENTRAEGERHEADER() PASS");
auto value = myFunction(bind_x,bind_y);
return ResultT!(bool)(value);
mismatch46:
position = start;
return ResultT!(bool)();
} |
here i unfortunatly would have to collect strings in an array to hand it to the function "myFunction".
rko
________
Yamaha YBR 125 specifications
Last edited by rko on Sun Feb 06, 2011 9:45 pm; edited 1 time in total |
|
Back to top |
|
|
pragma
Joined: 28 May 2004 Posts: 607 Location: Washington, DC
|
Posted: Tue Jun 13, 2006 9:04 am Post subject: |
|
|
rko wrote: | thanx for the quick answer and the very helpful explanations. |
No problem. So far, you're one of the first few people to provide feedback, so I'm eager to make sure that this tool works as intended.
i decided to try method 3 first
Code: | test
::= { ( "9100"| "9101"| "9103"| "9105"| "9106"):x AnyLine:y myFunction!(bind_x,bind_y)} ; |
the variables String bind_x and String bind_y are generated to often.[/quote]
"Generated too often"? What exactly do you mean here by this? I'm not sure what you mean.
Quote: | i might misunderstand the bool as throwaway, but should the failure of "parse_myFunction" return a false from test? |
Not exactly - pass/fail is a semantic supplied by the ResultT!() template that is completely distinct from the value that it stores. So returing true/false doesn't affect pass/fail. This was done so I could work with scalar types (int,float,char, etc) as return values, as each scalar's .init value is also a valid runtime state (unlike 'null' with pointers).
In short, ResultT!() defines pass/fail like so:
return ResultT!(SomeType)(value); // pass
return ResultT!(SomeType)(); // fail
Just those idioms as appropriate for what your custom function is doing. Also, take a look at the BaseParser in the SDK, for how Enki handles some of the lower-level rules like whitespace and identifier chars. I think you'll find those helpful.
Quote: |
Code: | test = bool myFunction(x,y) ::=
{
( "9100"
| "9101"
| "9103"
| "9105"
| "9106"
):x AnyLine:y
}; |
here i unfortunatly would have to collect strings in an array to hand it to the function "myFunction". |
This is quite true, and I forgot to mention that - my apologies. The grammar above would have to use the :~ operator and probably have x and y defined as arrays to work correctly. My guess is, that's not what you're looking for. _________________ -- !Eric.t.Anderton at gmail |
|
Back to top |
|
|
brad Site Admin
Joined: 22 Feb 2004 Posts: 490 Location: Atlanta, GA USA
|
Posted: Tue Jun 13, 2006 9:21 am Post subject: |
|
|
rko,
Your email is getting kicked back to me as being bogus. Can you please fix it in your profile?
Thx,
BA |
|
Back to top |
|
|
rko
Joined: 24 May 2006 Posts: 12
|
Posted: Tue Jun 13, 2006 2:00 pm Post subject: email |
|
|
sorry, seems like i can't change the profile (must be to stupid).
on the email addr, the 1 is to much
rko
________
Kingswood Estate
Last edited by rko on Sun Feb 06, 2011 9:45 pm; edited 1 time in total |
|
Back to top |
|
|
rko
Joined: 24 May 2006 Posts: 12
|
Posted: Tue Jun 13, 2006 2:11 pm Post subject: enki |
|
|
the too much is, that is it generated twice, such as:
Code: | //no declarations
String bind_x
String bind_y
String bind_x <----------------------------
String bind_y <----------------------------
{//Expression
uint start = position;
{//ZeroOrMoreExpr
|
if one does the following:
Code: | test = bool myFunction(x,y) ::=
{
( "9100":z
| "9101"
| "9103"
| "9105"
| "9106"
):x AnyLine:y
};
|
than the generated code for x and y is correct, but the code for variable z (String bind_y) is missing the semicolon.
i really like the tool. up to now, i used coco, antlr or an old meta4 generator.
Quote: | My guess is, that's not what you're looking for.
|
well, what i am trying to do is to disect some old ascii files. as an example:
017310327011975
^-first 3 char need to be discarded
^-the next 4 chars tell you what to do with rest, which are the data
01631057001902
020310650999 KOELN
rko
________
vapor genie vaporizer
Last edited by rko on Sun Feb 06, 2011 9:46 pm; edited 1 time in total |
|
Back to top |
|
|
rko
Joined: 24 May 2006 Posts: 12
|
Posted: Tue Jun 13, 2006 2:13 pm Post subject: |
|
|
shoot,
the
than the generated code for x and y is correct, but the code for variable z (String bind_y) is missing the semicolon.
should be
than the generated code for x and y is correct, but the code for variable z (String bind_z) is missing the semicolon.
________
Yamaha DX7 specifications
Last edited by rko on Sun Feb 06, 2011 9:46 pm; edited 1 time in total |
|
Back to top |
|
|
brad Site Admin
Joined: 22 Feb 2004 Posts: 490 Location: Atlanta, GA USA
|
Posted: Tue Jun 13, 2006 3:21 pm Post subject: Re: email |
|
|
rko wrote: | sorry, seems like i can't change the profile (must be to stupid).
on the email addr, the 1 is to much
rko |
done |
|
Back to top |
|
|
pragma
Joined: 28 May 2004 Posts: 607 Location: Washington, DC
|
Posted: Tue Jun 13, 2006 3:52 pm Post subject: Re: enki |
|
|
Quote: | than the generated code for x and y is correct, but the code for variable z (String bind_y) is missing the semicolon. |
Yikes! Sorry about that. I'll look into the code-generator and fix that bug.
Quote: |
i really like the tool. up to now, i used coco, antlr or an old meta4 generator. |
Thank you! I'm glad you like it.
[quote]
well, what i am trying to do is to disect some old ascii files. as an example:
017310327011975
^-first 3 char need to be discarded
^-the next 4 chars tell you what to do with rest, which are the data
01631057001902
020310650999 KOELN
/quote]
Ahh I see. I think you'll find Enki more than up to the task. _________________ -- !Eric.t.Anderton at gmail |
|
Back to top |
|
|
pragma
Joined: 28 May 2004 Posts: 607 Location: Washington, DC
|
Posted: Tue Jun 13, 2006 8:37 pm Post subject: |
|
|
RKO,
I just updated Enki to 1.1 - check it out in the downloads section of SVN or in the wiki. This update features bugfixes to the problems that you found earlier, plus some enhancements.
You can now use '@' to call custom methods. I think this might clean your code up a bit - I may even have a use for it myself in my own code.
Code: |
Foobar ::= "foo":x "bar":y @customFunc!(x,y);
|
Enjoy! _________________ -- !Eric.t.Anderton at gmail |
|
Back to top |
|
|
rko
Joined: 24 May 2006 Posts: 12
|
Posted: Wed Jun 14, 2006 3:59 am Post subject: |
|
|
i am enyoying!! thanx!
got another question so, or meight be an error.
Code: | AnyChar = String value ::= ["\\":~value] any:~value ;
AnyLine = String text ::= {AnyChar:text} eol RidFirstThree; |
produces the following generate with ==========unreachable code:
Code: | AnyLine
= String text
::= { AnyChar:text } eol RidFirstThree;
*/
public ResultT!(String) parse_AnyLine(){
debug writefln("parse_AnyLine()");
uint start = position;
String bind_text;
{//Expression
uint start = position;
{//ZeroOrMoreExpr
uint start = position;
uint termPos;
loop15:
termPos = position;
{//Expression
uint start = position;
if((parse_eol().success && parse_RidFirstThree().success)){
clearErrors();
goto loopend16;
}else{
position = start;
}
}
{//Expression ====================== unreachable code
uint start = position;
if((parse_AnyChar().assign!(String)(bind_text))){
clearErrors();
goto loop15;
}else{
setError("Expected AnyChar.");
position = start;
goto mismatch14;
}
}
loopend16:
{}
}
goto match13;
mismatch14:
position = start;
goto mismatch12;
match13:
clearErrors();
goto match11;
}
match11:
debug writefln("parse_AnyLine() PASS");
return ResultT!(String)(bind_text);
mismatch12:
position = start;
return ResultT!(String)();
} |
maybe i misinterpret this, but it doesn't look wright.
and it gets even fancier if you
Code: | AnyLine = String text ::= {AnyChar:text} eol {RidFirstThree}; |
also, when i via the .code statement insert a variable of type String, can i assign a parsed value to it?
Code: | "3000":z customvariable = z ?? |
thanx in advance
rko
________
herbal health shop
Last edited by rko on Sun Feb 06, 2011 9:46 pm; edited 1 time in total |
|
Back to top |
|
|
pragma
Joined: 28 May 2004 Posts: 607 Location: Washington, DC
|
Posted: Wed Jun 14, 2006 7:46 am Post subject: |
|
|
[quote="rko"]i am enyoying!! thanx!
got another question so, or meight be an error.
Code: | AnyChar = String value ::= ["\\":~value] any:~value ;
AnyLine = String text ::= {AnyChar:text} eol RidFirstThree; |
produces the following generate with ==========unreachable code:
Code: | AnyLine
= String text
::= { AnyChar:text } eol RidFirstThree;
*/
public ResultT!(String) parse_AnyLine(){
debug writefln("parse_AnyLine()");
uint start = position;
String bind_text;
{//Expression
uint start = position;
{//ZeroOrMoreExpr
uint start = position;
uint termPos;
loop15:
termPos = position;
{//Expression
uint start = position;
if((parse_eol().success && parse_RidFirstThree().success)){
clearErrors();
goto loopend16;
}else{
position = start;
}
}
{//Expression ====================== unreachable code
uint start = position;
if((parse_AnyChar().assign!(String)(bind_text))){
clearErrors();
goto loop15;
}else{
setError("Expected AnyChar.");
position = start;
goto mismatch14;
}
}
loopend16:
{}
}
goto match13;
mismatch14:
position = start;
goto mismatch12;
match13:
clearErrors();
goto match11;
}
match11:
debug writefln("parse_AnyLine() PASS");
return ResultT!(String)(bind_text);
mismatch12:
position = start;
return ResultT!(String)();
} |
Okay, I see what this did. Enki should be taking the next sub-expression and using it as a loop terminator. It's grabbing the next whole expression instead. Looking back at Enki's parser definition, its pretty obvious:
Code: | ZeroOrMoreExpr
= new ZeroOrMoreExpr(Expression expr,Binding binding,Expression term)
::= "{" ws Expression:expr ws "}" ws [ Binding:binding ws] [ Expression:term ] ; |
It should be like this instead:
Code: | ZeroOrMoreExpr
= new ZeroOrMoreExpr(Expression expr,Binding binding,SubExpression term)
::= "{" ws Expression:expr ws "}" ws [ Binding:binding ws] [ SubExpression:term ] ; |
So instead of checking for 'eol' each loop, its checking for 'eol and RidFirstThree' each loop. Yikes.
To circumvent this, you might want to try using parentheses to get the proper grouping you need.
Code: |
AnyLine = String text ::= ({AnyChar:text} eol) RidFirstThree; |
[/code]
Quote: |
also, when i via the .code statement insert a variable of type String, can i assign a parsed value to it?
Code: | "3000":z customvariable = z ?? |
|
Enki won't let you do assignments within a grammar like this. I did this to keep from having to support all the variations of D's assignment operator, and how that interacts with various types. I drew the line at functions and classes as interacting with them is much easier to support.
Anyway, you can use the '@' operator to get close. Just wrap the operation in a function instead.
Code: |
Foobar ::= "3000":z @assignVar!(z);
.code{{{
void assignVar(String z){ /* ... */ }
}}}
|
_________________ -- !Eric.t.Anderton at gmail |
|
Back to top |
|
|
rko
Joined: 24 May 2006 Posts: 12
|
Posted: Wed Jun 14, 2006 8:29 am Post subject: |
|
|
yup,
i figures the assignment and am wrapping.
maybe a construct for example like would be convienient.
another need construct could be Code: | (one or more for max n times)n+ | or Code: | {zero or more for max n times}n | .
a REAL need thing would be ranges for use in characterset or number sets like: Code: | number ::= '0'..'9'; | or Code: | ident ::= {'_'}('A'..'Z','a'..'z')+ {('A'..'Z','a'..'z','0'..'9')}; | that would save a lot of typing.
anyhow keep up the great work
rko
________
herbal shop
Last edited by rko on Sun Feb 06, 2011 9:46 pm; edited 1 time in total |
|
Back to top |
|
|
rko
Joined: 24 May 2006 Posts: 12
|
Posted: Wed Jun 14, 2006 8:41 am Post subject: |
|
|
nonsense i meant
ident ::= {'_'}('A'..'Z','a'..'z') {('A'..'Z','a'..'z','0'..'9')}255;
is there any way to sync to some rule or rulepart on error?
rko
________
Ford IB transmission history
Last edited by rko on Sun Feb 06, 2011 9:46 pm; edited 1 time in total |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|