1
2%{
3/* This file is part of kdev-pg-qt
4   Copyright (C) 2005 Roberto Raggi <roberto@kdevelop.org>
5   Copyright (C) 2006 Jakob Petsovits <jpetso@gmx.at>
6
7   This library is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public
9   License as published by the Free Software Foundation; either
10   version 2 of the License, or (at your option) any later version.
11
12   This library is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public License
18   along with this library; see the file COPYING.LIB.  If not, write to
19   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20   Boston, MA 02110-1301, USA.
21*/
22
23#include "kdev-pg.h"
24#include "kdev-pg-clone-tree.h"
25#include "kdev-pg-regexp.h"
26#include "kdev-pg-unicode-loader.h"
27#include "kdev-pg-checker.h"
28
29#include <QFile>
30#include <cassert>
31
32extern int yylex();
33extern void yyerror(const char* msg);
34extern int yyLine;
35
36QString lexerEnv;
37
38namespace KDevPG
39{
40    extern QFile file;
41    extern QTextStream checkOut;
42}
43
44KDevPG::Model::OperatorItem *operatorNode = 0;
45QString r;
46
47%}
48
49%union {
50    KDevPG::Model::Node *item;
51    char* str;
52    KDevPG::Model::VariableDeclarationItem::DeclarationType declarationType;
53    KDevPG::Model::VariableDeclarationItem::StorageType     storageType;
54    KDevPG::Model::VariableDeclarationItem::VariableType    variableType;
55    KDevPG::Model::Operator                                *operatorInformation;
56    KDevPG::GNFA                                           *nfa;
57}
58
59%token T_IDENTIFIER T_ARROW T_TERMINAL T_CODE T_STRING T_UNQUOTED_STRING T_NUMBER ';'
60%token T_TOKEN_DECLARATION T_TOKEN_STREAM_DECLARATION T_NAMESPACE_DECLARATION
61%token T_PARSERCLASS_DECLARATION T_LEXERCLASS_DECLARATION
62%token T_PUBLIC T_PRIVATE T_PROTECTED T_DECLARATION T_BITS
63%token T_CONSTRUCTOR T_DESTRUCTOR T_TRY_RECOVER T_TRY_ROLLBACK T_CATCH
64%token T_RULE_ARGUMENTS T_MEMBER T_TEMPORARY T_ARGUMENT T_EXPORT_MACRO
65%token T_NODE T_NODE_SEQUENCE T_TOKEN T_VARIABLE T_EXPORT_MACRO_HEADER
66%token T_AST_DECLARATION
67%token T_PARSER_DECLARATION_HEADER T_PARSER_BITS_HEADER T_AST_HEADER
68%token T_LEXER_DECLARATION_HEADER T_LEXER_BITS_HEADER
69%token T_PARSER_BASE T_AST_BASE T_LEXER_BASE
70%token T_BIN T_PRE T_POST T_TERN
71%token T_LOPR T_ROPR
72%token T_LEFT_ASSOC T_RIGHT_ASSOC T_IS_LEFT_ASSOC T_IS_RIGHT_ASSOC T_PRIORITY
73%token T_PAREN
74%token T_INLINE
75%token T_LEXER T_INPUT_STREAM T_INPUT_ENCODING T_TABLE_LEXER T_SEQUENCE_LEXER
76%token T_NAMED_REGEXP T_CONTINUE T_RANGE T_FAIL T_LOOKAHEAD T_BARRIER
77%token T_ENTER_RULE_SET T_LEAVE_RULE_SET
78
79%type<str> T_IDENTIFIER T_TERMINAL T_CODE T_STRING T_UNQUOTED_STRING T_RULE_ARGUMENTS T_NUMBER T_NAMED_REGEXP T_RANGE
80%type<str> name code_opt rule_arguments_opt priority assoc opt_lexer_action
81%type<item> item primary_item try_item primary_atom unary_item
82%type<item> postfix_item option_item item_sequence conditional_item
83%type<item> member_declaration_rest variableDeclarations variableDeclaration operatorRule
84%type<declarationType> declarationType_opt
85%type<storageType>     scope storageType
86%type<variableType>    variableType
87/* %type<void> operatorDeclaration operatorDeclarations operatorRule */
88%type<operatorInformation> operator
89%type<nfa> regexp regexp1 regexp2 regexp3 regexp4 regexp5 regexp6 regexp7 aregexp aregexp1 aregexp2 aregexp3 aregexp4 aregexp5 aregexp6 aregexp7
90
91%%
92
93system
94    : code_opt { KDevPG::globalSystem.decl = $1; }
95      declarations
96      rules
97      code_opt { KDevPG::globalSystem.bits += $5; }
98    ;
99
100declarations
101    : declaration
102    | declarations declaration
103    ;
104
105declaration
106    : T_PARSERCLASS_DECLARATION member_declaration_rest
107        { KDevPG::globalSystem.pushParserClassMember($2); }
108    | T_PARSERCLASS_DECLARATION '(' T_BITS ')' T_CODE
109        { KDevPG::globalSystem.bits += $5; }
110    | T_LEXERCLASS_DECLARATION member_declaration_rest
111        { KDevPG::globalSystem.pushLexerClassMember($2); }
112    | T_LEXERCLASS_DECLARATION '(' T_BITS ')' T_CODE
113        { KDevPG::globalSystem.lexerBits += $5; }
114    | T_TOKEN_DECLARATION declared_tokens ';'
115    | T_TABLE_LEXER
116      { if(KDevPG::globalSystem.hasLexer)
117        { KDevPG::checkOut << "** ERROR you have to specify the lexer-type (%table_lexer) before any lexer rules"; exit(-1); }
118        switch(KDevPG::GDFA::type)
119        {
120          case KDevPG::SAscii: KDevPG::GDFA::type = KDevPG::TAscii; break;
121          case KDevPG::SLatin1: KDevPG::GDFA::type = KDevPG::TLatin1; break;
122          case KDevPG::SUtf8: KDevPG::GDFA::type = KDevPG::TUtf8; break;
123          case KDevPG::SUcs2: KDevPG::GDFA::type = KDevPG::TUcs2; break;
124          case KDevPG::SUtf16: KDevPG::GDFA::type = KDevPG::TUtf16; break;
125/*           case KDevPG::SUcs4: KDevPG::GDFA::type = KDevPG::TUcs4; break; */
126          default: /* empty */;
127        }
128      }
129    | T_SEQUENCE_LEXER
130      { if(KDevPG::globalSystem.hasLexer)
131      { KDevPG::checkOut << "** ERROR you have to specify the lexer-type (%sequence_lexer) before any lexer rules"; exit(-1); }
132      switch(KDevPG::GDFA::type)
133      {
134        case KDevPG::TAscii: KDevPG::GDFA::type = KDevPG::SAscii; break;
135        case KDevPG::TLatin1: KDevPG::GDFA::type = KDevPG::SLatin1; break;
136        case KDevPG::TUtf8: KDevPG::GDFA::type = KDevPG::SUtf8; break;
137        case KDevPG::TUcs2: KDevPG::GDFA::type = KDevPG::SUcs2; break;
138        case KDevPG::TUtf16: KDevPG::GDFA::type = KDevPG::SUtf16; break;
139/*         case KDevPG::TUcs4: KDevPG::GDFA::type = KDevPG::SUcs4; break; */
140        default: /* empty */;
141      }
142      }
143    | T_INPUT_ENCODING T_STRING
144      {
145        if(KDevPG::globalSystem.hasLexer)
146        { KDevPG::checkOut << "** ERROR you have to specify the lexer-type (%sequence_lexer) before any lexer rules"; exit(-1); }
147        int base = (KDevPG::GDFA::type / 4) * 4; // warning: magic constant: number of different codecs
148        QString str = $2;
149        str = str.toLower();
150        str.replace('-', "");
151        if(str == "ascii")
152          /* base += 0*/;
153        else if(str == "latin1")
154          base += 1;
155        else if(str == "utf8")
156          base += 2;
157        else if(str == "ucs2")
158          base += 3;
159        else if(str == "utf16")
160          base += 4;
161        else if(str == "ucs4" || str == "utf32")
162          base += 5;
163        else
164        {
165          KDevPG::checkOut << "** ERROR unknown codec  ``" << $2 << "''" << endl;
166          exit(-1);
167        }
168        KDevPG::GDFA::type = KDevPG::AutomatonType(base);
169      }
170    | T_TOKEN_STREAM_DECLARATION T_IDENTIFIER ';'
171        { KDevPG::globalSystem.tokenStream = $2;           }
172    | T_EXPORT_MACRO T_STRING
173        { KDevPG::globalSystem.exportMacro = $2;           }
174    | T_EXPORT_MACRO_HEADER T_STRING
175        { KDevPG::globalSystem.exportMacroHeader = $2;     }
176    | T_NAMESPACE_DECLARATION T_CODE
177        { KDevPG::globalSystem.namespaceCode = $2;         }
178    | T_AST_DECLARATION T_CODE
179        { KDevPG::globalSystem.astCode = $2;               }
180    | T_PARSER_DECLARATION_HEADER T_STRING
181        { KDevPG::globalSystem.pushParserDeclarationHeader($2); }
182    | T_PARSER_BITS_HEADER T_STRING
183        { KDevPG::globalSystem.pushParserBitsHeader($2); }
184    | T_AST_HEADER T_STRING
185        { KDevPG::globalSystem.pushAstHeader($2); }
186    | T_LEXER_DECLARATION_HEADER T_STRING
187        { KDevPG::globalSystem.pushLexerDeclarationHeader($2); }
188    | T_INPUT_STREAM T_STRING
189        { KDevPG::globalSystem.inputStream = $2; }
190    | T_LEXER_BITS_HEADER T_STRING
191        { KDevPG::globalSystem.pushLexerBitsHeader($2); }
192    | T_AST_BASE T_IDENTIFIER T_STRING
193        { KDevPG::globalSystem.astBaseClasses[$2] = $3; }
194    | T_PARSER_BASE T_STRING
195        { KDevPG::globalSystem.parserBaseClass = $2; }
196    | T_LEXER_BASE T_STRING
197        { KDevPG::globalSystem.lexerBaseClass = $2; }
198    | T_LEXER T_STRING { KDevPG::globalSystem.hasLexer = true; lexerEnv = $2; if(KDevPG::globalSystem.lexerActions[lexerEnv].empty()) KDevPG::globalSystem.lexerActions[lexerEnv].push_back("qDebug() << \"error\"; exit(-1);"); } T_ARROW lexer_declaration_rest ';'
199    | T_LEXER { KDevPG::globalSystem.hasLexer = true; KDevPG::loadUnicodeData(); lexerEnv = "start"; if(KDevPG::globalSystem.lexerActions["start"].empty()) KDevPG::globalSystem.lexerActions["start"].push_back("qDebug() << \"error\"; exit(-1);"); } T_ARROW lexer_declaration_rest ';'
200    ;
201
202lexer_declaration_rest
203    : regexp T_ARROW T_IDENTIFIER ';'
204            { KDevPG::globalSystem.regexpById[$3] = $1;
205            } lexer_declaration_rest
206    | regexp code_opt opt_lexer_action ';'
207            {
208              if($1->acceptsEpsilon())
209                KDevPG::checkOut << "** WARNING Lexer rule accepting the empty word at line " << yyLine << endl;
210              else if($1->isEmpty())
211                KDevPG::checkOut << "** WARNING Lexer rule not accepting anything at line " << yyLine << endl;
212              QString s = QString($2) + QString(r);
213              KDevPG::globalSystem.lexerEnvs[lexerEnv].push_back($1);
214              KDevPG::globalSystem.lexerActions[lexerEnv].push_back(s);
215            } lexer_declaration_rest
216    | regexp T_LOOKAHEAD '(' regexp ')' code_opt opt_lexer_action ';'
217            {
218              if($1->acceptsEpsilon())
219                KDevPG::checkOut << "** WARNING Lexer rule accepting the empty word at line " << yyLine << endl;
220              else if($1->isEmpty())
221                KDevPG::checkOut << "** WARNING Lexer rule not accepting anything at line " << yyLine << endl;
222              bool ignore = false;
223              auto minLen = $4->minLength(), maxLen = $4->maxLength();
224              if(minLen == 0)
225              {
226                KDevPG::checkOut << "** WARNING Lexer rule specifying epsilon-lookahead at line " << yyLine << ", ignore the lookahead." << endl;
227                ignore = true;
228              }
229              else if(minLen != maxLen)
230              {
231                KDevPG::checkOut << "** WARNING Invalid lookahead (no fixed length) at line " << yyLine << " (min length: " << (minLen == -1 ? "none" : QString::number(minLen)) << ", max length: " << (maxLen == -2 ? "infinity" : (maxLen == -1 ? "none" : QString::number(maxLen))) << "), ignore the lookahead." << endl;
232                ignore = true;
233              }
234              if(ignore)
235              {
236                QString s = QString($6) + QString(r);
237                KDevPG::globalSystem.lexerEnvs[lexerEnv].push_back($1);
238                KDevPG::globalSystem.lexerActions[lexerEnv].push_back(s);
239              }
240              else
241              {
242                QString s = "Iterator::plain() -= " + QString::number(minLen) + "; " + QString($6) + QString(r);
243                *$1 <<= *$4;
244                KDevPG::globalSystem.lexerEnvs[lexerEnv].push_back($1);
245                KDevPG::globalSystem.lexerActions[lexerEnv].push_back(s);
246              }
247            } lexer_declaration_rest
248    | regexp T_BARRIER '(' regexp ')' code_opt opt_lexer_action ';'
249            {
250              if($1->acceptsEpsilon())
251                KDevPG::checkOut << "** WARNING Lexer rule accepting the empty word at line " << yyLine << endl;
252              else if($1->isEmpty())
253                KDevPG::checkOut << "** WARNING Lexer rule not accepting anything at line " << yyLine << endl;
254              bool ignore = false;
255              auto minLen = $4->minLength(), maxLen = $4->maxLength();
256              if(minLen == 0)
257              {
258                KDevPG::checkOut << "** WARNING Lexer rule specifying epsilon-barrier at line " << yyLine << ", ignore the barrier." << endl;
259                ignore = true;
260              }
261              else if(minLen != maxLen)
262              {
263                KDevPG::checkOut << "** WARNING Invalid barrier (no fixed length) at line " << yyLine << " (min length: " << (minLen == -1 ? "none" : QString::number(minLen)) << ", max length: " << (maxLen == -2 ? "infinity" : (maxLen == -1 ? "none" : QString::number(maxLen))) << "), ignore the barrier." << endl;
264                ignore = true;
265              }
266              if(ignore)
267              {
268                QString s = QString($6) + QString(r);
269                KDevPG::globalSystem.lexerEnvs[lexerEnv].push_back($1);
270                KDevPG::globalSystem.lexerActions[lexerEnv].push_back(s);
271              }
272              else
273              {
274                KDevPG::GNFA exclude = KDevPG::GNFA::anything();
275                exclude <<= *$4;
276                exclude <<= KDevPG::GNFA::anything();
277                KDevPG::GNFA *staying = new KDevPG::GNFA(*$1);
278                *staying ^= exclude;
279                KDevPG::globalSystem.lexerEnvs[lexerEnv].push_back(staying);
280                KDevPG::globalSystem.lexerActions[lexerEnv].push_back(QString($6) + QString(r));
281                // barrier should not get read partially
282                exclude <<= KDevPG::GNFA::anyChar();
283                *$1 <<= *$4;
284                *$1 ^= exclude;
285                QString s = "Iterator::plain() -= " + QString::number(minLen) + "; " + QString($6) + QString(r);
286                KDevPG::globalSystem.lexerEnvs[lexerEnv].push_back($1);
287                KDevPG::globalSystem.lexerActions[lexerEnv].push_back(s);
288              }
289            } lexer_declaration_rest
290    | T_FAIL T_CODE
291            {
292              KDevPG::globalSystem.lexerActions[lexerEnv][0] = QString($2);
293            } lexer_declaration_rest
294    | T_ENTER_RULE_SET T_CODE
295            {
296              KDevPG::globalSystem.enteringCode[lexerEnv] = QString($2);
297            } lexer_declaration_rest
298    | T_LEAVE_RULE_SET T_CODE
299            {
300              KDevPG::globalSystem.leavingCode[lexerEnv] = QString($2);
301            } lexer_declaration_rest
302    | /* empty */
303    ;
304
305opt_lexer_action
306    : T_TERMINAL {
307        r = "\nlxRETURN(" + QString($1) + ")\n";
308      }
309    | T_CONTINUE {
310        r = "\nlxCONTINUE;\n";
311      }
312    | /* empty */ { r = "\nlxSKIP\n"; }
313    ;
314
315regexp
316    : regexp '|' regexp1    { $$ = new KDevPG::GNFA(*$1 |= *$3); delete $1; delete $3; }
317    | regexp1               { $$ = $1; }
318    ;
319
320regexp1
321    : regexp1 '&' regexp2   { $$ = new KDevPG::GNFA(*$1 &= *$3); delete $1; delete $3; }
322    | regexp2               { $$ = $1; }
323    ;
324
325regexp2
326    : regexp3 '^' regexp2   { $$ = new KDevPG::GNFA(*$1 ^= *$3); delete $1; delete $3; }
327    | regexp3               { $$ = $1; }
328    ;
329
330regexp3
331    : '~' regexp3           { $$ = new KDevPG::GNFA($2->negate()); delete $2; }
332    | '?' regexp3           { $$ = new KDevPG::GNFA(*$2 |= KDevPG::GNFA::emptyWord()); delete $2; }
333    | regexp4               { $$ = $1; }
334    ;
335
336regexp4
337    : regexp4 regexp5       { $$ = new KDevPG::GNFA(*$1 <<= *$2); delete $1; delete $2; }
338    | regexp5               { $$ = $1; }
339    ;
340
341regexp5
342    : regexp5 '@' regexp6   { $$ = new KDevPG::GNFA(*$1); KDevPG::GNFA *tmp = new KDevPG::GNFA(*$3 <<= *$1); **tmp; *$$ <<= *tmp; delete tmp; delete $1; delete $3; }
343    | regexp6               { $$ = $1; }
344    ;
345
346regexp6
347    : regexp6 '*'           { $$ = new KDevPG::GNFA(**$1); delete $1; }
348    | regexp6 '+'           { $$ = new KDevPG::GNFA(*$1); **$$; *$$ <<= *$1; delete $1; }
349    | regexp7               { $$ = $1; }
350    ;
351
352regexp7
353    : '(' regexp ')'        { $$ = new KDevPG::GNFA(*$2); delete $2; }
354    | '[' aregexp ']'       { $$ = $2; }
355    | '.'                   { $$ = new KDevPG::GNFA(KDevPG::GNFA::anyChar()); }
356    | T_STRING              { $$ = new KDevPG::GNFA(KDevPG::GNFA::word(KDevPG::unescaped(QByteArray($1)))); }
357    | T_UNQUOTED_STRING     { $$ = new KDevPG::GNFA(KDevPG::GNFA::word(KDevPG::unescaped(QByteArray($1)))); }
358    | T_NAMED_REGEXP        {
359                              if(!KDevPG::globalSystem.regexpById.contains($1))
360                              {
361                                KDevPG::checkOut << "** ERROR: no named regexp " << $1 << endl;
362                                exit(-1);
363                              }
364                              KDevPG::GNFA *regexp = KDevPG::globalSystem.regexpById[$1];
365                              if(!KDevPG::globalSystem.dfaForNfa.contains(regexp))
366                              {
367                                KDevPG::globalSystem.dfaForNfa[regexp] = new KDevPG::GDFA(regexp->dfa());
368                                KDevPG::globalSystem.dfaForNfa[regexp]->minimize();
369                                *regexp = KDevPG::globalSystem.dfaForNfa[regexp]->nfa();
370                              }
371                              $$ = new KDevPG::GNFA(*regexp);
372                            }
373    | /* empty */           { $$ = new KDevPG::GNFA(KDevPG::GNFA::emptyWord()); }
374    ;
375
376aregexp
377    : aregexp '|' aregexp1  { $$ = new KDevPG::GNFA(*$1 |= *$3); delete $1; delete $3; }
378    | aregexp1              { $$ = $1; }
379    ;
380
381aregexp1
382    : aregexp1 '&' aregexp2 { $$ = new KDevPG::GNFA(*$1 &= *$3); delete $1; delete $3; }
383    | aregexp2              { $$ = $1; }
384    ;
385
386aregexp2
387    : aregexp3 '^' aregexp2 { $$ = new KDevPG::GNFA(*$1 ^= *$3); delete $1; delete $3; }
388    | aregexp3              { $$ = $1; }
389    ;
390
391aregexp3
392    : '~' aregexp3          { $$ = new KDevPG::GNFA($2->negate()); delete $2; }
393    | '?' aregexp3          { $$ = new KDevPG::GNFA(*$2 |= KDevPG::GNFA::emptyWord()); delete $2; }
394    | aregexp4              { $$ = $1; }
395    ;
396
397aregexp4
398    : aregexp4 aregexp5     { $$ = new KDevPG::GNFA(*$1 |= *$2); delete $1; delete $2; }
399    | aregexp5
400    ;
401
402aregexp5
403    : aregexp5 '@' aregexp6 { $$ = new KDevPG::GNFA(*$1); KDevPG::GNFA *tmp = new KDevPG::GNFA(*$3 <<= *$1); **tmp; *$$ <<= *tmp; delete tmp; delete $1; delete $3; }
404    | aregexp6              { $$ = $1; }
405    ;
406
407aregexp6
408    : aregexp6 '*'          { $$ = new KDevPG::GNFA(**$1); delete $1; }
409    | aregexp6 '+'          { $$ = new KDevPG::GNFA(*$1); **$$; *$$ <<= *$1; delete $1; }
410    | aregexp7              { $$ = $1; }
411    ;
412
413aregexp7
414    : '(' regexp ')'        { $$ = new KDevPG::GNFA(*$2); delete $2; }
415    | '[' aregexp ']'       { $$ = $2; }
416    | '.'                   { $$ = new KDevPG::GNFA(KDevPG::GNFA::anyChar()); }
417    | T_STRING              { $$ = new KDevPG::GNFA(KDevPG::GNFA::word(KDevPG::unescaped(QByteArray($1)))); }
418    | T_RANGE               {
419      quint32 begin, end;
420      QString str = KDevPG::unescaped(QByteArray($1));
421      assert(str.size() >= 3 && str.size() <= 5);
422      if(str[1] == '-')
423      {
424        begin = str[0].unicode();
425        if(str.size() == 3)
426          end = str[2].unicode();
427        else
428          end = QChar::surrogateToUcs4(str[2], str[3]);
429      }
430      else
431      {
432        begin = QChar::surrogateToUcs4(str[0], str[1]);
433        assert(str[2] == '-');
434        if(str.size() == 4)
435          end = str[3].unicode();
436        else
437          end = QChar::surrogateToUcs4(str[3], str[4]);
438      }
439      $$ = new KDevPG::GNFA(KDevPG::GNFA::range(begin, end+1));
440    }
441    | T_UNQUOTED_STRING     { $$ = new KDevPG::GNFA(KDevPG::GNFA::collection(KDevPG::unescaped(QByteArray($1)))); }
442    | T_NAMED_REGEXP        {
443                              if(!KDevPG::globalSystem.regexpById.contains($1))
444                              {
445                                KDevPG::checkOut << "** ERROR: no named regexp " << $1 << endl;
446                                exit(-1);
447                              }
448                              KDevPG::GNFA *regexp = KDevPG::globalSystem.regexpById[$1];
449                              if(!KDevPG::globalSystem.dfaForNfa.contains(regexp))
450                              {
451                                KDevPG::globalSystem.dfaForNfa[regexp] = new KDevPG::GDFA(regexp->dfa());
452                                KDevPG::globalSystem.dfaForNfa[regexp]->minimize();
453                                *regexp = KDevPG::globalSystem.dfaForNfa[regexp]->nfa();
454                              }
455                              $$ = new KDevPG::GNFA(*regexp);
456                            }
457    | /* empty */           { $$ = new KDevPG::GNFA(KDevPG::GNFA::emptyWord()); }
458    ;
459
460
461member_declaration_rest
462    : '(' T_PUBLIC T_DECLARATION ')' T_CODE
463        { $$ = KDevPG::member(KDevPG::Settings::MemberItem::PublicDeclaration, $5);    }
464    | '(' T_PROTECTED T_DECLARATION ')' T_CODE
465        { $$ = KDevPG::member(KDevPG::Settings::MemberItem::ProtectedDeclaration, $5); }
466    | '(' T_PRIVATE T_DECLARATION ')' T_CODE
467        { $$ = KDevPG::member(KDevPG::Settings::MemberItem::PrivateDeclaration, $5);   }
468    | '(' T_CONSTRUCTOR ')' T_CODE
469        { $$ = KDevPG::member(KDevPG::Settings::MemberItem::ConstructorCode, $4);      }
470    | '(' T_DESTRUCTOR ')' T_CODE
471        { $$ = KDevPG::member(KDevPG::Settings::MemberItem::DestructorCode, $4);       }
472    ;
473
474declared_tokens
475    : T_TERMINAL                        { KDevPG::globalSystem.pushTerminal($1,$1); }
476    | T_TERMINAL '(' T_STRING ')'       { KDevPG::globalSystem.pushTerminal($1,$3); }
477    | declared_tokens ',' T_TERMINAL    { KDevPG::globalSystem.pushTerminal($3,$3); }
478    | declared_tokens ',' T_TERMINAL '(' T_STRING ')'
479                                        { KDevPG::globalSystem.pushTerminal($3,$5); }
480    ;
481
482rules
483    : /* empty */
484    | rules item ';'                    { KDevPG::globalSystem.pushRule($2); }
485    ;
486
487primary_item
488    : '0'                               { $$ = KDevPG::globalSystem.zero(); }
489    | '(' option_item ')'               { $$ = $2; }
490    | try_item                    { $$ = $1; }
491    | primary_atom                      { $$ = $1; }
492    | T_INLINE T_IDENTIFIER              { $$ = KDevPG::inlinedNonTerminal(KDevPG::globalSystem.pushSymbol($2)); }
493    | name scope primary_atom           { $$ = KDevPG::annotation($1, $3, false, $2); }
494    | '#' name scope primary_atom       { $$ = KDevPG::annotation($2, $4, true, $3);  }
495    ;
496
497primary_atom
498    : T_IDENTIFIER rule_arguments_opt   { $$ = KDevPG::nonTerminal(KDevPG::globalSystem.pushSymbol($1), $2); }
499    | T_TERMINAL                        { $$ = KDevPG::globalSystem.terminal($1); }
500    ;
501
502try_item
503    : T_TRY_RECOVER '(' option_item ')'
504        {
505          KDevPG::globalSystem.needStateManagement = true;
506          $$ = KDevPG::tryCatch($3, 0);
507        }
508    | T_TRY_ROLLBACK '(' option_item ')' T_CATCH '(' option_item ')'
509        {
510          KDevPG::globalSystem.needStateManagement = true;
511          $$ = KDevPG::tryCatch($3, $7);
512        }
513
514rule_arguments_opt
515    : /* empty */                       { $$ = const_cast<char*>(""); }
516    | T_RULE_ARGUMENTS                  { $$ = $1; }
517    ;
518
519name
520    : T_IDENTIFIER                      { $$ = $1; }
521/*    | T_IDENTIFIER '.' T_IDENTIFIER
522        {
523          $$ = $3;
524          fprintf(stderr, "** WARNING support for scoped name"
525                          " ``%s.%s'' not implemented\n", $1, $3);
526        }*/
527    ;
528
529scope
530    : '=' { $$ = KDevPG::Model::VariableDeclarationItem::StorageAstMember; }
531    | ':' { $$ = KDevPG::Model::VariableDeclarationItem::StorageTemporary;  }
532    ;
533
534unary_item
535    : primary_item '+'                  { $$ = KDevPG::plus($1); }
536    | primary_item '*'                  { $$ = KDevPG::star($1); }
537    | primary_item                      { $$ = $1; }
538    | '?' primary_item                   { $$ = KDevPG::alternative($2, KDevPG::globalSystem.zero()); }
539    ;
540
541postfix_item
542    : unary_item                        { $$ = $1; }
543    | postfix_item '@' primary_item
544        {
545          KDevPG::CloneTree cl;
546          $$ = KDevPG::cons($1, KDevPG::star(KDevPG::cons(cl.clone($3), cl.clone($1))));
547        }
548    | postfix_item T_CODE               { $$ = KDevPG::action($1, $2); }
549    | T_CODE                            { $$ = KDevPG::action(0, $1); }
550    ;
551
552item_sequence
553    : postfix_item                      { $$ = $1; }
554    | item_sequence postfix_item        { $$ = KDevPG::cons($1, $2); }
555    ;
556
557conditional_item
558    : item_sequence                     { $$ = $1; }
559    | '?' T_CODE item_sequence          { $$ = KDevPG::condition($2, $3); }
560    ;
561
562option_item
563    : conditional_item                  { $$ = $1; }
564    | option_item '|' conditional_item  { $$ = KDevPG::alternative($1, $3); }
565    ;
566
567item
568    : option_item T_ARROW T_IDENTIFIER T_CODE '[' variableDeclarations ']'
569        {
570          $$ = KDevPG::evolve($1, KDevPG::globalSystem.pushSymbol($3),
571                          (KDevPG::Model::VariableDeclarationItem*) $6, $4);
572        }
573    | option_item T_ARROW T_IDENTIFIER '[' variableDeclarations ']' code_opt
574        {
575          $$ = KDevPG::evolve($1, KDevPG::globalSystem.pushSymbol($3),
576                          (KDevPG::Model::VariableDeclarationItem*) $5, $7);
577        }
578    | option_item T_ARROW T_IDENTIFIER code_opt
579        { $$ = KDevPG::evolve($1, KDevPG::globalSystem.pushSymbol($3), 0, $4); }
580    | { if(KDevPG::globalSystem.generateAst == false)
581        {
582          qFatal("Operator-expression-parsing is not yet supported with --no-ast!");
583          exit(-1);
584        }
585        operatorNode = KDevPG::createNode<KDevPG::Model::OperatorItem>();
586      } operatorRule { KDevPG::globalSystem.needOperatorStack = true; $$ = $2; }
587    ;
588
589code_opt
590    : /* empty */                       { $$ = const_cast<char*>(""); }
591    | T_CODE                            { $$ = $1; }
592    ;
593
594
595operatorDeclarations
596    : operatorDeclaration operatorDeclarations
597    | /* empty */   { ; }
598    ;
599
600operatorRule
601    : T_LOPR primary_atom operatorDeclarations T_ROPR T_IDENTIFIER '[' variableDeclarations ']' code_opt
602            {
603              operatorNode->mBase = (KDevPG::Model::NonTerminalItem*)$2;
604              operatorNode->mName = $5;
605              if(!KDevPG::globalSystem.astBaseClasses.contains(operatorNode->mBase->mSymbol->mName))
606                KDevPG::globalSystem.astBaseClasses[operatorNode->mBase->mSymbol->mName] = KDevPG::capitalized(operatorNode->mName) + "Ast";
607              $$ = KDevPG::evolve(operatorNode, KDevPG::globalSystem.pushSymbol($5), (KDevPG::Model::VariableDeclarationItem*)$7, $9);
608            }
609    | T_LOPR primary_atom operatorDeclarations T_ROPR T_IDENTIFIER T_CODE '[' variableDeclarations ']'
610            {
611              operatorNode->mBase = (KDevPG::Model::NonTerminalItem*)$2;
612              operatorNode->mName = $5;
613              if(!KDevPG::globalSystem.astBaseClasses.contains(operatorNode->mBase->mSymbol->mName))
614                KDevPG::globalSystem.astBaseClasses[operatorNode->mBase->mSymbol->mName] = KDevPG::capitalized(operatorNode->mName) + "Ast";
615              $$ = KDevPG::evolve(operatorNode, KDevPG::globalSystem.pushSymbol($5), (KDevPG::Model::VariableDeclarationItem*)$8, $6);
616            }
617    | T_LOPR primary_atom operatorDeclarations T_ROPR T_IDENTIFIER code_opt
618            {
619              operatorNode->mBase = (KDevPG::Model::NonTerminalItem*)$2;
620              operatorNode->mName = $5;
621              if(!KDevPG::globalSystem.astBaseClasses.contains(operatorNode->mBase->mSymbol->mName))
622                KDevPG::globalSystem.astBaseClasses[operatorNode->mBase->mSymbol->mName] = KDevPG::capitalized(operatorNode->mName) + "Ast";
623              $$ = KDevPG::evolve(operatorNode, KDevPG::globalSystem.pushSymbol($5), 0, $6);
624            }
625    ;
626
627operatorDeclaration
628    : T_BIN operator priority assoc              { operatorNode->pushBin(*$2, $4, $3); free($2); }
629    | T_TERN operator operator priority assoc    { operatorNode->pushTern(*$2, *$3, $5, $4); free($2); free($3); }
630    | T_PRE operator priority                    { operatorNode->pushPre(*$2, $3); free($2); }
631    | T_POST operator priority                   { operatorNode->pushPost(*$2, "0", $3); free($2); free($3); }
632    | T_POST operator priority assoc             { operatorNode->pushPost(*$2, $4, $3); free($2); }
633    | T_PAREN operator operator                  { operatorNode->pushParen(*$2, *$3); free($2); free($3); }
634    ;
635
636priority
637    : '0'                          { $$ = (char*)"0"; }
638    | T_NUMBER                     { $$ = $1; }
639    | T_PRIORITY T_CODE            { $$ = $2; }
640    ;
641
642assoc
643    : T_LEFT_ASSOC                 { $$ = (char*)"1"; }
644    | T_RIGHT_ASSOC                { $$ = (char*)"0"; }
645    | T_IS_LEFT_ASSOC T_CODE       { uint yyleng = strlen($2);
646                                     char *tmp = (char*)calloc(yyleng+7, sizeof(char));
647                                     tmp[0] = '(';
648                                     strcpy(tmp+1, $2);
649                                     strcpy(tmp+yyleng+6-6+1, "?1:0)");
650                                     $$ = tmp;
651                                   }
652    | T_IS_RIGHT_ASSOC T_CODE      { uint yyleng = strlen($2);
653                                     char *tmp = (char*)calloc(yyleng+7, sizeof(char));
654                                     tmp[0] = '(';
655                                     strcpy(tmp+1, $2);
656                                     strcpy(tmp+yyleng+6-6+1, "?0:1)");
657                                     $$ = tmp;
658                                   }
659    ;
660
661operator
662    : '?' T_CODE T_TERMINAL T_CODE { $$ = KDevPG::makeOperator(KDevPG::globalSystem.terminal($3), $2, $4); }
663    | '?' T_CODE T_TERMINAL        { $$ = KDevPG::makeOperator(KDevPG::globalSystem.terminal($3), $2, ""); }
664    | T_TERMINAL T_CODE            { $$ = KDevPG::makeOperator(KDevPG::globalSystem.terminal($1), "", $2); }
665    | T_TERMINAL                   { $$ = KDevPG::makeOperator(KDevPG::globalSystem.terminal($1), "", ""); }
666    ;
667
668variableDeclarations
669    : variableDeclaration              { $$ = $1; }
670    | variableDeclarations variableDeclaration
671        {
672          KDevPG::Model::VariableDeclarationItem *last = (KDevPG::Model::VariableDeclarationItem*) $1;
673          while (last->mNext != 0) {
674            last = last->mNext;
675          }
676          last->mNext = (KDevPG::Model::VariableDeclarationItem*) $2;
677          $$ = $1;
678        }
679    ;
680
681variableDeclaration
682    : declarationType_opt storageType variableType T_IDENTIFIER ':' T_IDENTIFIER
683        { $$ = KDevPG::variableDeclaration($1, $2, $3, false, $4, $6); }
684    | declarationType_opt storageType T_TOKEN       T_IDENTIFIER ';'
685        { $$ = KDevPG::variableDeclaration($1, $2, KDevPG::Model::VariableDeclarationItem::TypeToken, false, $4, ""); }
686    | declarationType_opt storageType variableType '#' T_IDENTIFIER ':' T_IDENTIFIER
687        { $$ = KDevPG::variableDeclaration($1, $2, $3, true, $5, $7); }
688    | declarationType_opt storageType T_TOKEN       '#' T_IDENTIFIER ';'
689        { $$ = KDevPG::variableDeclaration($1, $2, KDevPG::Model::VariableDeclarationItem::TypeToken, true, $5, ""); }
690    ;
691
692declarationType_opt
693    : /* empty */       { $$ = KDevPG::Model::VariableDeclarationItem::DeclarationLocal;     }
694    | T_ARGUMENT        { $$ = KDevPG::Model::VariableDeclarationItem::DeclarationArgument;  }
695    ;
696
697storageType
698    : T_MEMBER          { $$ = KDevPG::Model::VariableDeclarationItem::StorageAstMember;    }
699    | T_TEMPORARY       { $$ = KDevPG::Model::VariableDeclarationItem::StorageTemporary;     }
700    ;
701
702variableType
703    : T_NODE            { $$ = KDevPG::Model::VariableDeclarationItem::TypeNode;             }
704    | T_VARIABLE        { $$ = KDevPG::Model::VariableDeclarationItem::TypeVariable;         }
705    ;
706
707%%
708