FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

enki question
Goto page 1, 2  Next
 
Post new topic   Reply to topic     Forum Index -> DDL - D Dynamic Libraries
View previous topic :: View next topic  
Author Message
rko



Joined: 24 May 2006
Posts: 12

PostPosted: Mon Jun 12, 2006 6:52 am    Post subject: enki question Reply with quote

hi,

is possible to call add a user supplied function in a rule and call it ?? like:

test1 ::=
{
( "9100"
| "9101"
| "9103"
| "9105"
| "9106"
)Mad 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
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Mon Jun 12, 2006 11:49 am    Post subject: Re: enki question Reply with quote

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"
)Mad 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. Smile

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. Wink

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
View user's profile Send private message Yahoo Messenger
rko



Joined: 24 May 2006
Posts: 12

PostPosted: Mon Jun 12, 2006 11:52 pm    Post subject: Reply with quote

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
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Tue Jun 13, 2006 9:04 am    Post subject: Reply with quote

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. Wink

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. Sad
_________________
-- !Eric.t.Anderton at gmail
Back to top
View user's profile Send private message Yahoo Messenger
brad
Site Admin


Joined: 22 Feb 2004
Posts: 490
Location: Atlanta, GA USA

PostPosted: Tue Jun 13, 2006 9:21 am    Post subject: Reply with quote

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
View user's profile Send private message
rko



Joined: 24 May 2006
Posts: 12

PostPosted: Tue Jun 13, 2006 2:00 pm    Post subject: email Reply with quote

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
View user's profile Send private message
rko



Joined: 24 May 2006
Posts: 12

PostPosted: Tue Jun 13, 2006 2:11 pm    Post subject: enki Reply with quote

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
View user's profile Send private message
rko



Joined: 24 May 2006
Posts: 12

PostPosted: Tue Jun 13, 2006 2:13 pm    Post subject: Reply with quote

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
View user's profile Send private message
brad
Site Admin


Joined: 22 Feb 2004
Posts: 490
Location: Atlanta, GA USA

PostPosted: Tue Jun 13, 2006 3:21 pm    Post subject: Re: email Reply with quote

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
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Tue Jun 13, 2006 3:52 pm    Post subject: Re: enki Reply with quote

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
View user's profile Send private message Yahoo Messenger
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Tue Jun 13, 2006 8:37 pm    Post subject: Reply with quote

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
View user's profile Send private message Yahoo Messenger
rko



Joined: 24 May 2006
Posts: 12

PostPosted: Wed Jun 14, 2006 3:59 am    Post subject: Reply with quote

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
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Wed Jun 14, 2006 7:46 am    Post subject: Reply with quote

[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
View user's profile Send private message Yahoo Messenger
rko



Joined: 24 May 2006
Posts: 12

PostPosted: Wed Jun 14, 2006 8:29 am    Post subject: Reply with quote

yup,
i figures the assignment and am wrapping.
maybe a construct for example like
Code:
(one or more)+
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
View user's profile Send private message
rko



Joined: 24 May 2006
Posts: 12

PostPosted: Wed Jun 14, 2006 8:41 am    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> DDL - D Dynamic Libraries All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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