Now we have a Compiler Compiler (the same idea as yacc and similar): PHPCC. You define a grammar, and it returns an object that can parse a tree (array of arrays) for you.
To use it, you define a grammar, use the PHPCC::createGrammar method, add necesary pointcuts in the parsed tree, and then parse the string.
A necessary example:
$oqlg =&PHPCC::createGrammar('<oql( condition="subexpression=">"\(",<expression>,"\)"|comparison=><value>,"=|<=|>=|LIKE",<value>.
expression::=logical=><condition>,operator->"AND|OR|and|or",<condition>|condition=><condition>.
oql::=class->["[a-zA-Z_][a-zA-Z_0-9]*"],
fields->["\(",fields->{"[a-zA-Z_][a-zA-Z_0-9]*","as","[a-zA-Z_][a-zA-Z_0-9]*";","},"\)"],
from->["from",from->{var->"[a-zA-Z_][a-zA-Z_0-9]*",":",class->"[a-zA-Z_][a-zA-Z_0-9]*";","}],
where->["where",expression-><expression>].
variable::={"[a-zA-Z_][a-zA-Z_0-9]*";"\."}.
value::=var=><variable>|value=>(number=>"[0-9]+"|str=>"\'[^\']\'"|phpvar=>"\$[a-zA-Z_][a-zA-Z_0-9]*"|bool=>"TRUE|FALSE|True|False|true|false").
)>'
);
$oqlg->addPointCuts(array (
'condition' => new FObject($this, 'parseCondition'),
'expression' => new FObject($this, 'parseExpression'),
'oql' => new FObject($this, 'parseOql'),
'variable' => new FObject($this, 'parseVariable'),
'value' => new FObject($this, 'parseValue'),
));
$config =& $oqlg->compile($query);
We first define the grammar of a query to our objects. Then, we add the pointcuts (function objects that are called when, for example, a 'value' is finished parsing) to transform the parsed tree to usable data. And then, just ->compile() the string.
The PointCuts are separately, so anyone can use a well defined parser to compile different results. The grammar and the semantics of the same language are separate.
Labels: DSLs