--------------------------------------------------------------------------------- Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).-- All rights reserved.-- Contact: Nokia Corporation (qt-info@nokia.com)---- This file is part of the QLALR project on Qt Labs.---- $QT_BEGIN_LICENSE:LGPL$-- No Commercial Usage-- This file contains pre-release code and may not be distributed.-- You may use this file in accordance with the terms and conditions-- contained in the Technology Preview License Agreement accompanying-- this package.---- GNU Lesser General Public License Usage-- Alternatively, this file may be used under the terms of the GNU Lesser-- General Public License version 2.1 as published by the Free Software-- Foundation and appearing in the file LICENSE.LGPL included in the-- packaging of this file. Please review the following information to-- ensure the GNU Lesser General Public License version 2.1 requirements-- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.---- In addition, as a special exception, Nokia gives you certain additional-- rights. These rights are described in the Nokia Qt LGPL Exception-- version 1.1, included in the file LGPL_EXCEPTION.txt in this package.---- If you have questions regarding the use of this file, please contact-- Nokia at qt-info@nokia.com.------------------ $QT_END_LICENSE$-------------------------------------------------------------------------------%parser grammar%decl recognizer.h%impl recognizer.cpp%token ID "identifier"%token STRING_LITERAL "string literal"%token DECL_FILE "%decl"%token EXPECT "%expect"%token EXPECT_RR "%expect-lr"%token IMPL_FILE "%impl"%token LEFT "%left"%token MERGED_OUTPUT "%merged_output"%token NONASSOC "%nonassoc"%token PARSER "%parser"%token PREC "%prec"%token RIGHT "%right"%token START "%start"%token TOKEN "%token"%token TOKEN_PREFIX "%token_prefix"%token COLON ":"%token OR "|"%token SEMICOLON ";"%token DECL%token IMPL%token ERROR%start Specification/:/******************************************************************************** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).** All rights reserved.** Contact: Nokia Corporation (qt-info@nokia.com)**** This file is part of the QLALR project on Qt Labs.**** $QT_BEGIN_LICENSE:LGPL$** No Commercial Usage** This file contains pre-release code and may not be distributed.** You may use this file in accordance with the terms and conditions** contained in the Technology Preview License Agreement accompanying** this package.**** GNU Lesser General Public License Usage** Alternatively, this file may be used under the terms of the GNU Lesser** General Public License version 2.1 as published by the Free Software** Foundation and appearing in the file LICENSE.LGPL included in the** packaging of this file. Please review the following information to** ensure the GNU Lesser General Public License version 2.1 requirements** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.**** In addition, as a special exception, Nokia gives you certain additional** rights. These rights are described in the Nokia Qt LGPL Exception** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.**** If you have questions regarding the use of this file, please contact** Nokia at qt-info@nokia.com.****************** $QT_END_LICENSE$******************************************************************************/#include <QtCore/QtDebug>#include <QtCore/QString>#include <QtCore/QFile>#include <QtCore/QTextStream>#include "$header"#include "lalr.h"#include <cstdlib>class Recognizer: protected $table{public: Recognizer (Grammar *grammar, bool no_lines); ~Recognizer(); bool parse (const QString &input_file = QString ()); inline QString decls () const { return _M_decls; } inline QString impls () const { return _M_impls; }protected: inline void reallocateStack (); inline QString &sym (int index) { return sym_stack [tos + index - 1]; }protected: // scanner int nextToken(); inline void inp () { if (_M_currentChar != _M_lastChar) { ch = *_M_currentChar++; if (ch == QLatin1Char('\n')) ++_M_line; } else ch = QChar(); } QString expand (const QString &text) const;protected: // recognizer int tos; int stack_size; QVector<QString> sym_stack; int *state_stack; QString _M_contents; QString::const_iterator _M_firstChar; QString::const_iterator _M_lastChar; QString::const_iterator _M_currentChar; // scanner QChar ch; int _M_line; int _M_action_line; Grammar *_M_grammar; RulePointer _M_current_rule; QString _M_input_file; QString _M_decls; QString _M_impls; QString _M_current_value; bool _M_no_lines;};://./******************************************************************************** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).** All rights reserved.** Contact: Nokia Corporation (qt-info@nokia.com)**** This file is part of the QLALR project on Qt Labs.**** $QT_BEGIN_LICENSE:LGPL$** No Commercial Usage** This file contains pre-release code and may not be distributed.** You may use this file in accordance with the terms and conditions** contained in the Technology Preview License Agreement accompanying** this package.**** GNU Lesser General Public License Usage** Alternatively, this file may be used under the terms of the GNU Lesser** General Public License version 2.1 as published by the Free Software** Foundation and appearing in the file LICENSE.LGPL included in the** packaging of this file. Please review the following information to** ensure the GNU Lesser General Public License version 2.1 requirements** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.**** In addition, as a special exception, Nokia gives you certain additional** rights. These rights are described in the Nokia Qt LGPL Exception** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.**** If you have questions regarding the use of this file, please contact** Nokia at qt-info@nokia.com.****************** $QT_END_LICENSE$******************************************************************************/#include "recognizer.h"#include <cstdlib>#include <cstring>#include <cctype>Recognizer::Recognizer (Grammar *grammar, bool no_lines): tos(0), stack_size(0), state_stack(0), _M_line(1), _M_action_line(0), _M_grammar(grammar), _M_no_lines(no_lines){}Recognizer::~Recognizer(){ if (stack_size) ::qFree(state_stack);}inline void Recognizer::reallocateStack(){ if (! stack_size) stack_size = 128; else stack_size <<= 1; sym_stack.resize (stack_size); if (! state_stack) state_stack = reinterpret_cast<int*> (::qMalloc(stack_size * sizeof(int))); else state_stack = reinterpret_cast<int*> (::qRealloc(state_stack, stack_size * sizeof(int)));}int Recognizer::nextToken(){ QString text; Lagain: while (ch.isSpace ()) inp (); if (ch.isNull ()) return EOF_SYMBOL; int token = ch.unicode (); if (token == '"') { inp(); // skip " text.clear (); while (! ch.isNull () && ch != QLatin1Char ('"')) { if (ch == QLatin1Char ('\\')) { text += ch; inp(); } text += ch; inp (); } if (ch == QLatin1Char ('"')) inp (); else qerr << _M_input_file << ":" << _M_line << ": Warning. Expected `\"'" << endl; _M_current_value = text; return (token = STRING_LITERAL); } else if (ch.isLetterOrNumber () || ch == QLatin1Char ('_')) { text.clear (); do { text += ch; inp (); } while (ch.isLetterOrNumber () || ch == QLatin1Char ('_') || ch == QLatin1Char ('.')); _M_current_value = text; return (token = ID); } else if (token == '%') { text.clear (); do { inp (); } while (ch.isSpace ()); do { text += ch; inp (); } while (ch.isLetterOrNumber () || ch == QLatin1Char ('_') || ch == QLatin1Char ('-')); if (text == QLatin1String("token_prefix")) return (token = TOKEN_PREFIX); else if (text == QLatin1String("merged_output")) return (token = MERGED_OUTPUT); else if (text == QLatin1String("token")) return (token = TOKEN); else if (text == QLatin1String("start")) return (token = START); else if (text == QLatin1String("parser")) return (token = PARSER); else if (text == QLatin1String("decl")) return (token = DECL_FILE); else if (text == QLatin1String("impl")) return (token = IMPL_FILE); else if (text == QLatin1String("expect")) return (token = EXPECT); else if (text == QLatin1String("expect-rr")) return (token = EXPECT_RR); else if (text == QLatin1String("left")) return (token = LEFT); else if (text == QLatin1String("right")) return (token = RIGHT); else if (text == QLatin1String("nonassoc")) return (token = NONASSOC); else if (text == QLatin1String("prec")) return (token = PREC); else { qerr << _M_input_file << ":" << _M_line << ": Unknown keyword `" << text << "'" << endl; exit (EXIT_FAILURE); return (token = ERROR); } } inp (); if (token == '-' && ch == QLatin1Char ('-')) { do { inp (); } while (! ch.isNull () && ch != QLatin1Char ('\n')); goto Lagain; } else if (token == ':' && ch == QLatin1Char (':')) { inp (); if (ch != QLatin1Char ('=')) return (token = ERROR); inp (); return (token = COLON); } else if (token == '/' && ch == QLatin1Char (':')) { _M_action_line = _M_line; text.clear (); if (! _M_no_lines) text += QLatin1String ("\n#line ") + QString::number (_M_action_line) + " \"" + _M_input_file + "\"\n"; inp (); // skip ':' forever { while (! ch.isNull ()) { token = ch.unicode (); inp (); if (token == ':' && ch == QLatin1Char ('/')) break; text += QLatin1Char (token); } if (ch != QLatin1Char ('/')) return (token = ERROR); inp (); if (ch.isNull () || ch.isSpace ()) { _M_current_value = text; return (token = DECL); } else text += QLatin1String (":/"); } } else if (token == '/' && ch == QLatin1Char ('.')) { _M_action_line = _M_line; text.clear (); if (! _M_no_lines) text += QLatin1String ("\n#line ") + QString::number (_M_action_line) + " \"" + _M_input_file + "\"\n"; inp (); // skip ':' forever { while (! ch.isNull ()) { token = ch.unicode (); inp (); if (token == '.' && ch == QLatin1Char ('/')) break; text += QLatin1Char (token); } if (ch != QLatin1Char ('/')) return (token = ERROR); inp (); if (ch.isNull () || ch.isSpace ()) { _M_current_value = text; return (token = IMPL); } else text += QLatin1String ("./"); } } switch (token) { case ':': return (token = COLON); case ';': return (token = SEMICOLON); case '|': return (token = OR); default: break; } return token;}bool Recognizer::parse (const QString &input_file){ _M_input_file = input_file; QFile file(_M_input_file); if (! file.open(QFile::ReadOnly)) { qerr << "qlalr: no input file\n"; return false; } QString _M_contents = QTextStream(&file).readAll(); _M_firstChar = _M_contents.constBegin(); _M_lastChar = _M_contents.constEnd(); _M_currentChar = _M_firstChar; _M_line = 1; int yytoken = -1; inp (); reallocateStack(); _M_current_rule = _M_grammar->rules.end (); _M_decls.clear (); _M_impls.clear (); tos = 0; state_stack[++tos] = 0; while (true) { if (yytoken == -1 && - TERMINAL_COUNT != action_index [state_stack [tos]]) yytoken = nextToken(); int act = t_action (state_stack [tos], yytoken); if (act == ACCEPT_STATE) return true; else if (act > 0) { if (++tos == stack_size) reallocateStack(); sym_stack [tos] = _M_current_value; state_stack [tos] = act; yytoken = -1; } else if (act < 0) { int r = - act - 1; tos -= rhs [r]; act = state_stack [tos++]; switch (r) {./----------------------------------------------------------- SPECSSpecification ::= Options Tokens Start Rules ;Options ::= Empty ;Options ::= Options Option ;StartHeader ::= START ID ;/.case $rule_number: { Name name = _M_grammar->intern (sym(2)); _M_grammar->start = name; _M_grammar->non_terminals.insert (name);} break;./Start ::= StartHeader UserActionOpt ;----------------------------------------------------------- OPTIONSOption ::= PARSER ID ;/.case $rule_number: { _M_grammar->table_name = sym(2);} break;./Option ::= MERGED_OUTPUT ID ;/.case $rule_number: { _M_grammar->merged_output = sym(2);} break;./Option ::= DECL_FILE ID ;/.case $rule_number: { _M_grammar->decl_file_name = sym(2);} break;./Option ::= IMPL_FILE ID ;/.case $rule_number: { _M_grammar->impl_file_name = sym(2);} break;./Option ::= EXPECT ID ;/.case $rule_number: { _M_grammar->expected_shift_reduce = sym(2).toInt();} break;./Option ::= EXPECT_RR ID ;/.case $rule_number: { _M_grammar->expected_reduce_reduce = sym(2).toInt();} break;./Option ::= TOKEN_PREFIX ID ;/.case $rule_number: { _M_grammar->token_prefix = sym(2);} break;./----------------------------------------------------------- TOKENSTokens ::= Empty ;Tokens ::= Tokens Token ;Token ::= TOKEN TerminalList ;TerminalList ::= Terminal ;TerminalList ::= TerminalList Terminal ;Terminal ::= ID Empty ;/.case $rule_number:./Terminal ::= ID STRING_LITERAL ;/.case $rule_number: { Name name = _M_grammar->intern (sym(1)); _M_grammar->terminals.insert (name); _M_grammar->spells.insert (name, sym(2));} break;./PrecHeader: LEFT ;/.case $rule_number: { _M_grammar->current_assoc = Grammar::Left; ++_M_grammar->current_prec;} break;./PrecHeader: RIGHT ;/.case $rule_number: { _M_grammar->current_assoc = Grammar::Right; ++_M_grammar->current_prec;} break;./PrecHeader: NONASSOC ;/.case $rule_number: { _M_grammar->current_assoc = Grammar::NonAssoc; ++_M_grammar->current_prec;} break;./Token ::= PrecHeader TokenList ;TokenList ::= TokenId ;TokenList ::= TokenList TokenId ;TokenId ::= ID ;/.case $rule_number: { Name name = _M_grammar->intern (sym(1)); _M_grammar->terminals.insert (name); Grammar::TokenInfo info; info.prec = _M_grammar->current_prec; info.assoc = _M_grammar->current_assoc; _M_grammar->token_info.insert (name, info);} break;./----------------------------------------------------------- CodeCode ::= DECL ;/.case $rule_number: { _M_decls += expand (sym(1));} break;./Code ::= IMPL ;/.case $rule_number: { _M_impls += expand (sym(1));} break;./UserAction ::= Code ;UserAction ::= UserAction Code ;UserActionOpt ::= ;UserActionOpt ::= UserAction ;----------------------------------------------------------- RULESRules ::= Empty ;Rules ::= Rules Rule ;RuleHeader ::= ID COLON ;/.case $rule_number: { _M_current_rule = _M_grammar->rules.insert (_M_grammar->rules.end (), Rule ()); _M_current_rule->lhs = _M_grammar->intern (sym(1)); _M_grammar->declared_lhs.insert (_M_current_rule->lhs); if (_M_grammar->terminals.find (_M_current_rule->lhs) != _M_grammar->terminals.end ()) { qerr << _M_input_file << ":" << _M_line << ": Invalid non terminal `" << *_M_current_rule->lhs << "'" << endl; return false; } _M_grammar->non_terminals.insert (_M_current_rule->lhs);} break;./Rule ::= RuleHeader RuleDefinition SEMICOLON UserActionOpt ;RuleDefinition ::= Symbols PrecOpt UserActionOpt ;RuleDefinition ::= RuleDefinition NewRule OR Symbols PrecOpt UserActionOpt ;NewRule ::= ;/.case $rule_number: { Name lhs = _M_current_rule->lhs; _M_current_rule = _M_grammar->rules.insert (_M_grammar->rules.end (), Rule ()); _M_current_rule->lhs = lhs; _M_grammar->declared_lhs.insert (_M_current_rule->lhs); if (_M_grammar->terminals.find (_M_current_rule->lhs) != _M_grammar->terminals.end ()) { qerr << _M_input_file << ":" << _M_line << ": Invalid non terminal `" << *_M_current_rule->lhs << "'" << endl; return false; } _M_grammar->non_terminals.insert (_M_current_rule->lhs);} break;./PrecOpt ::= ;/.case $rule_number: { _M_current_rule->prec = _M_grammar->names.end (); for (NameList::iterator it = _M_current_rule->rhs.begin (); it != _M_current_rule->rhs.end (); ++it) { if (! _M_grammar->isTerminal (*it)) continue; _M_current_rule->prec = *it; }} break;./PrecOpt ::= PREC ID ;/.case $rule_number: { Name tok = _M_grammar->intern (sym(2)); if (! _M_grammar->isTerminal (tok)) { qerr << _M_input_file << ":" << _M_line << ": `" << *tok << " is not a terminal symbol" << endl; _M_current_rule->prec = _M_grammar->names.end (); } else _M_current_rule->prec = tok;} break;./----------------------------------------------------------- SYMBOLSSymbols ::= Empty ;Symbols ::= Symbols ID ;/.case $rule_number: { Name name = _M_grammar->intern (sym(2)); if (_M_grammar->terminals.find (name) == _M_grammar->terminals.end ()) _M_grammar->non_terminals.insert (name); _M_current_rule->rhs.push_back (name);} break;./----------------------------------------------------------- HELPERSEmpty ::= ;/.case $rule_number: { sym(1) = QString();} break;./----------------------------------------------------------- END/. } // switch state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT); } else { break; } } qerr << _M_input_file << ":" << _M_line << ": Syntax error" << endl; return false;}./