begin LIME grammar

databind
vitalif 2013-04-19 15:55:42 +00:00 committed by Vitaliy Filippov
parent eab481212d
commit 1faa4cb96b
2 changed files with 289 additions and 4 deletions

286
template.lime Normal file
View File

@ -0,0 +1,286 @@
// Контекстно-свободная грамматика шаблонизатора
// Подразумевается, что лексический анализатор зависим от работы синтаксического,
// знает о его состоянии и соответственно выдаёт либо лексемы "внутри" блоков кода,
// либо литералы "вне" оных
// Олдстайл BEGIN .. END ликвидирован
// TODO foreach ... as key => value
%class VMXTemplateParser
%start chunks
%token literal
%token name
%left ".."
%left "||" "OR" "XOR"
%left "&&" "AND"
%nonassoc "==" "!=" "<" ">" "<=" ">="
%left "+" "-"
%left "&"
%left "*" "/" "%"
// Директивы
chunks = {
$$ = '';
}
| chunks/cs chunk/c {
$$ = $cs . $c;
}
.
chunk = error/e {
}
| literal/l {
$$ = '$t .= ' . $l . ";\n";
}
| "<!--" code_chunk/c "-->" {
$$ = $c;
}
| "{" exp/e "}" {
$$ = '$t .= ' . $e . ";\n";
}
.
code_chunk = c_if | c_set | c_fn | c_for | exp
c_if = "IF" exp/e "-->" chunks/if "<!--" "END" {
$$ = "if (" . $e . ") {\n" . $if . "}\n";
}
| "IF" exp/e "-->" chunks/if "<!--" "ELSE" "-->" chunks/else "<!--" "END" {
$$ = "if (" . $e . ") {\n" . $if . "} else {\n" . $else . "}\n";
}
| "IF" exp/e "-->" chunks/if c_elseifs/ei chunks/ec "<!--" "END" {
$$ = "if (" . $e . ") {\n" . $if . $ei . $ec . "}\n";
}
| "IF" exp/e "-->" chunks/if c_elseifs/ei chunks/ec "<!--" "ELSE" "-->" chunks/else "<!--" "END" {
$$ = "if (" . $e . ") {\n" . $if . $ei . $ec . "} else {\n" . $else . "}\n";
}
.
c_elseifs = "<!--" elseif exp/e "-->" {
$$ = "} elseif (" . $e . ") {\n";
}
| c_elseifs/p chunks/cs "<!--" elseif exp/e "-->" {
$$ = $p . $cs . "} elseif (" . $e . ") {\n";
}
.
c_set = "SET" varref/v "=" exp/e {
$$ = $v . ' = ' . $e . "\n";
}
| "SET" varref/v "-->" chunks/cs "<!--" "END" {
$$ = "\$stack[] = \$t;\n\$t = '';\n" . $cs . $v . " = \$t;\narray_pop(\$stack);\n";
}
.
c_fn = fn name/name "(" arglist/args ")" "=" exp/exp {
$this->functions[$name] = array(
'name' => $name,
'args' => $args,
'body' => 'function fn_'.$name." () {\n\$stack = array();\n\$t = '';\n",
//'line' => $line,
//'pos' => $pos,
);
$$ = '';
$code .= "function fn_".$f['name']." () {\n";
$code .= "\$stack = array();\n\$t = '';\n";
$code .= $f['body'];
$code .= "return \$t;\n}\n";
}
| fn name/name "(" arglist/args ")" "-->" chunks/cs "<!--" "END" {
$this->functions[$name] = array(
'name' => $name,
'args' => $args,
'body' => ,
//'line' => $line,
//'pos' => $pos,
);
$$ = '';
}
.
c_for = for varref/varref "=" exp/exp "-->" chunks "<!--" "END" {
$varref_index = substr($varref, 0, -1) . ".'_index']";
$$ = "\$stack[] = ".$varref.";
\$stack[] = ".$varref_index.";
\$stack[] = 0;
foreach (self::array1($exp) as \$item) {
".$varref." = \$item;
".$varref_index." = \$stack[count(\$stack)-1]++;
" . $cs . "}
array_pop(\$stack);
".$varref_index." = array_pop(\$stack);
".$varref." = array_pop(\$stack);
";
}
.
fn = "FUNCTION" | "BLOCK" | "MACRO"
for = "FOR" | "FOREACH"
elseif = "ELSE" "IF" | "ELSIF" | "ELSEIF"
// Выражения
exp: exp/a ".." exp/b {
$$ = '(' . $a . ' . ' . $b . ')';
}
| exp/a "||" exp/b {
$$ = 'self::perlish_or(' . $a . ', ' . $b . ')';
}
| exp/a "OR" exp/b {
$$ = 'self::perlish_or(' . $a . ', ' . $b . ')';
}
| exp/a "XOR" exp/b {
$$ = '(' . $a . ' XOR ' . $b . ')';
}
| exp/a "&&" exp/b {
$$ = '(' . $a . ' && ' . $b . ')';
}
| exp/a "AND" exp/b {
$$ = '(' . $a . ' && ' . $b . ')';
}
| exp/a "==" exp/b {
$$ = '(' . $a . ' == ' . $b . ')';
}
| exp/a "!=" exp/b {
$$ = '(' . $a . ' != ' . $b . ')';
}
| exp/a "<" exp/b {
$$ = '(' . $a . ' < ' . $b . ')';
}
| exp/a ">" exp/b {
$$ = '(' . $a . ' > ' . $b . ')';
}
| exp/a "<=" exp/b {
$$ = '(' . $a . ' <= ' . $b . ')';
}
| exp/a ">=" exp/b {
$$ = '(' . $a . ' >= ' . $b . ')';
}
| exp/a "+" exp/b {
$$ = '(' . $a . ' + ' . $b . ')';
}
| exp/a "-" exp/b {
$$ = '(' . $a . ' - ' . $b . ')';
}
| exp/a "&" exp/b {
$$ = '(' . $a . ' & ' . $b . ')';
}
| exp/a "*" exp/b {
$$ = '(' . $a . ' * ' . $b . ')';
}
| exp/a "/" exp/b {
$$ = '(' . $a . ' / ' . $b . ')';
}
| exp/a "%" exp/b {
$$ = '(' . $a . ' % ' . $b . ')';
}
| p10
.
p10: p11 | '-' p11/a {
$$ = '(-'.$a.')';
}
.
p11: nonbrace
| '(' exp/e ')' varpath/p {
$$ = '('.$e.')'.$p;
}
| '!' p11/a {
$$ = '(!'.$a.')';
}
| "NOT" p11/a {
$$ = '(!'.$a.')';
}
.
nonbrace: '{' hash/h '}' {
$$ = 'array(' . $h . ')';
}
| literal
| varref
| name/f '(' ')' {
$$ = $this->compile_function($f, []);
}
| name/f '(' list/args ')' {
$$ = $this->compile_function($f, $args);
}
| name/f '(' gthash/args ')' {
$$ = "\$this->parent->call_block(".$f.", ".$args.")";
}
| name/f nonbrace/arg {
$$ = $this->compile_function($f, [ $arg ]);
}
| method/f '(' ')' {
$$ = $f.'()';
}
| method/f '(' list/args ')' {
$$ = $f.'('.implode(', ', $args).')';
}
.
method: varref/v '.' name/m {
$$ = $v.'->'.$m;
}
.
list: exp/e {
$$ = [ $e ];
}
| exp/e ',' list/l {
$$ = $l;
array_unshift($$, $e);
}
.
arglist: name {
}
| name ',' arglist {
}
| {
}
.
hash: pair/p {
$$ = $p;
}
| pair/p ',' hash/h {
$$ = $p . ', ' . $h;
}
| {
$$ = '';
}
.
gthash: gtpair/p {
$$ = $p;
}
| gtpair/p ',' gthash/h {
$$ = $p . ', ' . $h;
}
.
pair: exp/k ',' exp/v {
$$ = $k . ' => ' . $v;
}
| gtpair/e {
$$ = $e;
}
.
gtpair: exp/k "=>" exp/v {
$$ = $k . ' => ' . $v;
}
.
varref: name/n {
$$ = '$this->tpldata[\''.addcslashes($n, '\\\'').'\']';
}
| varref/v varpart/p {
$$ = $v . $p;
}
.
varpart: '.' name/n {
$$ = '[\''.addcslashes($n, '\\\'').'\']';
}
| '[' exp/e ']' {
$$ = '['.$e.']';
}
.
varpath: {
$$ = '';
}
| varpath/a varpart/p {
$$ = $a . $p;
}
.

View File

@ -46,13 +46,12 @@ exp: exp ".." exp |
p10
p10: p11 | '-' p11
p11: nonbrace | '(' exp ')' varpath | '!' p11 | "NOT" p11
nonbrace: '{' hash '}' | literal | varref | func '(' list_or_gthash ')' | func nonbrace
list_or_gthash: list | gthash
func: name | varref varpart
nonbrace: '{' hash '}' | literal | varref | name '(' ')' | name '(' list ')' | name '(' gthash ')' | name nonbrace | method '(' ')' | method '(' list ')'
method: varref '.' name
list: exp | exp ',' list
arglist: name | name ',' arglist |
hash: pair | pair ',' hash |
gthash: gtpair | gtpair ',' gthash |
gthash: gtpair | gtpair ',' gthash
pair: exp ',' exp | gtpair
gtpair: exp "=>" exp
varref: name | varref varpart