root/trunk/rphp/compiler/analysis/grammar_src/rphp_grammar.y @ 1025

Revision 1025, 53.4 KB (checked in by weyrick, 7 months ago)

add bitwise not and resolve some conflicts

Line 
1/* ***** BEGIN LICENSE BLOCK *****
2;; Roadsend PHP Compiler
3;;
4;; Copyright (c) 2008-2010 Shannon Weyrick <weyrick@roadsend.com>
5;;
6;; This program is free software; you can redistribute it and/or
7;; modify it under the terms of the GNU General Public License
8;; as published by the Free Software Foundation; either version 2
9;; of the License, or (at your option) any later version.
10;;
11;; This program is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;; GNU General Public License for more details.
15;;
16;; You should have received a copy of the GNU General Public License
17;; along with this program; if not, write to the Free Software
18;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19   ***** END LICENSE BLOCK *****
20*/
21
22%include {   
23
24#include "rphp/pSourceTypes.h"
25#include "rphp/analysis/pAST.h"
26#include "rphp/analysis/pSourceModule.h"
27
28#include <iostream>
29#include <string>
30#include <cctype> // for toupper
31#include <algorithm>
32#include <unicode/unistr.h>
33
34using namespace rphp;
35
36#define CTXT          pMod->context()
37#define TOKEN_LINE(T) CTXT.getTokenLine(T)
38#define CURRENT_LINE  CTXT.currentLineNum()
39
40AST::literalExpr* extractLiteralString(pSourceRange* B, pSourceModule* pMod, bool isSimple) {
41  // binary specifier?
42  bool binaryString = false;
43  pSourceCharIterator start;
44  if ( *(*B).begin() == 'b') {
45      // binary
46      binaryString = true;
47      start = ++(*B).begin();
48  }
49  else {
50      // according to module default
51      start = (*B).begin();
52  }
53  // substring out the quotes, special case for empty string
54  AST::literalString* A;
55  if (++start == (*B).end()) {
56    A = new (CTXT) AST::literalString(binaryString);
57  }
58  else {
59    A = new (CTXT) AST::literalString(pSourceRange(start, --(*B).end()), binaryString);
60  }
61  A->setIsSimple(isSimple);
62  return A;
63}
64
65
66
67%name rphpParse
68%token_type {pSourceRange*}
69%default_type {pSourceRange*}
70%extra_argument {pSourceModule* pMod}
71
72
73// tokens that don't need parse info or AST nodes
74%type T_WHITESPACE {int}
75%type T_OPEN_TAG {int}
76%type T_CLOSE_TAG {int}
77%type T_LEFTPAREN {int}
78%type T_RIGHTPAREN {int}
79%type T_LEFTCURLY {int}
80%type T_RIGHTCURLY {int}
81%type T_LEFTSQUARE {int}
82%type T_RIGHTSQUARE {int}
83%type T_COMMA {int}
84%type T_SINGLELINE_COMMENT {int}
85%type T_MULTILINE_COMMENT {int}
86%type T_DOC_COMMENT {int}
87%type T_INLINE_HTML {int}
88%type T_WHILE {int}
89%type T_ENDWHILE {int}
90%type T_ELSE {int}
91%type T_ELSEIF {int}
92%type T_ARRAY {int}
93%type T_ARROWKEY {int}
94%type T_AND {int}
95%type T_ASSIGN {int}
96%type T_DQ_STRING {int}
97//We need _LIT versions here for 'and', 'or' and 'xor' because these have another precedence than '&&' and  '||'
98//but finally we want them to look like the normal ast nodes.
99%type T_BOOLEAN_AND {int}
100%type T_BOOLEAN_AND_LIT {int}
101%type T_BOOLEAN_OR {int}
102%type T_BOOLEAN_OR_LIT {int}
103%type T_BOOLEAN_XOR_LIT {int}
104%type T_BOOLEAN_NOT {int}
105%type T_IDENTIFIER {int}
106%type T_GLOBAL {int}
107%type T_FUNCTION {int}
108%type T_EMPTY {int}
109%type T_EQUAL {int}
110%type T_NOT_EQUAL {int}
111%type T_ISSET {int}
112%type T_UNSET {int}
113%type T_VAR {int}
114%type T_CLASS {int}
115%type T_CLASSDEREF {int}
116%type T_FOREACH {int}
117%type T_ENDFOREACH {int}
118%type T_FOR {int}
119%type T_ENDFOR {int}
120%type T_AS {int}
121%type T_RETURN {int}
122%type T_DOT {int}
123%type T_GREATER_THAN {int}
124%type T_LESS_THAN {int}
125%type T_GREATER_OR_EQUAL {int}
126%type T_LESS_OR_EQUAL {int}
127%type T_LIST {int}
128%type T_EXTENDS {int}
129%type T_PUBLIC {int}
130%type T_PRIVATE {int}
131%type T_PROTECTED {int}
132%type T_INCLUDE {int}
133%type T_INCLUDE_ONCE {int}
134%type T_REQUIRE {int}
135%type T_REQUIRE_ONCE {int}
136%type T_IDENTICAL {int}
137%type T_NOT_IDENTICAL {int}
138%type T_QUESTION {int}
139%type T_COLON {int}
140%type T_DBL_COLON {int}
141%type T_INC {int}
142%type T_DEC {int}
143%type T_EXIT {int}
144%type T_MINUS {int}
145%type T_PLUS {int}
146%type T_DIV {int}
147%type T_MOD {int}
148%type T_MULT {int}
149%type T_SWITCH {int}
150%type T_ENDSWITCH {int}
151%type T_CASE {int}
152%type T_BREAK {int}
153%type T_CONTINUE {int}
154%type T_DEFAULT {int}
155%type T_CLONE {int}
156%type T_TRY {int}
157%type T_CATCH {int}
158%type T_THROW {int}
159%type T_STATIC {int}
160%type T_CONST {int}
161%type T_AT {int}
162%type T_INSTANCEOF {int}
163%type T_PLUS_EQUAL {int}
164%type T_MINUS_EQUAL {int}
165%type T_EVAL {int}
166%type T_SR_EQUAL {int}
167%type T_SL_EQUAL {int}
168%type T_XOR_EQUAL {int}
169%type T_OR_EQUAL {int}
170%type T_AND_EQUAL {int}
171%type T_MOD_EQUAL {int}
172%type T_CONCAT_EQUAL {int}
173%type T_DIV_EQUAL {int}
174%type T_MUL_EQUAL {int}
175%type T_SR {int}
176%type T_SL {int}
177%type T_NAMESPACE {int}
178%type T_INT_CAST {int}
179%type T_FLOAT_CAST {int}
180%type T_STRING_CAST {int}
181%type T_UNICODE_CAST {int}
182%type T_BINARY_CAST {int}
183%type T_ARRAY_CAST {int}
184%type T_OBJECT_CAST {int}
185%type T_UNSET_CAST {int}
186%type T_BOOL_CAST {int}
187%type T_GOTO {int}
188%type T_MAGIC_FILE {int}
189%type T_MAGIC_LINE {int}
190%type T_MAGIC_NS {int}
191%type T_MAGIC_CLASS {int}
192%type T_MAGIC_FUNCTION {int}
193%type T_MAGIC_METHOD {int}
194%type T_TICK {int}
195%type T_TILDE {int}
196%type T_PIPE {int}
197%type T_CARET {int}
198%type T_PRINT {int}
199%type T_INTERFACE {int}
200
201// double quote parsing
202%type T_DQ_DONE {int}
203%type T_DQ_DQ  {int}
204%type T_DQ_NEWLINE  {int}
205%type T_DQ_VARIABLE  {int}
206%type T_DQ_ESCAPE  {int}
207
208%syntax_error { 
209  CTXT.parseError(TOKEN);
210}   
211%stack_overflow { 
212  std::cerr << "Parser stack overflow" << std::endl;
213}   
214
215/** ASSOCIATIVITY AND PRECEDENCE (low to high) **/
216%left T_INCLUDE T_INCLUDE_ONCE T_REQUIRE T_REQUIRE_ONCE T_EVAL.
217%left T_COMMA.
218%left T_BOOLEAN_OR_LIT.
219%left T_BOOLEAN_XOR_LIT.
220%left T_BOOLEAN_AND_LIT.
221%right T_PRINT.
222%left T_ASSIGN T_CONCAT_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_PLUS_EQUAL T_MINUS_EQUAL T_MOD_EQUAL T_DIV_EQUAL T_MUL_EQUAL T_SL_EQUAL T_SR_EQUAL.
223%left T_QUESTION T_COLON.
224%left T_BOOLEAN_AND T_BOOLEAN_OR.
225%left T_PIPE.
226%left T_CARET.
227%left T_AND.
228%nonassoc T_EQUAL T_NOT_EQUAL T_IDENTICAL T_NOT_IDENTICAL.
229%nonassoc T_GREATER_THAN T_LESS_THAN T_GREATER_OR_EQUAL T_LESS_OR_EQUAL.
230%left T_SL T_SR.
231%left T_PLUS T_MINUS T_DOT.
232%left T_DIV T_MOD T_MULT.
233%right T_BOOLEAN_NOT.
234%nonassoc T_INSTANCEOF.
235%right T_TILDE T_INC T_DEC T_FLOAT_CAST T_STRING_CAST T_BINARY_CAST T_UNICODE_CAST T_ARRAY_CAST T_OBJECT_CAST T_INT_CAST T_BOOL_CAST T_UNSET_CAST T_AT.
236%right T_LEFTSQUARE.
237%nonassoc T_NEW T_CLONE.
238%left T_ELSE T_ELSEIF.
239%right T_STATIC T_PROTECTED T_PRIVATE T_ABSTRACT T_FINAL T_PUBLIC.
240
241
242/** GOAL **/
243%type module {int}
244module ::= statement_list(LIST). { pMod->setAST(LIST); delete LIST; }
245
246%type statement_list {AST::statementList*}
247statement_list(A) ::= . { A = new AST::statementList(); }
248statement_list(A) ::= statement_list(B) statement(C). { B->push_back(C); A = B; }
249
250/******** STATEMENTS ********/
251%type statement {AST::stmt*}
252statement(A) ::= statementBlock(B). { A = B; }
253statement(A) ::= inlineHTML(B). { A = B; }
254statement(A) ::= staticDecl(B). { A = B; }
255statement(A) ::= functionDecl(B). { A = B; }
256statement(A) ::= classDecl(B). { A = B; }
257statement(A) ::= ifBlock(B). { A = B; }
258statement(A) ::= forEach(B). { A = B; }
259statement(A) ::= forStmt(B). { A = B; }
260statement(A) ::= doStmt(B). { A = B; }
261statement(A) ::= whileStmt(B). { A = B; }
262statement(A) ::= switchStmt(B). { A = B; }
263statement(A) ::= tryCatch(B). { A = B; }
264statement(A) ::= echo(B) T_SEMI. { A = B; }
265statement(A) ::= throw(B) T_SEMI. { A = B; }
266statement(A) ::= expr(B) T_SEMI. { A = B; }
267statement(A) ::= return(B) T_SEMI. { A = B; }
268statement(A) ::= break(B) T_SEMI. { A = B; }
269statement(A) ::= continue(B) T_SEMI. { A = B; }
270statement(A) ::= global(B) T_SEMI. { A = B; }
271statement(A) ::= T_SEMI.
272{
273    A = new (CTXT) AST::emptyStmt();
274}
275
276// statement block
277%type statementBlock{AST::block*}
278statementBlock(A) ::= T_LEFTCURLY(LC) statement_list(B) T_RIGHTCURLY(RC).
279{
280    A = new (CTXT) AST::block(CTXT, B);
281    A->setLine(TOKEN_LINE(LC), TOKEN_LINE(RC));
282    delete B;
283}
284
285// echo
286%type echo {AST::builtin*}
287echo(A) ::= T_ECHO commaExprList(EXPRS).
288{
289   A = new (CTXT) AST::builtin(CTXT, AST::builtin::ECHO, EXPRS);
290   A->setLine(CURRENT_LINE);
291   delete EXPRS;
292}
293
294// throw
295%type throw {AST::builtin*}
296throw(A) ::= T_THROW expr(RVAL).
297{
298    AST::expressionList* rVal = new AST::expressionList();
299    rVal->push_back(RVAL);
300    A = new (CTXT) AST::builtin(CTXT, AST::builtin::THROW, rVal);
301    delete rVal;
302    A->setLine(CURRENT_LINE);
303}
304
305// return
306%type return {AST::returnStmt*}
307return(A) ::= T_RETURN.
308{
309    A = new (CTXT) AST::returnStmt(NULL);
310    A->setLine(CURRENT_LINE);
311}
312return(A) ::= T_RETURN expr(B).
313{
314    A = new (CTXT) AST::returnStmt(B);
315    A->setLine(CURRENT_LINE);
316}
317// break
318%type break {AST::breakStmt*}
319break(A) ::= T_BREAK.
320{
321    A = new (CTXT) AST::breakStmt(NULL);
322    A->setLine(CURRENT_LINE);
323}
324break(A) ::= T_BREAK expr(B).
325{
326    A = new (CTXT) AST::breakStmt(B);
327    A->setLine(CURRENT_LINE);
328}
329// continue
330%type continue {AST::continueStmt*}
331continue(A) ::= T_CONTINUE.
332{
333    A = new (CTXT) AST::continueStmt(NULL);
334    A->setLine(CURRENT_LINE);
335}
336continue(A) ::= T_CONTINUE expr(B).
337{
338    A = new (CTXT) AST::continueStmt(B);
339    A->setLine(CURRENT_LINE);
340}
341
342// global
343%type global {AST::globalDecl*}
344global(A) ::= T_GLOBAL globalVarList(B).
345{
346    A = new (CTXT) AST::globalDecl(B, CTXT);
347    A->setLine(CURRENT_LINE);
348    delete B;
349}
350
351// inline html
352%type inlineHTML {AST::inlineHtml*}
353inlineHTML(A) ::= T_INLINE_HTML(B).
354{
355    A = new (CTXT) AST::inlineHtml(*B);
356    A->setLine(CURRENT_LINE);
357}
358
359// try/catch
360%type tryCatch {AST::tryStmt*}
361tryCatch(A) ::= T_TRY statementBlock(BODY)
362                catch(COMP) moreCatches(MORECATCHES).
363{
364
365    AST::statementList catchList;
366    catchList.push_back(COMP); // compulsory
367
368    // copy in additional catches, if any
369    if (MORECATCHES != NULL) {
370      for(AST::statementList::iterator i = MORECATCHES->begin();
371          i != MORECATCHES->end();
372          ++i) {
373            catchList.push_back(*i);
374      }
375      delete MORECATCHES;
376    }
377
378    A = new (CTXT) AST::tryStmt(CTXT, new (CTXT) AST::block(CTXT, BODY), &catchList);
379    A->setLine(CURRENT_LINE);
380    // catchList goes out of scope and frees
381
382}
383
384%type moreCatches {AST::statementList*}
385moreCatches(A) ::= . { A = NULL; }
386moreCatches(A) ::= nonEmptyCatches(B). { A = B; }
387
388%type nonEmptyCatches {AST::statementList*}
389nonEmptyCatches(A) ::= catch(C).
390{
391    A = new AST::statementList();
392    A->push_back(C);
393}
394nonEmptyCatches(A) ::= nonEmptyCatches(LIST) catch(C).
395{
396    LIST->push_back(C);
397    A = LIST;
398}
399
400%type catch {AST::catchStmt*}
401catch(A) ::= T_CATCH T_LEFTPAREN T_IDENTIFIER(CLASSNAME) T_VARIABLE(VAR) T_RIGHTPAREN
402             statementBlock(CATCHBODY).
403{
404    A = new (CTXT) AST::catchStmt(*CLASSNAME, *VAR, CTXT, new (CTXT) AST::block(CTXT, CATCHBODY));
405    A->setLine(CURRENT_LINE);
406}
407
408// conditionals
409%type elseSingle {AST::stmt*}
410// empty else
411elseSingle(A) ::= . { A = NULL; }
412// simple else
413elseSingle(A) ::= T_ELSE statement(BODY).
414{
415    A = BODY;
416}
417
418// else series
419%type elseSeries{AST::stmt*}
420// elseif with (potential) single statement
421elseSeries(A) ::=  T_ELSEIF(EIF) T_LEFTPAREN expr(COND) T_RIGHTPAREN statement(TRUE) elseSingle(ELSE).
422{
423    A = new (CTXT) AST::ifStmt(CTXT, COND, TRUE, ELSE);
424    A->setLine(TOKEN_LINE(EIF));
425}
426// elseif series
427elseSeries(A) ::=  T_ELSEIF(EIF) T_LEFTPAREN expr(COND) T_RIGHTPAREN statement(TRUE) elseSeries(ELSE).
428{
429    A = new (CTXT) AST::ifStmt(CTXT, COND, TRUE, ELSE);
430    A->setLine(TOKEN_LINE(EIF));
431}
432
433// if
434%type ifBlock {AST::ifStmt*}
435ifBlock(A) ::= T_IF(IF) T_LEFTPAREN expr(COND) T_RIGHTPAREN statement(TRUE) elseSeries(ELSE).
436{
437    A = new (CTXT) AST::ifStmt(CTXT, COND, TRUE, ELSE);
438    A->setLine(TOKEN_LINE(IF));
439}
440ifBlock(A) ::= T_IF(IF) T_LEFTPAREN expr(COND) T_RIGHTPAREN statement(TRUE) elseSingle(ELSE).
441{
442    A = new (CTXT) AST::ifStmt(CTXT, COND, TRUE, ELSE);
443    A->setLine(TOKEN_LINE(IF));
444}
445
446// foreach
447%type forEach {AST::forEach*}
448// foreach($expr as $val)
449forEach(A) ::= T_FOREACH(F) T_LEFTPAREN expr(RVAL) T_AS T_VARIABLE(VAL) T_RIGHTPAREN statement(BODY).
450{
451    A = new (CTXT) AST::forEach(RVAL, BODY, CTXT, *VAL, false /*by ref*/ );
452    A->setLine(TOKEN_LINE(F));
453}
454// foreach($expr as $key => $val)
455forEach(A) ::= T_FOREACH(F) T_LEFTPAREN expr(RVAL) T_AS T_VARIABLE(KEY) T_ARROWKEY T_VARIABLE(VAL) T_RIGHTPAREN statement(BODY).
456{
457    A = new (CTXT) AST::forEach(RVAL, BODY, CTXT, *VAL, false /*by ref*/, KEY);
458    A->setLine(TOKEN_LINE(F));
459}
460// foreach($expr as &$val)
461forEach(A) ::= T_FOREACH(F) T_LEFTPAREN expr(RVAL) T_AS T_AND T_VARIABLE(VAL) T_RIGHTPAREN statement(BODY).
462{
463    A = new (CTXT) AST::forEach(RVAL, BODY, CTXT, *VAL, true /*by ref*/);
464    A->setLine(TOKEN_LINE(F));
465}
466// foreach($expr as $key => &$val)
467forEach(A) ::= T_FOREACH(F) T_LEFTPAREN expr(RVAL) T_AS T_VARIABLE(KEY) T_ARROWKEY T_AND T_VARIABLE(VAL) T_RIGHTPAREN statement(BODY).
468{
469    A = new (CTXT) AST::forEach(RVAL, BODY, CTXT, *VAL, true /*by ref*/, KEY);
470    A->setLine(TOKEN_LINE(F));
471}
472
473// for
474%type forStmt {AST::forStmt*}
475forStmt(A) ::= T_FOR(F) T_LEFTPAREN forExpr(INIT) T_SEMI forExpr(COND) T_SEMI forExpr(INC) T_RIGHTPAREN statement(BODY).
476{
477    A = new (CTXT) AST::forStmt(CTXT, INIT, COND, INC, BODY);
478    A->setLine(TOKEN_LINE(F));
479}
480
481%type forExpr {AST::stmt*}
482forExpr(A) ::= .
483{
484    A = NULL;
485}
486forExpr(A) ::= commaExprList(B).
487{
488    assert(B->size());
489    if (B->size() == 1) {
490        A = static_cast<AST::stmt*>( B->at(0) );
491    }
492    else {
493        A = new (CTXT) AST::block(CTXT, B);
494    }
495    delete B;
496}
497
498// do
499%type doStmt {AST::doStmt*}
500doStmt(A) ::= T_DO statement(BODY) T_WHILE T_LEFTPAREN expr(COND) T_RIGHTPAREN.
501{
502    A = new (CTXT) AST::doStmt(CTXT, COND, BODY);
503    A->setLine(CURRENT_LINE);
504}
505
506// while
507%type whileStmt {AST::whileStmt*}
508whileStmt(A) ::= T_WHILE T_LEFTPAREN expr(COND) T_RIGHTPAREN statement(BODY).
509{
510    A = new (CTXT) AST::whileStmt(CTXT, COND, BODY);
511    A->setLine(CURRENT_LINE);
512}
513
514// switch
515%type switchStmt {AST::switchStmt*}
516switchStmt(A) ::= T_SWITCH T_LEFTPAREN expr(RVAL) T_RIGHTPAREN switchCaseList(CASES).
517{
518    A = new (CTXT) AST::switchStmt(RVAL, CASES);
519    A->setLine(CURRENT_LINE);
520}
521
522%type switchCaseList {AST::block*}
523switchCaseList(A) ::= T_LEFTCURLY(LC) caseList(CASES) T_RIGHTCURLY(RC).
524{
525    A = new (CTXT) AST::block(CTXT, CASES);
526    A->setLine(TOKEN_LINE(LC), TOKEN_LINE(RC));
527    delete CASES;
528}
529switchCaseList(A) ::= T_LEFTCURLY(LC) T_SEMI caseList(CASES) T_RIGHTCURLY(RC).
530{
531    A = new (CTXT) AST::block(CTXT, CASES);
532    A->setLine(TOKEN_LINE(LC), TOKEN_LINE(RC));
533    delete CASES;
534}
535switchCaseList(A) ::= T_COLON(LC) caseList(CASES) T_ENDSWITCH(RC).
536{
537    A = new (CTXT) AST::block(CTXT, CASES);
538    A->setLine(TOKEN_LINE(LC), TOKEN_LINE(RC));
539    delete CASES;
540}
541switchCaseList(A) ::= T_COLON(LC) T_SEMI caseList(CASES) T_ENDSWITCH(RC).
542{
543    A = new (CTXT) AST::block(CTXT, CASES);
544    A->setLine(TOKEN_LINE(LC), TOKEN_LINE(RC));
545    delete CASES;
546}
547
548%type caseList {AST::statementList*} //  root nodes here must be switchCase* casted to stmt*
549caseList(A) ::= .
550{
551    A = new AST::statementList();
552}
553caseList(A) ::= caseList(LIST) T_CASE expr(COND) caseSeparator statement_list(STMTS).
554{
555    AST::switchCase* c = new (CTXT) AST::switchCase(COND,
556                                                    new (CTXT) AST::block(CTXT, STMTS));
557    c->setLine(CURRENT_LINE);
558    LIST->push_back(static_cast<AST::stmt*>(c));
559    delete STMTS;
560    A = LIST;
561}
562caseList(A) ::= caseList(LIST) T_DEFAULT caseSeparator statement_list(STMTS).
563{
564    AST::switchCase* c = new (CTXT) AST::switchCase(NULL,
565                                                     new (CTXT) AST::block(CTXT, STMTS));
566    c->setLine(CURRENT_LINE);
567    LIST->push_back(static_cast<AST::stmt*>(c));
568    delete STMTS;
569    A = LIST;
570}
571
572caseSeparator ::= T_COLON.
573caseSeparator ::= T_SEMI.
574
575/** DECLARATIONS **/
576
577/** STATIC **/
578%type staticDecl {AST::staticDecl*}
579staticDecl(A) ::= T_STATIC staticVarList(VARLIST).
580{
581    A = new (CTXT) AST::staticDecl(VARLIST, CTXT);
582    A->setLine(CURRENT_LINE);
583    delete VARLIST;
584}
585
586staticDecl(A) ::= T_STATIC staticVarList(VARLIST) T_ASSIGN staticScalar(DEF).
587{
588    A = new (CTXT) AST::staticDecl(VARLIST, CTXT, DEF);
589    A->setLine(CURRENT_LINE);
590    delete VARLIST;
591}
592
593
594/** FUNCTION FORMAL PARAMS **/
595%type formalParam {AST::formalParam*}
596formalParam(A) ::= maybeHint(HINT) T_VARIABLE(PARAM).
597{
598    A = new (CTXT) AST::formalParam(pSourceRange(++(*PARAM).begin(), (*PARAM).end()),
599                              CTXT, false/*ref*/);
600    if (HINT == (pSourceRange*)0x1) {
601        A->setArrayHint();
602    }
603    else if (HINT) {
604        A->setClassHint(*HINT, CTXT);
605    }
606    A->setLine(TOKEN_LINE(PARAM));
607}
608formalParam(A) ::= maybeHint(HINT) T_AND T_VARIABLE(PARAM).
609{
610    A = new (CTXT) AST::formalParam(pSourceRange(++(*PARAM).begin(), (*PARAM).end()),
611                              CTXT, true/*ref*/);
612    if (HINT == (pSourceRange*)0x1) {
613        A->setArrayHint();
614    }
615    else if (HINT) {
616        A->setClassHint(*HINT, CTXT);
617    }
618    A->setLine(TOKEN_LINE(PARAM));
619}
620formalParam(A) ::= maybeHint(HINT) T_VARIABLE(PARAM) T_ASSIGN staticScalar(DEF).
621{
622    A = new (CTXT) AST::formalParam(pSourceRange(++(*PARAM).begin(), (*PARAM).end()),
623                              CTXT, false/*ref*/, DEF);
624    if (HINT == (pSourceRange*)0x1) {
625        A->setArrayHint();
626    }
627    else if (HINT) {
628        A->setClassHint(*HINT, CTXT);
629    }
630    A->setLine(TOKEN_LINE(PARAM));
631}
632formalParam(A) ::= maybeHint(HINT) T_AND T_VARIABLE(PARAM) T_ASSIGN staticScalar(DEF).
633{
634    A = new (CTXT) AST::formalParam(pSourceRange(++(*PARAM).begin(), (*PARAM).end()),
635                              CTXT, true/*ref*/, DEF);
636    if (HINT == (pSourceRange*)0x1) {
637        A->setArrayHint();
638    }
639    else if (HINT) {
640        A->setClassHint(*HINT, CTXT);
641    }
642    A->setLine(TOKEN_LINE(PARAM));
643}
644
645// this will be NULL (no hint), integral 1 (array hint) or an identifier
646%type maybeHint {pSourceRange*}
647maybeHint(A) ::= . { A = NULL; }
648maybeHint(A) ::= T_ARRAY. { A = (pSourceRange*)0x1; }
649maybeHint(A) ::= T_IDENTIFIER(B). { A = B; }
650
651%type formalParamList {AST::formalParamList*}
652formalParamList(A) ::= formalParam(PARAM).
653{
654    A = new AST::formalParamList();
655    A->push_back(PARAM);
656}
657formalParamList(A) ::= formalParam(PARAM) T_COMMA formalParamList(C).
658{
659    C->push_back(PARAM);
660    A = C;
661}
662formalParamList(A) ::= .
663{
664    A = new AST::formalParamList();
665}
666
667/** FUNCTION DECL **/
668%type signature {AST::signature*}
669signature(A) ::= T_IDENTIFIER(NAME) T_LEFTPAREN formalParamList(PARAMS) T_RIGHTPAREN.
670{
671    A = new (CTXT) AST::signature(*NAME, CTXT, PARAMS, false/*ref*/);
672    A->setLine(TOKEN_LINE(NAME));
673    delete PARAMS;
674}
675signature(A) ::= T_AND T_IDENTIFIER(NAME) T_LEFTPAREN formalParamList(PARAMS) T_RIGHTPAREN.
676{
677    A = new (CTXT) AST::signature(*NAME, CTXT, PARAMS, true/*ref*/);
678    A->setLine(TOKEN_LINE(NAME));
679    delete PARAMS;
680}
681
682%type functionDecl {AST::functionDecl*}
683functionDecl(A) ::= T_FUNCTION signature(SIG) statementBlock(BODY).
684{
685    A = new (CTXT) AST::functionDecl(SIG, BODY);
686}                   
687
688/** CLASSES **/
689%type classDecl {AST::classDecl*}
690classDecl(A) ::= T_CLASS(C) T_IDENTIFIER(NAME) classExtends(EXTENDS) classImplements(IMPLEMENTS)
691                 T_LEFTCURLY classStatements(MEMBERS) T_RIGHTCURLY(RC).
692{
693    A = new (CTXT) AST::classDecl(CTXT,
694                                  *NAME,
695                                  AST::classDecl::NORMAL,
696                                  EXTENDS,
697                                  IMPLEMENTS,
698                                  new (CTXT) AST::block(CTXT, MEMBERS));
699    A->setLine(TOKEN_LINE(C), TOKEN_LINE(RC));
700    if (EXTENDS)
701        delete EXTENDS;
702    if (IMPLEMENTS)
703        delete IMPLEMENTS;
704    delete MEMBERS;
705}
706classDecl(A) ::= T_FINAL T_CLASS(C) T_IDENTIFIER(NAME) classExtends(EXTENDS) classImplements(IMPLEMENTS)
707                 T_LEFTCURLY classStatements(MEMBERS) T_RIGHTCURLY(RC).
708{
709    A = new (CTXT) AST::classDecl(CTXT,
710                                  *NAME,
711                                  AST::classDecl::FINAL,
712                                  EXTENDS,
713                                  IMPLEMENTS,
714                                  new (CTXT) AST::block(CTXT, MEMBERS));
715    A->setLine(TOKEN_LINE(C), TOKEN_LINE(RC));
716    if (EXTENDS)
717        delete EXTENDS;
718    if (IMPLEMENTS)
719        delete IMPLEMENTS;
720    delete MEMBERS;
721}
722classDecl(A) ::= T_ABSTRACT T_CLASS(C) T_IDENTIFIER(NAME) classExtends(EXTENDS) classImplements(IMPLEMENTS)
723                 T_LEFTCURLY classStatements(MEMBERS) T_RIGHTCURLY(RC).
724{
725    A = new (CTXT) AST::classDecl(CTXT,
726                                  *NAME,
727                                  AST::classDecl::ABSTRACT,
728                                  EXTENDS,
729                                  IMPLEMENTS,
730                                  new (CTXT) AST::block(CTXT, MEMBERS));
731    A->setLine(TOKEN_LINE(C), TOKEN_LINE(RC));
732    if (EXTENDS)
733        delete EXTENDS;
734    if (IMPLEMENTS)
735        delete IMPLEMENTS;
736    delete MEMBERS;
737}
738classDecl(A) ::= T_INTERFACE(C) T_IDENTIFIER(NAME) interfaceExtends(EXTENDS)
739                 T_LEFTCURLY classStatements(MEMBERS) T_RIGHTCURLY(RC).
740{
741    A = new (CTXT) AST::classDecl(CTXT,
742                                  *NAME,
743                                  AST::classDecl::IFACE,
744                                  EXTENDS,
745                                  NULL, /* interfaces can't implement */
746                                  new (CTXT) AST::block(CTXT, MEMBERS));
747    A->setLine(TOKEN_LINE(C), TOKEN_LINE(RC));
748    if (EXTENDS)
749        delete EXTENDS;
750    delete MEMBERS;
751}
752
753%type classStatements {AST::statementList*}
754classStatements(A) ::= .
755{
756    A = new AST::statementList();
757
758}
759classStatements(A) ::= classStatements(LIST) classStatement(STMT).
760{
761    LIST->push_back(STMT);
762    A = LIST;
763}
764
765// things that can go inside of a class declaration
766%type classStatement {AST::stmt*}
767classStatement(A) ::= classVarFlags(FLAGS) classVar(VARS) T_SEMI.
768{
769    pUInt flags(0);
770    if (FLAGS) {
771        flags = *FLAGS;
772    }
773    // set flags on each var decl
774    for (AST::statementList::iterator i = VARS->begin();
775         i != VARS->end();
776         ++i)
777    {
778        static_cast<AST::propertyDecl*>((*i))->setFlags(flags);
779    }
780    if (VARS->size() == 1) {
781        // one var decl
782        A = VARS->at(0);
783    }
784    else {
785        // list, make a block
786        A = new (CTXT) AST::block(CTXT, VARS);
787    }
788    // all done with vector
789    delete VARS;
790}
791classStatement(A) ::= classConstantDecl(VARS) T_SEMI.
792{
793    if (VARS->size() == 1) {
794        // one var decl
795        A = VARS->at(0);
796    }
797    else {
798        // list, make a block
799        A = new (CTXT) AST::block(CTXT, VARS);
800    }
801    // all done with vector
802    delete VARS;
803}
804classStatement(A) ::= methodFlags(FLAGS) T_FUNCTION signature(SIG) methodBody(BODY).
805{
806    pUInt flags(0);
807    if (FLAGS) {
808        flags = *FLAGS;
809    }
810    A = new (CTXT) AST::methodDecl(SIG, flags, BODY);
811}
812classStatement(A) ::= methodFlags(FLAGS) T_AND T_FUNCTION signature(SIG) methodBody(BODY).
813{
814    pUInt flags(0);
815    if (FLAGS) {
816        flags = *FLAGS;
817    }
818    A = new (CTXT) AST::methodDecl(SIG, flags, BODY);
819}
820
821%type classVar {AST::statementList*}
822classVar(A) ::= classVar(LIST) T_COMMA T_VARIABLE(VAR).
823{
824    // strip $
825    LIST->push_back(new (CTXT) AST::propertyDecl(CTXT, pSourceRange(++(*VAR).begin(), (*VAR).end()), NULL));
826    A = LIST;
827}
828classVar(A) ::= classVar(LIST) T_COMMA T_VARIABLE(VAR) T_ASSIGN staticScalar(DEFAULT).
829{
830    // strip $
831    LIST->push_back(new (CTXT) AST::propertyDecl(CTXT, pSourceRange(++(*VAR).begin(), (*VAR).end()), DEFAULT));
832    A = LIST;
833}
834classVar(A) ::= T_VARIABLE(VAR).
835{
836    A = new AST::statementList();
837    // strip $
838    A->push_back(new (CTXT) AST::propertyDecl(CTXT, pSourceRange(++(*VAR).begin(), (*VAR).end()), NULL));
839}
840classVar(A) ::= T_VARIABLE(VAR) T_ASSIGN staticScalar(DEFAULT).
841{
842    A = new AST::statementList();
843    // strip $
844    A->push_back(new (CTXT) AST::propertyDecl(CTXT, pSourceRange(++(*VAR).begin(), (*VAR).end()), DEFAULT));
845}
846%type classConstantDecl {AST::statementList*}
847classConstantDecl(A) ::= classConstantDecl(LIST) T_COMMA T_IDENTIFIER(ID) T_ASSIGN staticScalar(DEFAULT).
848{
849    AST::propertyDecl* prop = new (CTXT) AST::propertyDecl(CTXT, *ID, DEFAULT);
850    prop->setFlags(AST::memberFlags::CONST);
851    LIST->push_back(prop);
852    A = LIST;
853}
854classConstantDecl(A) ::= T_CONST T_IDENTIFIER(ID) T_ASSIGN staticScalar(DEFAULT).
855{
856    A = new AST::statementList();
857    AST::propertyDecl* prop = new (CTXT) AST::propertyDecl(CTXT, *ID, DEFAULT);
858    prop->setFlags(AST::memberFlags::CONST);
859    A->push_back(prop);
860}
861
862%type methodFlags {pUInt*}
863methodFlags(A) ::= .
864{
865    // empty
866    A = NULL;
867}
868methodFlags(A) ::= nonEmptyMemberFlags(F). { A = F; }
869
870%type classVarFlags {const pUInt*}
871classVarFlags(A) ::= T_VAR.
872{
873    A = &AST::memberFlags::PUBLIC;
874}
875classVarFlags(A) ::= nonEmptyMemberFlags(F).
876{
877    if (*F & AST::memberFlags::ABSTRACT) {
878        CTXT.parseError("Cannot declare class variables abstract");
879    }
880    A = F;
881}
882
883%type nonEmptyMemberFlags {pUInt*}
884nonEmptyMemberFlags(A) ::= memberFlag(F).
885{
886    A = new (CTXT) pUInt(*F); // freed by context
887}
888nonEmptyMemberFlags(A) ::= nonEmptyMemberFlags(L) memberFlag(R).
889{
890    *L |= *R;
891    A = L;
892}
893
894%type memberFlag {const pUInt*}
895memberFlag(A) ::= T_PUBLIC. { A = &AST::memberFlags::PUBLIC; }
896memberFlag(A) ::= T_PROTECTED. { A = &AST::memberFlags::PROTECTED; }
897memberFlag(A) ::= T_PRIVATE. { A = &AST::memberFlags::PRIVATE; }
898memberFlag(A) ::= T_STATIC. { A = &AST::memberFlags::STATIC; }
899memberFlag(A) ::= T_ABSTRACT. { A = &AST::memberFlags::ABSTRACT; }
900memberFlag(A) ::= T_FINAL. { A = &AST::memberFlags::FINAL; }
901
902// if a method body is null, it's abstract
903%type methodBody {AST::block*}
904methodBody(A) ::= T_SEMI. { A = NULL; }
905methodBody(A) ::= statementBlock(B). { A = B; }
906
907// class extends at most one id
908%type classExtends {AST::sourceRangeList*}
909classExtends(A) ::= . { A = NULL; }
910classExtends(A) ::= T_EXTENDS T_IDENTIFIER(NAME).
911{
912    A = new AST::sourceRangeList();
913    A->push_back(NAME);
914}
915
916// interface extends 0-n ids
917%type interfaceExtends {AST::sourceRangeList*}
918interfaceExtends(A) ::= . { A = NULL; }
919interfaceExtends(A) ::= T_EXTENDS idList(LIST).
920{
921    A = LIST;
922}
923
924// class implements 0-n ids
925%type classImplements {AST::sourceRangeList*}
926classImplements(A) ::= . { A = NULL; }
927classImplements(A) ::= T_IMPLEMENTS idList(LIST).
928{
929    A = LIST;
930}
931
932// 1-n identifiers, comma separated
933%type idList {AST::sourceRangeList*}
934idList(A) ::= T_IDENTIFIER(NAME).
935{
936    A = new AST::sourceRangeList();
937    A->push_back(NAME);
938}
939idList(A) ::= idList(LIST) T_COMMA T_IDENTIFIER(NAME).
940{
941    LIST->push_back(NAME);
942    A = LIST;
943}
944
945
946/****** EXPRESSIONS *********/
947%type baseExpr {AST::expr*} // expr_without_variable
948baseExpr(A) ::= assignment(B). { A = B; }
949baseExpr(A) ::= opAssignment(B). { A = B; }
950baseExpr(A) ::= listAssignment(B). { A = B; }
951baseExpr(A) ::= functionInvoke(B). { A = B; }
952baseExpr(A) ::= constructorInvoke(B). { A = B; }
953baseExpr(A) ::= unaryOp(B). { A = B; }
954baseExpr(A) ::= binaryOp(B). { A = B; }
955baseExpr(A) ::= builtin(B). { A = B; }
956baseExpr(A) ::= typeCast(B). { A = B; }
957baseExpr(A) ::= preOp(B). { A = B; }
958baseExpr(A) ::= postOp(B). { A = B; }
959baseExpr(A) ::= conditionalExpr(B). { A = B; }
960baseExpr(A) ::= scalar(B). { A = B; }
961baseExpr(A) ::= literalArray(B). { A = B; }
962baseExpr(A) ::= T_LEFTPAREN expr(B) T_RIGHTPAREN. { A = B; }
963
964%type expr {AST::expr*} // expr
965expr(A) ::= baseExpr(B). { A = B; }
966expr(A) ::= rVar(B). { A = B; }
967
968/** BUILTINS **/
969%type builtin {AST::builtin*}
970// exit
971builtin(A) ::= T_EXIT.
972{
973    A = new (CTXT) AST::builtin(CTXT, AST::builtin::EXIT);
974    A->setLine(CURRENT_LINE);
975}
976builtin(A) ::= T_EXIT T_LEFTPAREN T_RIGHTPAREN.
977{
978    A = new (CTXT) AST::builtin(CTXT, AST::builtin::EXIT);
979    A->setLine(CURRENT_LINE);
980}
981builtin(A) ::= T_EXIT T_LEFTPAREN expr(RVAL) T_RIGHTPAREN.
982{
983    AST::expressionList* rVal = new AST::expressionList();
984    rVal->push_back(RVAL);
985    A = new (CTXT) AST::builtin(CTXT, AST::builtin::EXIT, rVal);
986    delete rVal;
987    A->setLine(CURRENT_LINE);
988}
989// empty
990builtin(A) ::= T_EMPTY T_LEFTPAREN var(RVAL) T_RIGHTPAREN.
991{
992    AST::expressionList* rVal = new AST::expressionList();
993    rVal->push_back(RVAL);
994    A = new (CTXT) AST::builtin(CTXT, AST::builtin::EMPTY, rVal);
995    delete rVal;
996    A->setLine(CURRENT_LINE);
997}
998// isset
999 builtin(A) ::= T_ISSET T_LEFTPAREN commaVarList(VARS) T_RIGHTPAREN.
1000{
1001   A = new (CTXT) AST::builtin(CTXT, AST::builtin::ISSET, VARS);
1002   A->setLine(CURRENT_LINE);
1003   delete VARS;
1004}
1005// unset
1006builtin(A) ::= T_UNSET T_LEFTPAREN commaVarList(VARS) T_RIGHTPAREN.
1007{
1008   A = new (CTXT) AST::builtin(CTXT, AST::builtin::UNSET, VARS);
1009   A->setLine(CURRENT_LINE);
1010   delete VARS;
1011}
1012// print
1013builtin(A) ::= T_PRINT expr(RVAL).
1014{
1015    AST::expressionList* rVal = new AST::expressionList();
1016    rVal->push_back(RVAL);
1017    A = new (CTXT) AST::builtin(CTXT, AST::builtin::PRINT, rVal);
1018    delete rVal;
1019    A->setLine(CURRENT_LINE);
1020}
1021// clone
1022builtin(A) ::= T_CLONE expr(RVAL).
1023{
1024    AST::expressionList* rVal = new AST::expressionList();
1025    rVal->push_back(RVAL);
1026    A = new (CTXT) AST::builtin(CTXT, AST::builtin::CLONE, rVal);
1027    delete rVal;
1028    A->setLine(CURRENT_LINE);
1029}
1030// include/require
1031builtin(A) ::= T_REQUIRE expr(RVAL).
1032{
1033    AST::expressionList* rVal = new AST::expressionList();
1034    rVal->push_back(RVAL);
1035    A = new (CTXT) AST::builtin(CTXT, AST::builtin::REQUIRE, rVal);
1036    delete rVal;
1037    A->setLine(CURRENT_LINE);
1038}
1039builtin(A) ::= T_REQUIRE_ONCE expr(RVAL).
1040{
1041    AST::expressionList* rVal = new AST::expressionList();
1042    rVal->push_back(RVAL);
1043    A = new (CTXT) AST::builtin(CTXT, AST::builtin::REQUIRE_ONCE, rVal);
1044    delete rVal;
1045    A->setLine(CURRENT_LINE);
1046}
1047builtin(A) ::= T_INCLUDE expr(RVAL).
1048{
1049    AST::expressionList* rVal = new AST::expressionList();
1050    rVal->push_back(RVAL);
1051    A = new (CTXT) AST::builtin(CTXT, AST::builtin::INCLUDE, rVal);
1052    delete rVal;
1053    A->setLine(CURRENT_LINE);
1054}
1055builtin(A) ::= T_INCLUDE_ONCE expr(RVAL).
1056{
1057    AST::expressionList* rVal = new AST::expressionList();
1058    rVal->push_back(RVAL);
1059    A = new (CTXT) AST::builtin(CTXT, AST::builtin::INCLUDE_ONCE, rVal);
1060    delete rVal;
1061    A->setLine(CURRENT_LINE);
1062}
1063builtin(A) ::= T_AT expr(RVAL).
1064{
1065    AST::expressionList* rVal = new AST::expressionList();
1066    rVal->push_back(RVAL);
1067    A = new (CTXT) AST::builtin(CTXT, AST::builtin::IGNORE_WARNING, rVal);
1068    delete rVal;
1069    A->setLine(CURRENT_LINE);
1070}
1071
1072%type commaVarList {AST::expressionList*}
1073commaVarList(A) ::= var(VAR).
1074{
1075    A = new AST::expressionList();
1076    A->push_back(VAR);
1077}
1078commaVarList(A) ::= commaVarList(LIST) T_COMMA var(VAR).
1079{
1080    LIST->push_back(VAR);
1081    A = LIST;
1082}
1083
1084%type globalVarList {AST::expressionList*}
1085globalVarList(A) ::= globalVar(B).
1086{
1087    A = new AST::expressionList();
1088    A->push_back(B);
1089}
1090globalVarList(A) ::= globalVarList(LIST) T_COMMA globalVar(B).
1091{
1092    LIST->push_back(B);
1093    A = LIST;
1094}
1095%type globalVar {AST::expr*}
1096globalVar(A) ::= T_VARIABLE(B).
1097{
1098    // strip $
1099    A = new (CTXT) AST::var(pSourceRange(++(*B).begin(), (*B).end()), CTXT);
1100}
1101globalVar(A) ::= T_DOLLAR rVar(B).
1102{
1103    AST::dynamicID* r = new (CTXT) AST::dynamicID(B);
1104    A = r;
1105}
1106// XXX support ${expr} format for globals here?
1107
1108%type staticVarList {AST::expressionList*}
1109staticVarList(A) ::= T_VARIABLE(B).
1110{
1111    A = new AST::expressionList();
1112    A->push_back(new (CTXT) AST::var(pSourceRange(++(*B).begin(), (*B).end()), CTXT));
1113}
1114staticVarList(A) ::= staticVarList(LIST) T_COMMA T_VARIABLE(B).
1115{
1116    // strip $
1117    LIST->push_back(new (CTXT) AST::var(pSourceRange(++(*B).begin(), (*B).end()), CTXT));
1118    A = LIST;
1119}
1120
1121%type commaExprList {AST::expressionList*}
1122commaExprList(A) ::= expr(E).
1123{
1124    A = new AST::expressionList();
1125    A->push_back(E);
1126}
1127commaExprList(A) ::= commaExprList(LIST) T_COMMA expr(E).
1128{
1129    LIST->push_back(E);
1130    A = LIST;
1131}
1132
1133// ternary operator
1134%type conditionalExpr {AST::conditionalExpr*}
1135conditionalExpr(A) ::= expr(COND) T_QUESTION expr(TRUE) T_COLON expr(FALSE).
1136{
1137    A = new (CTXT) AST::conditionalExpr(COND, TRUE, FALSE);
1138    A->setLine(CURRENT_LINE);
1139}
1140
1141/** TYPECASTS **/
1142%type typeCast {AST::typeCast*}
1143typeCast(A) ::= T_FLOAT_CAST expr(rVal).
1144{
1145    A = new (CTXT) AST::typeCast(AST::typeCast::REAL, rVal);
1146    A->setLine(CURRENT_LINE);
1147}
1148typeCast(A) ::= T_INT_CAST expr(rVal).
1149{
1150    A = new (CTXT) AST::typeCast(AST::typeCast::INT, rVal);
1151    A->setLine(CURRENT_LINE);
1152}
1153typeCast(A) ::= T_STRING_CAST expr(rVal).
1154{
1155    A = new (CTXT) AST::typeCast(AST::typeCast::STRING, rVal);
1156    A->setLine(CURRENT_LINE);
1157}
1158typeCast(A) ::= T_BINARY_CAST expr(rVal).
1159{
1160    A = new (CTXT) AST::typeCast(AST::typeCast::BINARY, rVal);
1161    A->setLine(CURRENT_LINE);
1162}
1163typeCast(A) ::= T_UNICODE_CAST expr(rVal).
1164{
1165    A = new (CTXT) AST::typeCast(AST::typeCast::UNICODE, rVal);
1166    A->setLine(CURRENT_LINE);
1167}
1168typeCast(A) ::= T_ARRAY_CAST expr(rVal).
1169{
1170    A = new (CTXT) AST::typeCast(AST::typeCast::ARRAY, rVal);
1171    A->setLine(CURRENT_LINE);
1172}
1173typeCast(A) ::= T_OBJECT_CAST expr(rVal).
1174{
1175    A = new (CTXT) AST::typeCast(AST::typeCast::OBJECT, rVal);
1176    A->setLine(CURRENT_LINE);
1177}
1178typeCast(A) ::= T_UNSET_CAST expr(rVal).
1179{
1180    A = new (CTXT) AST::typeCast(AST::typeCast::UNSET, rVal);
1181    A->setLine(CURRENT_LINE);
1182}
1183typeCast(A) ::= T_BOOL_CAST expr(rVal).
1184{
1185    A = new (CTXT) AST::typeCast(AST::typeCast::BOOL, rVal);
1186    A->setLine(CURRENT_LINE);
1187}
1188
1189
1190/** SCALAR **/
1191%type scalar {AST::expr*}
1192scalar(A) ::= literal(B). { A = B; }
1193scalar(A) ::= literalMagic(B). { A = B; }
1194// static constant
1195scalar(A) ::= T_IDENTIFIER(B).
1196{
1197    A = new (CTXT) AST::literalConstant(*B, CTXT);
1198    A->setLine(CURRENT_LINE);
1199}
1200// static class constant
1201scalar(A) ::= T_IDENTIFIER(TARGET) T_DBL_COLON T_IDENTIFIER(ID).
1202{
1203    A = new (CTXT) AST::literalConstant(*ID, CTXT, new (CTXT) AST::literalID(*TARGET, CTXT));
1204    A->setLine(CURRENT_LINE);
1205}
1206
1207// same as a scalar except can be +, - and array
1208%type staticScalar {AST::expr*}
1209staticScalar(A) ::= scalar(B). { A = B; }
1210staticScalar(A) ::= literalArray(B). { A = B; }
1211staticScalar ::= T_PLUS staticScalar. // ignore
1212staticScalar(A) ::= T_MINUS staticScalar(R).
1213{
1214    A = new (CTXT) AST::unaryOp(R, AST::unaryOp::NEGATIVE);
1215    A->setLine(CURRENT_LINE);
1216}
1217
1218%type literal {AST::literalExpr*} // common_scalar
1219// literal string
1220literal(A) ::= T_SQ_STRING(B).
1221{
1222  A = extractLiteralString(B, pMod, true);
1223  A->setLine(CURRENT_LINE);
1224}
1225literal(A) ::= T_DQ_STRING(B).
1226{
1227  A = extractLiteralString(B, pMod, false);
1228  A->setLine(CURRENT_LINE);
1229}
1230
1231// literal integers (decimal)
1232literal(A) ::= T_LNUMBER(B).
1233{
1234    A = new (CTXT) AST::literalInt(*B);
1235    A->setLine(CURRENT_LINE);
1236}
1237
1238// literal integers (float)
1239literal(A) ::= T_DNUMBER(B).
1240{
1241    A = new (CTXT) AST::literalFloat(*B);
1242    A->setLine(CURRENT_LINE);   
1243}
1244
1245// literal identifier: null, true, false or constant
1246literal(A) ::= T_TRUE.
1247{
1248    A = new (CTXT) AST::literalBool(true);
1249    A->setLine(CURRENT_LINE);
1250}
1251literal(A) ::= T_FALSE.
1252{
1253    A = new (CTXT) AST::literalBool(false);
1254    A->setLine(CURRENT_LINE);
1255}
1256literal(A) ::= T_NULL.
1257{
1258    A = new (CTXT) AST::literalNull();
1259    A->setLine(CURRENT_LINE);
1260}
1261
1262%type literalMagic {AST::expr*}
1263literalMagic(A) ::= T_MAGIC_FILE(ID).
1264{
1265    A = new (CTXT) AST::literalID(*ID, CTXT);
1266    A->setLine(CURRENT_LINE);
1267}
1268literalMagic(A) ::= T_MAGIC_LINE(ID).
1269{
1270    A = new (CTXT) AST::literalID(*ID, CTXT);
1271    A->setLine(CURRENT_LINE);
1272}
1273literalMagic(A) ::= T_MAGIC_CLASS(ID).
1274{
1275    A = new (CTXT) AST::literalID(*ID, CTXT);
1276    A->setLine(CURRENT_LINE);
1277}
1278literalMagic(A) ::= T_MAGIC_METHOD(ID).
1279{
1280    A = new (CTXT) AST::literalID(*ID, CTXT);
1281    A->setLine(CURRENT_LINE);
1282}
1283literalMagic(A) ::= T_MAGIC_FUNCTION(ID).
1284{
1285    A = new (CTXT) AST::literalID(*ID, CTXT);
1286    A->setLine(CURRENT_LINE);
1287}
1288literalMagic(A) ::= T_MAGIC_NS(ID).
1289{
1290    A = new (CTXT) AST::literalID(*ID, CTXT);
1291    A->setLine(CURRENT_LINE);
1292}
1293
1294
1295/** LITERAL ARRAY ITEMS **/
1296%type arrayItemList {AST::arrayList*}
1297arrayItemList(A) ::= arrayItem(B).
1298{
1299    A = new AST::arrayList();
1300    A->push_back(*B); // copy item into vector
1301    // note no delete here because it's in ast pool
1302}
1303arrayItemList(A) ::= arrayItem(B) T_COMMA arrayItemList(C).
1304{
1305    C->push_back(*B); // copy item into vector
1306    A = C;
1307    // note no delete here because it's in ast pool
1308}
1309arrayItemList(A) ::= .
1310{
1311    A = new AST::arrayList();
1312}
1313
1314%type arrayItem {AST::arrayItem*}
1315arrayItem(A) ::= expr(B).
1316{
1317    A = new (CTXT) AST::arrayItem(NULL, B, false);
1318}
1319arrayItem(A) ::= T_AND expr(B).
1320{
1321    A = new (CTXT) AST::arrayItem(NULL, B, true);
1322}
1323arrayItem(A) ::= expr(KEY) T_ARROWKEY expr(VAL).
1324{
1325    A = new (CTXT) AST::arrayItem(KEY, VAL, false);
1326}
1327arrayItem(A) ::= expr(KEY) T_ARROWKEY T_AND expr(VAL).
1328{
1329    A = new (CTXT) AST::arrayItem(KEY, VAL, true);
1330}
1331
1332// literal array
1333%type literalArray {AST::literalExpr*}
1334literalArray(A) ::= T_ARRAY(ARY) T_LEFTPAREN arrayItemList(B) T_RIGHTPAREN.
1335{
1336    A = new (CTXT) AST::literalArray(B);
1337    A->setLine(TOKEN_LINE(ARY));
1338    delete B; // deletes the vector, NOT the exprs in it!
1339}
1340
1341/** UNARY OPERATORS **/
1342%type unaryOp {AST::unaryOp*}
1343unaryOp(A) ::= T_PLUS expr(R).
1344{
1345    A = new (CTXT) AST::unaryOp(R, AST::unaryOp::POSITIVE);
1346    A->setLine(CURRENT_LINE);
1347}
1348unaryOp(A) ::= T_MINUS expr(R).
1349{
1350    A = new (CTXT) AST::unaryOp(R, AST::unaryOp::NEGATIVE);
1351    A->setLine(CURRENT_LINE);
1352}
1353unaryOp(A) ::= T_BOOLEAN_NOT expr(R).
1354{
1355    A = new (CTXT) AST::unaryOp(R, AST::unaryOp::LOGICALNOT);
1356    A->setLine(CURRENT_LINE);
1357}
1358unaryOp(A) ::= T_TILDE expr(R).
1359{
1360    A = new (CTXT) AST::unaryOp(R, AST::unaryOp::BITWISENOT);
1361    A->setLine(CURRENT_LINE);
1362}
1363/** BINARY OPERATORS **/
1364%type binaryOp {AST::binaryOp*}
1365binaryOp(A) ::= expr(L) T_DOT expr(R).
1366{
1367    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::CONCAT);
1368    A->setLine(CURRENT_LINE);
1369}
1370binaryOp(A) ::= expr(L) T_BOOLEAN_AND expr(R).
1371{
1372    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::BOOLEAN_AND);
1373    A->setLine(CURRENT_LINE);
1374}
1375binaryOp(A) ::= expr(L) T_BOOLEAN_AND_LIT expr(R).
1376{
1377    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::BOOLEAN_AND);
1378    A->setLine(CURRENT_LINE);
1379}
1380binaryOp(A) ::= expr(L) T_BOOLEAN_OR expr(R).
1381{
1382    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::BOOLEAN_OR);
1383    A->setLine(CURRENT_LINE);
1384}
1385binaryOp(A) ::= expr(L) T_BOOLEAN_OR_LIT expr(R).
1386{
1387    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::BOOLEAN_OR);
1388    A->setLine(CURRENT_LINE);
1389}
1390binaryOp(A) ::= expr(L) T_BOOLEAN_XOR_LIT expr(R).
1391{
1392    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::BOOLEAN_XOR);
1393    A->setLine(CURRENT_LINE);
1394}
1395binaryOp(A) ::= expr(L) T_DIV expr(R).
1396{
1397    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::DIV);
1398    A->setLine(CURRENT_LINE);
1399}
1400binaryOp(A) ::= expr(L) T_MOD expr(R).
1401{
1402    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::MOD);
1403    A->setLine(CURRENT_LINE);
1404}
1405binaryOp(A) ::= expr(L) T_MULT expr(R).
1406{
1407    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::MULT);
1408    A->setLine(CURRENT_LINE);
1409}
1410binaryOp(A) ::= expr(L) T_PLUS expr(R).
1411{
1412    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::ADD);
1413    A->setLine(CURRENT_LINE);
1414}
1415binaryOp(A) ::= expr(L) T_MINUS expr(R).
1416{
1417    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::SUB);
1418    A->setLine(CURRENT_LINE);
1419}
1420binaryOp(A) ::= expr(L) T_GREATER_THAN expr(R).
1421{
1422    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::GREATER_THAN);
1423    A->setLine(CURRENT_LINE);
1424}
1425binaryOp(A) ::= expr(L) T_LESS_THAN expr(R).
1426{
1427    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::LESS_THAN);
1428    A->setLine(CURRENT_LINE);
1429}
1430binaryOp(A) ::= expr(L) T_GREATER_OR_EQUAL expr(R).
1431{
1432    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::GREATER_OR_EQUAL);
1433    A->setLine(CURRENT_LINE);
1434}
1435binaryOp(A) ::= expr(L) T_LESS_OR_EQUAL expr(R).
1436{
1437    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::LESS_OR_EQUAL);
1438    A->setLine(CURRENT_LINE);
1439}
1440binaryOp(A) ::= expr(L) T_EQUAL expr(R).
1441{
1442    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::EQUAL);
1443    A->setLine(CURRENT_LINE);
1444}
1445binaryOp(A) ::= expr(L) T_NOT_EQUAL expr(R).
1446{
1447    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::NOT_EQUAL);
1448    A->setLine(CURRENT_LINE);
1449}
1450binaryOp(A) ::= expr(L) T_IDENTICAL expr(R).
1451{
1452    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::IDENTICAL);
1453    A->setLine(CURRENT_LINE);
1454}
1455binaryOp(A) ::= expr(L) T_NOT_IDENTICAL expr(R).
1456{
1457    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::NOT_IDENTICAL);
1458    A->setLine(CURRENT_LINE);
1459}
1460binaryOp(A) ::= expr(L) T_CARET expr(R).
1461{
1462    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::BIT_XOR);
1463    A->setLine(CURRENT_LINE);
1464}
1465binaryOp(A) ::= expr(L) T_PIPE expr(R).
1466{
1467    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::BIT_OR);
1468    A->setLine(CURRENT_LINE);
1469}
1470binaryOp(A) ::= expr(L) T_AND expr(R).
1471{
1472    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::BIT_AND);
1473    A->setLine(CURRENT_LINE);
1474}
1475binaryOp(A) ::= expr(L) T_SL expr(R).
1476{
1477    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::SHIFT_LEFT);
1478    A->setLine(CURRENT_LINE);
1479}
1480binaryOp(A) ::= expr(L) T_SR expr(R).
1481{
1482    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::SHIFT_RIGHT);
1483    A->setLine(CURRENT_LINE);
1484}
1485binaryOp(A) ::= expr(L) T_INSTANCEOF maybeDynamicID(R).
1486{
1487    A = new (CTXT) AST::binaryOp(L, R, AST::binaryOp::INSTANCEOF);
1488    A->setLine(CURRENT_LINE);
1489}
1490
1491/** PRE/POST OP **/
1492%type preOp {AST::preOp*}
1493preOp(A) ::= T_INC var(R).
1494{
1495    A = new (CTXT) AST::preOp(R, AST::preOp::INC);
1496    A->setLine(CURRENT_LINE);
1497}
1498preOp(A) ::= T_DEC var(R).
1499{
1500    A = new (CTXT) AST::preOp(R, AST::preOp::DEC);
1501    A->setLine(CURRENT_LINE);
1502}
1503%type postOp {AST::postOp*}
1504postOp(A) ::= var(R) T_INC.
1505{
1506    A = new (CTXT) AST::postOp(R, AST::postOp::INC);
1507    A->setLine(CURRENT_LINE);
1508}
1509postOp(A) ::= var(R) T_DEC.
1510{
1511    A = new (CTXT) AST::postOp(R, AST::postOp::DEC);
1512    A->setLine(CURRENT_LINE);
1513}
1514
1515/** ASSIGNMENT **/
1516%type assignment {AST::assignment*}
1517assignment(A) ::= var(L) T_ASSIGN(EQ_SIGN) expr(R).
1518{
1519    A = new (CTXT) AST::assignment(L, R, false);
1520    A->setLine(TOKEN_LINE(EQ_SIGN));
1521}
1522assignment(A) ::= var(L) T_ASSIGN T_AND(EQ_SIGN) var(R).
1523{
1524    A = new (CTXT) AST::assignment(L, R, true);
1525    A->setLine(TOKEN_LINE(EQ_SIGN));
1526}
1527assignment(A) ::= var(L) T_ASSIGN T_AND(EQ_SIGN) functionInvoke(R).
1528{
1529    A = new (CTXT) AST::assignment(L, R, true);
1530    A->setLine(TOKEN_LINE(EQ_SIGN));
1531}
1532assignment(A) ::= var(L) T_ASSIGN T_AND(EQ_SIGN) constructorInvoke(R).
1533{
1534    A = new (CTXT) AST::assignment(L, R, true);
1535    A->setLine(TOKEN_LINE(EQ_SIGN));
1536}
1537
1538%type opAssignment {AST::opAssignment*}
1539opAssignment(A) ::= var(L) T_AND_EQUAL(EQ_SIGN) expr(R).
1540{
1541    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::AND);
1542    A->setLine(TOKEN_LINE(EQ_SIGN));
1543}
1544opAssignment(A) ::= var(L) T_OR_EQUAL(EQ_SIGN) expr(R).
1545{
1546    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::OR);
1547    A->setLine(TOKEN_LINE(EQ_SIGN));
1548}
1549opAssignment(A) ::= var(L) T_XOR_EQUAL(EQ_SIGN) expr(R).
1550{
1551    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::XOR);
1552    A->setLine(TOKEN_LINE(EQ_SIGN));
1553}
1554opAssignment(A) ::= var(L) T_CONCAT_EQUAL(OP) expr(R).
1555{
1556    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::CONCAT);
1557    A->setLine(TOKEN_LINE(OP));
1558}
1559opAssignment(A) ::= var(L) T_DIV_EQUAL(OP) expr(R).
1560{
1561    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::DIV);
1562    A->setLine(TOKEN_LINE(OP));
1563}
1564opAssignment(A) ::= var(L) T_MUL_EQUAL(OP) expr(R).
1565{
1566    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::MULT);
1567    A->setLine(TOKEN_LINE(OP));
1568}
1569opAssignment(A) ::= var(L) T_PLUS_EQUAL(OP) expr(R).
1570{
1571    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::ADD);
1572    A->setLine(TOKEN_LINE(OP));
1573}
1574opAssignment(A) ::= var(L) T_MINUS_EQUAL(OP) expr(R).
1575{
1576    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::SUB);
1577    A->setLine(TOKEN_LINE(OP));
1578}
1579opAssignment(A) ::= var(L) T_MOD_EQUAL(OP) expr(R).
1580{
1581    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::MOD);
1582    A->setLine(TOKEN_LINE(OP));
1583}
1584opAssignment(A) ::= var(L) T_SL_EQUAL(OP) expr(R).
1585{
1586    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::SHIFT_LEFT);
1587    A->setLine(TOKEN_LINE(OP));
1588}
1589opAssignment(A) ::= var(L) T_SR_EQUAL(OP) expr(R).
1590{
1591    A = new (CTXT) AST::opAssignment(L, R, AST::opAssignment::SHIFT_RIGHT);
1592    A->setLine(TOKEN_LINE(OP));
1593}
1594
1595%type listAssignment {AST::listAssignment*}
1596listAssignment(A) ::= T_LIST(LIST) T_LEFTPAREN listAssignmentList(VARS) T_RIGHTPAREN T_ASSIGN expr(RVAL).
1597{
1598    AST::block* varList = new (CTXT) AST::block(CTXT, VARS);
1599    A = new (CTXT) AST::listAssignment(varList, RVAL);
1600    A->setLine(TOKEN_LINE(LIST));
1601    delete VARS;
1602}
1603
1604%type listAssignmentList {AST::statementList*}
1605listAssignmentList(A) ::= listElement(E).
1606{
1607    A = new AST::statementList();
1608    A->push_back(E);
1609}
1610listAssignmentList(A) ::= listAssignmentList(LIST) T_COMMA listElement(E).
1611{
1612    LIST->push_back(E);
1613    A = LIST;
1614}
1615// note a listElement can be null
1616%type listElement {AST::stmt*}
1617// simple var, may include array indices
1618listElement(A) ::= var(VAR). { A = VAR; }
1619// nested list, return a block
1620listElement(A) ::= T_LIST T_LEFTPAREN listAssignmentList(VARS) T_RIGHTPAREN.
1621{
1622    AST::block* varList = new (CTXT) AST::block(CTXT, VARS);
1623    A = static_cast<AST::stmt*>(varList);
1624    delete VARS;
1625}
1626// empty, i.e. skipped
1627listElement(A) ::= . { A = NULL; }
1628
1629/** VARIABLES **/
1630%type rVar {AST::expr*}
1631rVar(A) ::= var(B). { A = B; }
1632/*
1633%type wVar {AST::expr*}
1634wVar(A) ::= var(B). { A = B; }
1635%type rwVar {AST::expr*}
1636rwVar(A) ::= var(B). { A = B; }
1637*/
1638
1639%type var {AST::expr*}
1640var(A) ::= varWithFunCalls(B). { A = B; }
1641
1642/* xx imported from matching phc rule xx
1643 *
1644 * The original rule read
1645 *
1646 * variable ::= base_variable_with_function_calls O_SINGLEARROW object_property
1647 *     method_or_not variable_properties
1648 *
1649 * However, this duplicates work done in variable_properties, because
1650 * variable_properties is a list of variable_property's, and
1651 *
1652 * variable_property ::= O_SINGLEARROW object_property method_or_not
1653 *
1654 * Now, in the original grammar, variable_properties allows for an empty list;
1655 * that's now changed, so that it requires at least one variable_property.
1656 *
1657 * We don't normally change the grammar, but this rule is difficult enough
1658 * as it is, so that we don't want to be duplicating code.
1659 */
1660var(A) ::= varWithFunCalls(TARGET) varPropertyList(PROPS).
1661{
1662  for (AST::expressionList::iterator i = PROPS->begin();
1663       i != PROPS->end();
1664       ++i) {
1665
1666      AST::var* v = dyn_cast<AST::var>(*i);
1667      if (v) {
1668          v->setTarget(TARGET);
1669          // XXX phc checks for function params attribute here and
1670          // makes a new method call if it finds them, otherwise returning the var
1671          // we just do the var here so far
1672          TARGET = v;
1673      }
1674      else {
1675          AST::functionInvoke* f = dyn_cast<AST::functionInvoke>(*i);
1676          assert(f && "expected function invoke");
1677          f->setTarget(TARGET);
1678          TARGET = f;
1679      }
1680
1681  }
1682  A = TARGET;
1683
1684}
1685
1686%type varPropertyList {AST::expressionList*}
1687varPropertyList(A) ::= varPropertyList(LIST) varProperty(PROP).
1688{
1689    LIST->push_back(PROP);
1690    A = LIST;
1691}
1692varPropertyList(A) ::= varProperty(PROP).
1693{
1694    A = new AST::expressionList();
1695    A->push_back(PROP);
1696}
1697
1698/* xx imported from matching phc rule xx
1699 *
1700 * We decide to synthesise an Variable or an Method_invocation
1701 * based on the absence or presence of a parameter list (method_or_not).
1702 * If there is a parameter list, we _try_ to generate a method invocation.
1703 *
1704 * To do this, we take the name of the variable synthesised by
1705 * object_property, and use it for the name of the method invocation. That is,
1706 * if the name of the variable is VarName[x], we convert it to FnName[x];
1707 * otherwise, it must be an expression and we use the name as-is.
1708 *
1709 * However, this fails to work if the variable has array indices. This is
1710 * the case, for example, in "$x->f[]()" (i.e., "f[]()" as far as
1711 * variable_property is concerned). In this case, the name of the method
1712 * is "$x->f[]"; however, we cannot generate this here because we don't
1713 * know the "$x" part. Instead, we synthesise up "f[]" (Variable), and
1714 * we set a private attribute in Variable, called "function_params", to
1715 * the parameters of the method. The rule "variable ::= " must check for
1716 * this attribute, and generate the correct method invocation if set.
1717 */
1718%type varProperty {AST::expr*}
1719varProperty(A) ::= T_CLASSDEREF objProperty(PROP) maybeMethodInvoke(ARGS).
1720{
1721    if (ARGS) {
1722        // XXX phc checks for array indices on PROP
1723        AST::functionInvoke* f = new (CTXT) AST::functionInvoke(new (CTXT) AST::literalID(PROP->name(), CTXT), CTXT, ARGS);       
1724        A = f;
1725        // PROP is now orphaned
1726        PROP->destroy(CTXT);
1727    }
1728    else {
1729        // var
1730        A = PROP;
1731    }
1732}
1733
1734%type maybeMethodInvoke {AST::expressionList*}
1735maybeMethodInvoke(A) ::= T_LEFTPAREN argList(ARGS) T_RIGHTPAREN.
1736{
1737    A = ARGS;
1738}
1739maybeMethodInvoke(A) ::= . { A  = NULL; }
1740
1741%type varNoObjects {AST::var*}
1742varNoObjects(A) ::= refVar(VAR). { A = VAR; }
1743varNoObjects(A) ::= varVar(COUNT) refVar(VAR).
1744{
1745    VAR->setIndirectionCount(*COUNT);
1746    delete COUNT;
1747    A = VAR;
1748}
1749
1750// foo::$bar
1751%type staticMember {AST::expr*}
1752staticMember(A) ::= T_IDENTIFIER(TARGET) T_DBL_COLON varNoObjects(VAR).
1753{
1754    VAR->setTarget(new (CTXT) AST::literalID(*TARGET, CTXT));
1755    A = VAR;
1756}
1757
1758%type varWithFunCalls {AST::expr*}
1759varWithFunCalls(A) ::= baseVar(VAR). { A = VAR; }
1760varWithFunCalls(A) ::= functionInvoke(FUN). { A = FUN; }
1761
1762%type baseVar {AST::expr*}
1763baseVar(A) ::= varNoObjects(VAR). { A = VAR; }
1764baseVar(A) ::= staticMember(B). { A = B; }
1765
1766%type refVar {AST::var*}
1767refVar(A) ::= T_VARIABLE(B).
1768{
1769    // strip $
1770    A = new (CTXT) AST::var(pSourceRange(++(*B).begin(), (*B).end()), CTXT);
1771    A->setLine(CURRENT_LINE);
1772}
1773refVar(A) ::= T_VARIABLE(B) arrayIndices(C).
1774{
1775    // strip $
1776    A = new (CTXT) AST::var(pSourceRange(++(*B).begin(), (*B).end()), CTXT, C);
1777    A->setLine(CURRENT_LINE);
1778    delete C;
1779}
1780// XXX refVar: support ${expr} syntax here?
1781/////
1782
1783%type objProperty {AST::var*}
1784objProperty(A) ::= T_IDENTIFIER(ID).
1785{
1786    A = new (CTXT) AST::var(*ID, CTXT);
1787    A->setLine(CURRENT_LINE);
1788}
1789objProperty(A) ::= T_IDENTIFIER(ID) arrayIndices(INDICES).
1790{
1791    A = new (CTXT) AST::var(*ID, CTXT, INDICES);
1792    A->setLine(CURRENT_LINE);
1793    delete INDICES;
1794}
1795// XXX objProperty: support $foo->$bar here?
1796// XXX objProperty: support $foo->${baz} here?
1797
1798%type varVar {pUInt*}
1799varVar(A) ::= T_DOLLAR. { A = new pUInt(1); }
1800varVar(A) ::= varVar(COUNT) T_DOLLAR. { (*COUNT)++; A = COUNT; }
1801
1802/** ARGLIST **/
1803%type argList {AST::expressionList*}
1804argList(A) ::= expr(B).
1805{
1806    A = new AST::expressionList();
1807    A->push_back(B);
1808}
1809argList(A) ::= expr(B) T_COMMA argList(C).
1810{
1811    C->push_back(B);
1812    A = C;
1813}
1814argList(A) ::= .
1815{
1816    A = new AST::expressionList();
1817}
1818
1819/** ARRAY INDICES **/
1820%type arrayIndices {AST::expressionList*}
1821arrayIndices(A) ::= T_LEFTSQUARE expr(B) T_RIGHTSQUARE.
1822{
1823    A = new AST::expressionList();
1824    A->push_back(B);
1825}
1826arrayIndices(A) ::= T_LEFTCURLY expr(B) T_RIGHTCURLY.
1827{
1828    A = new AST::expressionList();
1829    A->push_back(B);
1830}
1831arrayIndices(A) ::= arrayIndices(B) T_LEFTSQUARE expr(C) T_RIGHTSQUARE.
1832{
1833    B->push_back(C);
1834    A = B;
1835}
1836arrayIndices(A) ::= arrayIndices(B) T_LEFTCURLY expr(C) T_RIGHTCURLY.
1837{
1838    // XXX unparse needs to know curly
1839    B->push_back(C);
1840    A = B;
1841}
1842arrayIndices(A) ::= T_LEFTSQUARE T_RIGHTSQUARE.
1843{
1844    A = new AST::expressionList();   
1845    AST::stmt* noop = new (CTXT) AST::emptyStmt();
1846    A->push_back(static_cast<AST::expr*>(noop));
1847}
1848arrayIndices(A) ::= arrayIndices(B) T_LEFTSQUARE T_RIGHTSQUARE.
1849{
1850    AST::stmt* noop = new (CTXT) AST::emptyStmt();
1851    B->push_back(static_cast<AST::expr*>(noop));
1852    A = B;
1853}
1854
1855/** FUNCTION/METHOD INVOKE **/
1856%type functionInvoke {AST::functionInvoke*}
1857// foo() or $foo() or $foo[1]() ...
1858functionInvoke(A) ::= maybeDynamicID(ID) T_LEFTPAREN argList(ARGS) T_RIGHTPAREN.
1859{
1860    A = new (CTXT) AST::functionInvoke(ID, // f name
1861                                       CTXT,
1862                                       ARGS  // expression list: arguments, copied
1863                                       );
1864    A->setLine(CURRENT_LINE);
1865    delete ARGS;
1866}
1867// foo::bar() (or self:: or parent::)
1868functionInvoke(A) ::= T_IDENTIFIER(TARGET) T_DBL_COLON T_IDENTIFIER(ID) T_LEFTPAREN argList(ARGS) T_RIGHTPAREN.
1869{
1870    A = new (CTXT) AST::functionInvoke(new (CTXT) AST::literalID(*ID, CTXT), // f name
1871                                       CTXT,
1872                                       ARGS,  // expression list: arguments, copied
1873                                       new (CTXT) AST::literalID(*TARGET, CTXT)
1874                                       );
1875    A->setLine(CURRENT_LINE);
1876    delete ARGS;
1877}
1878functionInvoke(A) ::= T_IDENTIFIER(TARGET) T_DBL_COLON varNoObjects(DNAME) T_LEFTPAREN argList(ARGS) T_RIGHTPAREN.
1879{
1880    A = new (CTXT) AST::functionInvoke(DNAME, // f name
1881                                       CTXT,
1882                                       ARGS,  // expression list: arguments, copied
1883                                       new (CTXT) AST::literalID(*TARGET, CTXT)
1884                                       );
1885    A->setLine(CURRENT_LINE);
1886    delete ARGS;
1887}
1888functionInvoke(A) ::= varNoObjects(DNAME) T_LEFTPAREN argList(ARGS) T_RIGHTPAREN.
1889{
1890    A = new (CTXT) AST::functionInvoke(DNAME, // f name
1891                                       CTXT,
1892                                       ARGS  // expression list: arguments, copied
1893                                       );
1894    A->setLine(CURRENT_LINE);
1895    delete ARGS;
1896}
1897
1898/** CONSTRUCTOR INVOKE **/
1899%type constructorInvoke {AST::functionInvoke*}
1900constructorInvoke(A) ::= T_NEW maybeDynamicID(ID) T_LEFTPAREN argList(C) T_RIGHTPAREN.
1901{
1902    A = new (CTXT) AST::functionInvoke(ID, // f name
1903                                       CTXT,
1904                                       C  // expression list: arguments, copied
1905                                       );
1906    A->setLine(CURRENT_LINE);
1907    delete C;
1908}
1909constructorInvoke(A) ::= T_NEW maybeDynamicID(ID).
1910{
1911    A = new (CTXT) AST::functionInvoke(ID, // f name
1912                                       CTXT
1913                                       );
1914    A->setLine(CURRENT_LINE);
1915}
1916
1917
1918
1919/* DYNAMIC IDENTIFIERS */
1920// these are either identifiers or a variable representing one
1921
1922%type literalID {AST::expr*}
1923literalID(A) ::= T_IDENTIFIER(ID).
1924{
1925    A = new (CTXT) AST::literalID(*ID, CTXT);
1926    A->setLine(CURRENT_LINE);
1927}
1928%type maybeDynamicID {AST::expr*}
1929maybeDynamicID(A) ::= literalID(B). { A = B; }
1930maybeDynamicID(A) ::= baseVar(VAL).
1931{
1932    A = new (CTXT) AST::dynamicID(VAL);
1933    A->setLine(CURRENT_LINE);
1934}
Note: See TracBrowser for help on using the browser.