forked from qt-creator/qt-creator
3806 lines
110 KiB
C++
3806 lines
110 KiB
C++
/***************************************************************************
|
|
**
|
|
** This file is part of Qt Creator
|
|
**
|
|
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
**
|
|
** Contact: Qt Software Information (qt-info@nokia.com)
|
|
**
|
|
**
|
|
** Non-Open Source Usage
|
|
**
|
|
** Licensees may use this file in accordance with the Qt Beta Version
|
|
** License Agreement, Agreement version 2.2 provided with the Software or,
|
|
** alternatively, in accordance with the terms contained in a written
|
|
** agreement between you and Nokia.
|
|
**
|
|
** GNU General Public License Usage
|
|
**
|
|
** Alternatively, this file may be used under the terms of the GNU General
|
|
** Public License versions 2.0 or 3.0 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL included in the packaging
|
|
** of this file. Please review the following information to ensure GNU
|
|
** General Public Licensing requirements will be met:
|
|
**
|
|
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
|
|
** http://www.gnu.org/copyleft/gpl.html.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt GPL Exception
|
|
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
|
|
**
|
|
***************************************************************************/
|
|
// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
#include "Parser.h"
|
|
#include "Token.h"
|
|
#include "Lexer.h"
|
|
#include "Control.h"
|
|
#include "AST.h"
|
|
#include "Literals.h"
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
|
|
CPLUSPLUS_BEGIN_NAMESPACE
|
|
|
|
Parser::Parser(TranslationUnit *unit)
|
|
: _translationUnit(unit),
|
|
_control(_translationUnit->control()),
|
|
_pool(_translationUnit->memoryPool()),
|
|
_tokenIndex(1),
|
|
_templateArguments(0),
|
|
_qtMocRunEnabled(false),
|
|
_objCEnabled(false),
|
|
_inFunctionBody(false),
|
|
_inObjCImplementationContext(false)
|
|
{ }
|
|
|
|
Parser::~Parser()
|
|
{ }
|
|
|
|
bool Parser::qtMocRunEnabled() const
|
|
{ return _qtMocRunEnabled; }
|
|
|
|
void Parser::setQtMocRunEnabled(bool onoff)
|
|
{ _qtMocRunEnabled = onoff; }
|
|
|
|
bool Parser::objCEnabled() const
|
|
{ return _objCEnabled; }
|
|
|
|
void Parser::setObjCEnabled(bool onoff)
|
|
{ _objCEnabled = onoff; }
|
|
|
|
bool Parser::switchTemplateArguments(bool templateArguments)
|
|
{
|
|
bool previousTemplateArguments = _templateArguments;
|
|
_templateArguments = templateArguments;
|
|
return previousTemplateArguments;
|
|
}
|
|
|
|
bool Parser::blockErrors(bool block)
|
|
{ return _translationUnit->blockErrors(block); }
|
|
|
|
bool Parser::skipUntil(int token)
|
|
{
|
|
while (int tk = LA()) {
|
|
if (tk == token)
|
|
return true;
|
|
|
|
consumeToken();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::skipUntilDeclaration()
|
|
{
|
|
while (int tk = LA()) {
|
|
switch (tk) {
|
|
case T_SEMICOLON:
|
|
case T_TILDE:
|
|
case T_COLON_COLON:
|
|
case T_IDENTIFIER:
|
|
case T_OPERATOR:
|
|
case T_CHAR:
|
|
case T_WCHAR_T:
|
|
case T_BOOL:
|
|
case T_SHORT:
|
|
case T_INT:
|
|
case T_LONG:
|
|
case T_SIGNED:
|
|
case T_UNSIGNED:
|
|
case T_FLOAT:
|
|
case T_DOUBLE:
|
|
case T_VOID:
|
|
case T_EXTERN:
|
|
case T_NAMESPACE:
|
|
case T_USING:
|
|
case T_TYPEDEF:
|
|
case T_ASM:
|
|
case T_TEMPLATE:
|
|
case T_EXPORT:
|
|
case T_CONST:
|
|
case T_VOLATILE:
|
|
case T_PUBLIC:
|
|
case T_PROTECTED:
|
|
case T_PRIVATE:
|
|
return true;
|
|
|
|
default:
|
|
consumeToken();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::skipUntilStatement()
|
|
{
|
|
while (int tk = LA()) {
|
|
switch (tk) {
|
|
case T_SEMICOLON:
|
|
case T_LBRACE:
|
|
case T_RBRACE:
|
|
case T_CONST:
|
|
case T_VOLATILE:
|
|
case T_IDENTIFIER:
|
|
case T_CASE:
|
|
case T_DEFAULT:
|
|
case T_IF:
|
|
case T_SWITCH:
|
|
case T_WHILE:
|
|
case T_DO:
|
|
case T_FOR:
|
|
case T_BREAK:
|
|
case T_CONTINUE:
|
|
case T_RETURN:
|
|
case T_GOTO:
|
|
case T_TRY:
|
|
case T_CATCH:
|
|
case T_THROW:
|
|
case T_CHAR:
|
|
case T_WCHAR_T:
|
|
case T_BOOL:
|
|
case T_SHORT:
|
|
case T_INT:
|
|
case T_LONG:
|
|
case T_SIGNED:
|
|
case T_UNSIGNED:
|
|
case T_FLOAT:
|
|
case T_DOUBLE:
|
|
case T_VOID:
|
|
case T_CLASS:
|
|
case T_STRUCT:
|
|
case T_UNION:
|
|
case T_ENUM:
|
|
case T_COLON_COLON:
|
|
case T_TEMPLATE:
|
|
case T_USING:
|
|
return true;
|
|
|
|
default:
|
|
consumeToken();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::skip(int l, int r)
|
|
{
|
|
int count = 0;
|
|
|
|
while (int tk = LA()) {
|
|
if (tk == l)
|
|
++count;
|
|
else if (tk == r)
|
|
--count;
|
|
else if (l != T_LBRACE && (tk == T_LBRACE ||
|
|
tk == T_RBRACE ||
|
|
tk == T_SEMICOLON))
|
|
return false;
|
|
|
|
if (count == 0)
|
|
return true;
|
|
|
|
consumeToken();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Parser::match(int kind, unsigned *token)
|
|
{
|
|
if (LA() == kind)
|
|
*token = consumeToken();
|
|
else {
|
|
*token = 0;
|
|
_translationUnit->error(_tokenIndex, "expected token `%s' got `%s'",
|
|
Token::name(kind), tok().spell());
|
|
}
|
|
}
|
|
|
|
bool Parser::parseClassOrNamespaceName(NameAST *&node)
|
|
{
|
|
if (LA() == T_IDENTIFIER) {
|
|
unsigned identifier_token = cursor();
|
|
|
|
if (LA(2) == T_LESS && parseTemplateId(node) && LA() == T_COLON_COLON)
|
|
return true;
|
|
|
|
rewind(identifier_token);
|
|
|
|
if (LA(2) == T_COLON_COLON) {
|
|
SimpleNameAST *ast = new (_pool) SimpleNameAST;
|
|
ast->identifier_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
} else if (LA() == T_TEMPLATE) {
|
|
unsigned template_token = consumeToken();
|
|
if (parseTemplateId(node))
|
|
return true;
|
|
rewind(template_token);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTemplateId(NameAST *&node)
|
|
{
|
|
if (LA() == T_IDENTIFIER && LA(2) == T_LESS) {
|
|
TemplateIdAST *ast = new (_pool) TemplateIdAST;
|
|
ast->identifier_token = consumeToken();
|
|
ast->less_token = consumeToken();
|
|
if (LA() == T_GREATER || parseTemplateArgumentList(
|
|
ast->template_arguments)) {
|
|
if (LA() == T_GREATER) {
|
|
ast->greater_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseNestedNameSpecifier(NestedNameSpecifierAST *&node,
|
|
bool /*acceptTemplateId*/)
|
|
{
|
|
NestedNameSpecifierAST **nested_name_specifier = &node;
|
|
NameAST *class_or_namespace_name = 0;
|
|
if (parseClassOrNamespaceName(class_or_namespace_name) &&
|
|
LA() == T_COLON_COLON) {
|
|
unsigned scope_token = consumeToken();
|
|
*nested_name_specifier = new (_pool) NestedNameSpecifierAST;
|
|
(*nested_name_specifier)->class_or_namespace_name
|
|
= class_or_namespace_name;
|
|
(*nested_name_specifier)->scope_token = scope_token;
|
|
|
|
nested_name_specifier = &(*nested_name_specifier)->next;
|
|
|
|
while (parseClassOrNamespaceName(class_or_namespace_name) &&
|
|
LA() == T_COLON_COLON) {
|
|
scope_token = consumeToken();
|
|
*nested_name_specifier = new (_pool) NestedNameSpecifierAST;
|
|
(*nested_name_specifier)->class_or_namespace_name = class_or_namespace_name;
|
|
(*nested_name_specifier)->scope_token = scope_token;
|
|
nested_name_specifier = &(*nested_name_specifier)->next;
|
|
}
|
|
|
|
// ### ugly hack
|
|
rewind(scope_token);
|
|
consumeToken();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseNestedNameSpecifierOpt(NestedNameSpecifierAST *&name,
|
|
bool acceptTemplateId)
|
|
{
|
|
unsigned start = cursor();
|
|
if (! parseNestedNameSpecifier(name, acceptTemplateId))
|
|
rewind(start);
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseName(NameAST *&node, bool acceptTemplateId)
|
|
{
|
|
unsigned global_scope_token = 0;
|
|
if (LA() == T_COLON_COLON)
|
|
global_scope_token = consumeToken();
|
|
|
|
NestedNameSpecifierAST *nested_name_specifier = 0;
|
|
parseNestedNameSpecifierOpt(nested_name_specifier,
|
|
/*acceptTemplateId=*/ true);
|
|
|
|
NameAST *unqualified_name = 0;
|
|
if (parseUnqualifiedName(unqualified_name,
|
|
/*acceptTemplateId=*/ acceptTemplateId || nested_name_specifier != 0)) {
|
|
if (! global_scope_token && ! nested_name_specifier) {
|
|
node = unqualified_name;
|
|
return true;
|
|
}
|
|
|
|
QualifiedNameAST *ast = new (_pool) QualifiedNameAST;
|
|
ast->global_scope_token = global_scope_token;
|
|
ast->nested_name_specifier = nested_name_specifier;
|
|
ast->unqualified_name = unqualified_name;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTranslationUnit(TranslationUnitAST *&node)
|
|
{
|
|
TranslationUnitAST *ast = new (_pool) TranslationUnitAST;
|
|
DeclarationAST **decl = &ast->declarations;
|
|
|
|
while (LA()) {
|
|
unsigned start_declaration = cursor();
|
|
|
|
if (parseDeclaration(*decl)) {
|
|
if (*decl)
|
|
decl = &(*decl)->next;
|
|
} else {
|
|
rewind(start_declaration + 1);
|
|
skipUntilDeclaration();
|
|
}
|
|
}
|
|
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseEmptyDeclaration(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_SEMICOLON) {
|
|
EmptyDeclarationAST *ast = new (_pool) EmptyDeclarationAST;
|
|
ast->semicolon_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseDeclaration(DeclarationAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_SEMICOLON:
|
|
return parseEmptyDeclaration(node);
|
|
|
|
case T_NAMESPACE:
|
|
return parseNamespace(node);
|
|
|
|
case T_USING:
|
|
return parseUsing(node);
|
|
|
|
case T_ASM:
|
|
return parseAsmDefinition(node);
|
|
|
|
case T_TEMPLATE:
|
|
case T_EXPORT:
|
|
return parseTemplateDeclaration(node);
|
|
|
|
// ObjcC++
|
|
case T_AT_CLASS:
|
|
return parseObjCClassDeclaration(node);
|
|
|
|
case T_AT_INTERFACE:
|
|
return parseObjCInterface(node);
|
|
|
|
case T_AT_PROTOCOL:
|
|
return parseObjCProtocol(node);
|
|
|
|
case T_AT_IMPLEMENTATION:
|
|
return parseObjCImplementation(node);
|
|
|
|
case T_AT_END:
|
|
return parseObjCEnd(node);
|
|
|
|
default: {
|
|
if (_objCEnabled && LA() == T___ATTRIBUTE__) {
|
|
const unsigned start = cursor();
|
|
SpecifierAST *attributes = 0, **attr = &attributes;
|
|
while (parseAttributeSpecifier(*attr))
|
|
attr = &(*attr)->next;
|
|
if (LA() == T_AT_INTERFACE)
|
|
return parseObjCInterface(node, attributes);
|
|
else if (LA() == T_AT_PROTOCOL)
|
|
return parseObjCProtocol(node, attributes);
|
|
else if (LA() == T_AT_PROPERTY)
|
|
return parseObjCPropertyDeclaration(node, attributes);
|
|
rewind(start);
|
|
}
|
|
|
|
if (LA() == T_EXTERN && LA(2) == T_TEMPLATE)
|
|
return parseTemplateDeclaration(node);
|
|
else if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL)
|
|
return parseLinkageSpecification(node);
|
|
else
|
|
return parseSimpleDeclaration(node);
|
|
} break; // default
|
|
|
|
} // end switch
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseLinkageSpecification(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) {
|
|
LinkageSpecificationAST *ast = new (_pool) LinkageSpecificationAST;
|
|
ast->extern_token = consumeToken();
|
|
ast->extern_type = consumeToken();
|
|
|
|
if (LA() == T_LBRACE)
|
|
parseLinkageBody(ast->declaration);
|
|
else
|
|
parseDeclaration(ast->declaration);
|
|
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseLinkageBody(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_LBRACE) {
|
|
LinkageBodyAST *ast = new (_pool) LinkageBodyAST;
|
|
ast->lbrace_token = consumeToken();
|
|
DeclarationAST **declaration_ptr = &ast->declarations;
|
|
|
|
while (int tk = LA()) {
|
|
if (tk == T_RBRACE)
|
|
break;
|
|
|
|
unsigned start_declaration = cursor();
|
|
if (parseDeclaration(*declaration_ptr)) {
|
|
if (*declaration_ptr) // ### remove me
|
|
declaration_ptr = &(*declaration_ptr)->next;
|
|
} else {
|
|
rewind(start_declaration + 1);
|
|
skipUntilDeclaration();
|
|
}
|
|
}
|
|
match(T_RBRACE, &ast->rbrace_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ### rename parseNamespaceAliarOrDeclaration?
|
|
bool Parser::parseNamespace(DeclarationAST *&node)
|
|
{
|
|
if (LA() != T_NAMESPACE)
|
|
return false;
|
|
|
|
unsigned namespace_token = consumeToken();
|
|
|
|
if (LA() == T_IDENTIFIER && LA(2) == T_EQUAL) {
|
|
NamespaceAliasDefinitionAST *ast =
|
|
new (_pool) NamespaceAliasDefinitionAST;
|
|
ast->namespace_token = namespace_token;
|
|
ast->namespace_name = consumeToken();
|
|
ast->equal_token = consumeToken();
|
|
parseName(ast->name);
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
NamespaceAST *ast = new (_pool) NamespaceAST;
|
|
ast->namespace_token = namespace_token;
|
|
if (LA() == T_IDENTIFIER)
|
|
ast->identifier_token = consumeToken();
|
|
SpecifierAST **attr_ptr = &ast->attributes;
|
|
while (LA() == T___ATTRIBUTE__) {
|
|
parseAttributeSpecifier(*attr_ptr);
|
|
attr_ptr = &(*attr_ptr)->next;
|
|
}
|
|
if (LA() == T_LBRACE)
|
|
parseLinkageBody(ast->linkage_body);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseUsing(DeclarationAST *&node)
|
|
{
|
|
if (LA() != T_USING)
|
|
return false;
|
|
|
|
if (LA(2) == T_NAMESPACE)
|
|
return parseUsingDirective(node);
|
|
|
|
UsingAST *ast = new (_pool) UsingAST;
|
|
ast->using_token = consumeToken();
|
|
|
|
if (LA() == T_TYPENAME)
|
|
ast->typename_token = consumeToken();
|
|
|
|
parseName(ast->name);
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseUsingDirective(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_USING && LA(2) == T_NAMESPACE) {
|
|
UsingDirectiveAST *ast = new (_pool) UsingDirectiveAST;
|
|
ast->using_token = consumeToken();
|
|
ast->namespace_token = consumeToken();
|
|
if (! parseName(ast->name))
|
|
_translationUnit->warning(cursor(), "expected `namespace name' before `%s'",
|
|
tok().spell());
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseConversionFunctionId(NameAST *&node)
|
|
{
|
|
if (LA() != T_OPERATOR)
|
|
return false;
|
|
unsigned operator_token = consumeToken();
|
|
SpecifierAST *type_specifier = 0;
|
|
if (! parseTypeSpecifier(type_specifier)) {
|
|
return false;
|
|
}
|
|
PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
|
|
while (parsePtrOperator(*ptr_operators_tail))
|
|
ptr_operators_tail = &(*ptr_operators_tail)->next;
|
|
|
|
ConversionFunctionIdAST *ast = new (_pool) ConversionFunctionIdAST;
|
|
ast->operator_token = operator_token;
|
|
ast->type_specifier = type_specifier;
|
|
ast->ptr_operators = ptr_operators;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseOperatorFunctionId(NameAST *&node)
|
|
{
|
|
if (LA() != T_OPERATOR)
|
|
return false;
|
|
unsigned operator_token = consumeToken();
|
|
|
|
OperatorAST *op = 0;
|
|
if (! parseOperator(op))
|
|
return false;
|
|
|
|
OperatorFunctionIdAST *ast = new (_pool) OperatorFunctionIdAST;
|
|
ast->operator_token = operator_token;
|
|
ast->op = op;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseTemplateArgumentList(TemplateArgumentListAST *&node)
|
|
{
|
|
TemplateArgumentListAST **template_argument_ptr = &node;
|
|
ExpressionAST *template_argument = 0;
|
|
if (parseTemplateArgument(template_argument)) {
|
|
*template_argument_ptr = new (_pool) TemplateArgumentListAST;
|
|
(*template_argument_ptr)->template_argument = template_argument;
|
|
template_argument_ptr = &(*template_argument_ptr)->next;
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
|
|
if (parseTemplateArgument(template_argument)) {
|
|
*template_argument_ptr = new (_pool) TemplateArgumentListAST;
|
|
(*template_argument_ptr)->template_argument = template_argument;
|
|
template_argument_ptr = &(*template_argument_ptr)->next;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseAsmDefinition(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_ASM) {
|
|
AsmDefinitionAST *ast = new (_pool) AsmDefinitionAST;
|
|
ast->asm_token = consumeToken();
|
|
parseCvQualifiers(ast->cv_qualifier_seq);
|
|
if (LA() == T_LPAREN) {
|
|
ast->lparen_token = cursor();
|
|
if (skip(T_LPAREN, T_RPAREN))
|
|
ast->rparen_token = consumeToken();
|
|
}
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTemplateDeclaration(DeclarationAST *&node)
|
|
{
|
|
if (! (LA(1) == T_TEMPLATE || ((LA(1) == T_EXPORT || LA(1) == T_EXTERN)
|
|
&& LA(2) == T_TEMPLATE)))
|
|
return false;
|
|
|
|
TemplateDeclarationAST *ast = new (_pool) TemplateDeclarationAST;
|
|
|
|
if (LA() == T_EXPORT || LA() == T_EXPORT)
|
|
ast->export_token = consumeToken();
|
|
|
|
ast->template_token = consumeToken();
|
|
|
|
if (LA() == T_LESS) {
|
|
ast->less_token = consumeToken();
|
|
if (LA() == T_GREATER || parseTemplateParameterList(ast->template_parameters))
|
|
match(T_GREATER, &ast->greater_token);
|
|
}
|
|
|
|
parseDeclaration(ast->declaration);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseOperator(OperatorAST *&node) // ### FIXME
|
|
{
|
|
OperatorAST *ast = new (_pool) OperatorAST;
|
|
|
|
switch (LA()) {
|
|
case T_NEW:
|
|
case T_DELETE: {
|
|
ast->op_token = consumeToken();
|
|
if (LA() == T_LBRACKET) {
|
|
ast->open_token = consumeToken();
|
|
match(T_RBRACKET, &ast->close_token);
|
|
}
|
|
} break;
|
|
|
|
case T_PLUS:
|
|
case T_MINUS:
|
|
case T_STAR:
|
|
case T_SLASH:
|
|
case T_PERCENT:
|
|
case T_CARET:
|
|
case T_AMPER:
|
|
case T_PIPE:
|
|
case T_TILDE:
|
|
case T_EXCLAIM:
|
|
case T_LESS:
|
|
case T_GREATER:
|
|
case T_COMMA:
|
|
case T_AMPER_EQUAL:
|
|
case T_CARET_EQUAL:
|
|
case T_SLASH_EQUAL:
|
|
case T_EQUAL:
|
|
case T_EQUAL_EQUAL:
|
|
case T_EXCLAIM_EQUAL:
|
|
case T_GREATER_EQUAL:
|
|
case T_GREATER_GREATER_EQUAL:
|
|
case T_LESS_EQUAL:
|
|
case T_LESS_LESS_EQUAL:
|
|
case T_MINUS_EQUAL:
|
|
case T_PERCENT_EQUAL:
|
|
case T_PIPE_EQUAL:
|
|
case T_PLUS_EQUAL:
|
|
case T_STAR_EQUAL:
|
|
case T_TILDE_EQUAL:
|
|
case T_LESS_LESS:
|
|
case T_GREATER_GREATER:
|
|
case T_AMPER_AMPER:
|
|
case T_PIPE_PIPE:
|
|
case T_PLUS_PLUS:
|
|
case T_MINUS_MINUS:
|
|
case T_ARROW_STAR:
|
|
case T_DOT_STAR:
|
|
case T_ARROW:
|
|
ast->op_token = consumeToken();
|
|
break;
|
|
|
|
default:
|
|
if (LA() == T_LPAREN && LA(2) == T_RPAREN) {
|
|
ast->op_token = ast->open_token = consumeToken();
|
|
ast->close_token = consumeToken();
|
|
} else if (LA() == T_LBRACKET && LA(2) == T_RBRACKET) {
|
|
ast->op_token = ast->open_token = consumeToken();
|
|
ast->close_token = consumeToken();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseCvQualifiers(SpecifierAST *&node)
|
|
{
|
|
unsigned start = cursor();
|
|
SpecifierAST **ast = &node;
|
|
while (*ast)
|
|
ast = &(*ast)->next;
|
|
|
|
while (int tk = LA()) {
|
|
if (tk == T_CONST || tk == T_VOLATILE) {
|
|
SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
|
|
spec->specifier_token = consumeToken();
|
|
*ast = spec;
|
|
ast = &(*ast)->next;
|
|
} else if(LA() == T___ATTRIBUTE__) {
|
|
parseAttributeSpecifier(*ast);
|
|
ast = &(*ast)->next;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return start != cursor();
|
|
}
|
|
|
|
bool Parser::parsePtrOperator(PtrOperatorAST *&node)
|
|
{
|
|
if (LA() == T_AMPER) {
|
|
ReferenceAST *ast = new (_pool) ReferenceAST;
|
|
ast->amp_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
} else if (LA() == T_STAR) {
|
|
PointerAST *ast = new (_pool) PointerAST;
|
|
ast->star_token = consumeToken();
|
|
parseCvQualifiers(ast->cv_qualifier_seq);
|
|
node = ast;
|
|
return true;
|
|
} else if (LA() == T_COLON_COLON || LA() == T_IDENTIFIER) {
|
|
unsigned scope_or_identifier_token = cursor();
|
|
|
|
unsigned global_scope_token = 0;
|
|
if (LA() == T_COLON_COLON)
|
|
global_scope_token = consumeToken();
|
|
|
|
NestedNameSpecifierAST *nested_name_specifier = 0;
|
|
bool has_nested_name_specifier = parseNestedNameSpecifier(
|
|
nested_name_specifier, true);
|
|
if (has_nested_name_specifier && LA() == T_STAR) {
|
|
PointerToMemberAST *ast = new (_pool) PointerToMemberAST;
|
|
ast->global_scope_token = global_scope_token;
|
|
ast->nested_name_specifier = nested_name_specifier;
|
|
ast->star_token = consumeToken();
|
|
parseCvQualifiers(ast->cv_qualifier_seq);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
rewind(scope_or_identifier_token);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTemplateArgument(ExpressionAST *&node)
|
|
{
|
|
unsigned start = cursor();
|
|
if (parseTypeId(node) && (LA() == T_COMMA || LA() == T_GREATER))
|
|
return true;
|
|
|
|
rewind(start);
|
|
bool previousTemplateArguments = switchTemplateArguments(true);
|
|
bool parsed = parseLogicalOrExpression(node);
|
|
(void) switchTemplateArguments(previousTemplateArguments);
|
|
return parsed;
|
|
}
|
|
|
|
bool Parser::parseDeclSpecifierSeq(SpecifierAST *&decl_specifier_seq,
|
|
bool onlyTypeSpecifiers,
|
|
bool simplified)
|
|
{
|
|
bool has_type_specifier = false;
|
|
NameAST *named_type_specifier = 0;
|
|
SpecifierAST **decl_specifier_seq_ptr = &decl_specifier_seq;
|
|
for (;;) {
|
|
if (lookAtCVQualifier()) {
|
|
SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
|
|
spec->specifier_token = consumeToken();
|
|
*decl_specifier_seq_ptr = spec;
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
} else if (! onlyTypeSpecifiers && lookAtStorageClassSpecifier()) {
|
|
SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
|
|
spec->specifier_token = consumeToken();
|
|
*decl_specifier_seq_ptr = spec;
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
} else if (! named_type_specifier && lookAtBuiltinTypeSpecifier()) {
|
|
parseBuiltinTypeSpecifier(*decl_specifier_seq_ptr);
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
has_type_specifier = true;
|
|
} else if (! has_type_specifier && (LA() == T_COLON_COLON ||
|
|
LA() == T_IDENTIFIER)) {
|
|
if (! parseName(named_type_specifier))
|
|
return false;
|
|
NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
|
|
spec->name = named_type_specifier;
|
|
*decl_specifier_seq_ptr = spec;
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
has_type_specifier = true;
|
|
} else if (! simplified && ! has_type_specifier && (LA() == T_TYPENAME ||
|
|
LA() == T_ENUM ||
|
|
lookAtClassKey())) {
|
|
unsigned startOfElaboratedTypeSpecifier = cursor();
|
|
if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr)) {
|
|
_translationUnit->error(startOfElaboratedTypeSpecifier,
|
|
"expected an elaborated type specifier");
|
|
break;
|
|
}
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
has_type_specifier = true;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
return decl_specifier_seq != 0;
|
|
}
|
|
|
|
bool Parser::parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node)
|
|
{
|
|
unsigned start = cursor();
|
|
bool blocked = blockErrors(true);
|
|
if (parseDeclarator(node)) {
|
|
blockErrors(blocked);
|
|
return true;
|
|
}
|
|
blockErrors(blocked);
|
|
rewind(start);
|
|
return parseAbstractDeclarator(node);
|
|
}
|
|
|
|
bool Parser::parseCoreDeclarator(DeclaratorAST *&node)
|
|
{
|
|
PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
|
|
while (parsePtrOperator(*ptr_operators_tail))
|
|
ptr_operators_tail = &(*ptr_operators_tail)->next;
|
|
|
|
if (LA() == T_COLON_COLON || LA() == T_IDENTIFIER || LA() == T_TILDE
|
|
|| LA() == T_OPERATOR) {
|
|
NameAST *name = 0;
|
|
if (parseName(name)) {
|
|
DeclaratorIdAST *declarator_id = new (_pool) DeclaratorIdAST;
|
|
declarator_id->name = name;
|
|
DeclaratorAST *ast = new (_pool) DeclaratorAST;
|
|
ast->ptr_operators = ptr_operators;
|
|
ast->core_declarator = declarator_id;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
} else if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
DeclaratorAST *declarator = 0;
|
|
if (parseDeclarator(declarator) && LA() == T_RPAREN) {
|
|
NestedDeclaratorAST *nested_declarator = new (_pool) NestedDeclaratorAST;
|
|
nested_declarator->lparen_token = lparen_token;
|
|
nested_declarator->declarator = declarator;
|
|
nested_declarator->rparen_token = consumeToken();
|
|
DeclaratorAST *ast = new (_pool) DeclaratorAST;
|
|
ast->ptr_operators = ptr_operators;
|
|
ast->core_declarator = nested_declarator;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseDeclarator(DeclaratorAST *&node)
|
|
{
|
|
if (! parseCoreDeclarator(node))
|
|
return false;
|
|
|
|
PostfixDeclaratorAST **postfix_ptr = &node->postfix_declarators;
|
|
|
|
for (;;) {
|
|
unsigned startOfPostDeclarator = cursor();
|
|
|
|
if (LA() == T_LPAREN) {
|
|
FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
|
|
ast->lparen_token = consumeToken();
|
|
parseParameterDeclarationClause(ast->parameters);
|
|
if (LA() != T_RPAREN) {
|
|
rewind(startOfPostDeclarator);
|
|
break;
|
|
}
|
|
|
|
ast->rparen_token = consumeToken();
|
|
parseCvQualifiers(ast->cv_qualifier_seq);
|
|
parseExceptionSpecification(ast->exception_specification);
|
|
*postfix_ptr = ast;
|
|
postfix_ptr = &(*postfix_ptr)->next;
|
|
} else if (LA() == T_LBRACKET) {
|
|
ArrayDeclaratorAST *ast = new (_pool) ArrayDeclaratorAST;
|
|
ast->lbracket_token = consumeToken();
|
|
if (LA() == T_RBRACKET || parseConstantExpression(ast->expression)) {
|
|
match(T_RBRACKET, &ast->rbracket_token);
|
|
}
|
|
*postfix_ptr = ast;
|
|
postfix_ptr = &(*postfix_ptr)->next;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
SpecifierAST **spec_ptr = &node->attributes;
|
|
while (LA() == T___ATTRIBUTE__) {
|
|
parseAttributeSpecifier(*spec_ptr);
|
|
spec_ptr = &(*spec_ptr)->next;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseAbstractCoreDeclarator(DeclaratorAST *&node)
|
|
{
|
|
PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
|
|
while (parsePtrOperator(*ptr_operators_tail))
|
|
ptr_operators_tail = &(*ptr_operators_tail)->next;
|
|
|
|
unsigned after_ptr_operators = cursor();
|
|
|
|
if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
DeclaratorAST *declarator = 0;
|
|
if (parseAbstractDeclarator(declarator) && LA() == T_RPAREN) {
|
|
NestedDeclaratorAST *nested_declarator = new (_pool) NestedDeclaratorAST;
|
|
nested_declarator->lparen_token = lparen_token;
|
|
nested_declarator->declarator = declarator;
|
|
nested_declarator->rparen_token = consumeToken();
|
|
DeclaratorAST *ast = new (_pool) DeclaratorAST;
|
|
ast->ptr_operators = ptr_operators;
|
|
ast->core_declarator = nested_declarator;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
rewind(after_ptr_operators);
|
|
if (ptr_operators) {
|
|
DeclaratorAST *ast = new (_pool) DeclaratorAST;
|
|
ast->ptr_operators = ptr_operators;
|
|
node = ast;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseAbstractDeclarator(DeclaratorAST *&node)
|
|
{
|
|
if (! parseAbstractCoreDeclarator(node))
|
|
return false;
|
|
|
|
PostfixDeclaratorAST *postfix_declarators = 0,
|
|
**postfix_ptr = &postfix_declarators;
|
|
|
|
for (;;) {
|
|
if (LA() == T_LPAREN) {
|
|
FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
|
|
ast->lparen_token = consumeToken();
|
|
if (LA() == T_RPAREN || parseParameterDeclarationClause(ast->parameters)) {
|
|
if (LA() == T_RPAREN)
|
|
ast->rparen_token = consumeToken();
|
|
}
|
|
parseCvQualifiers(ast->cv_qualifier_seq);
|
|
parseExceptionSpecification(ast->exception_specification);
|
|
*postfix_ptr = ast;
|
|
postfix_ptr = &(*postfix_ptr)->next;
|
|
} else if (LA() == T_LBRACKET) {
|
|
ArrayDeclaratorAST *ast = new (_pool) ArrayDeclaratorAST;
|
|
ast->lbracket_token = consumeToken();
|
|
if (LA() == T_RBRACKET || parseConstantExpression(ast->expression)) {
|
|
if (LA() == T_RBRACKET)
|
|
ast->rbracket_token = consumeToken();
|
|
}
|
|
*postfix_ptr = ast;
|
|
postfix_ptr = &(*postfix_ptr)->next;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
if (postfix_declarators) {
|
|
if (! node)
|
|
node = new (_pool) DeclaratorAST;
|
|
|
|
node->postfix_declarators = postfix_declarators;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseEnumSpecifier(SpecifierAST *&node)
|
|
{
|
|
if (LA() == T_ENUM) {
|
|
unsigned enum_token = consumeToken();
|
|
NameAST *name = 0;
|
|
parseName(name);
|
|
if (LA() == T_LBRACE) {
|
|
EnumSpecifierAST *ast = new (_pool) EnumSpecifierAST;
|
|
ast->enum_token = enum_token;
|
|
ast->name = name;
|
|
ast->lbrace_token = consumeToken();
|
|
EnumeratorAST **enumerator_ptr = &ast->enumerators;
|
|
while (int tk = LA()) {
|
|
if (tk == T_RBRACE)
|
|
break;
|
|
|
|
if (LA() != T_IDENTIFIER) {
|
|
_translationUnit->error(cursor(), "expected identifier before '%s'", tok().spell());
|
|
skipUntil(T_IDENTIFIER);
|
|
}
|
|
|
|
if (parseEnumerator(*enumerator_ptr))
|
|
enumerator_ptr = &(*enumerator_ptr)->next;
|
|
|
|
if (LA() != T_RBRACE) {
|
|
unsigned comma_token = 0;
|
|
match(T_COMMA, &comma_token);
|
|
}
|
|
}
|
|
match(T_RBRACE, &ast->rbrace_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTemplateParameterList(DeclarationAST *&node)
|
|
{
|
|
DeclarationAST **template_parameter_ptr = &node;
|
|
if (parseTemplateParameter(*template_parameter_ptr)) {
|
|
template_parameter_ptr = &(*template_parameter_ptr)->next;
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
|
|
if (parseTemplateParameter(*template_parameter_ptr))
|
|
template_parameter_ptr = &(*template_parameter_ptr)->next;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTemplateParameter(DeclarationAST *&node)
|
|
{
|
|
if (parseTypeParameter(node))
|
|
return true;
|
|
bool previousTemplateArguments = switchTemplateArguments(true);
|
|
bool parsed = parseParameterDeclaration(node);
|
|
(void) switchTemplateArguments(previousTemplateArguments);
|
|
return parsed;
|
|
}
|
|
|
|
bool Parser::parseTypenameTypeParameter(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_CLASS || LA() == T_TYPENAME) {
|
|
TypenameTypeParameterAST *ast = new (_pool) TypenameTypeParameterAST;
|
|
ast->classkey_token = consumeToken();
|
|
parseName(ast->name);
|
|
if (LA() == T_EQUAL) {
|
|
ast->equal_token = consumeToken();
|
|
parseTypeId(ast->type_id);
|
|
}
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_TEMPLATE) {
|
|
TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST;
|
|
ast->template_token = consumeToken();
|
|
if (LA() == T_LESS)
|
|
ast->less_token = consumeToken();
|
|
parseTemplateParameterList(ast->template_parameters);
|
|
if (LA() == T_GREATER)
|
|
ast->greater_token = consumeToken();
|
|
if (LA() == T_CLASS)
|
|
ast->class_token = consumeToken();
|
|
|
|
// parse optional name
|
|
parseName(ast->name);
|
|
|
|
if (LA() == T_EQUAL) {
|
|
ast->equal_token = consumeToken();
|
|
parseTypeId(ast->type_id);
|
|
}
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTypeParameter(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_CLASS || LA() == T_TYPENAME)
|
|
return parseTypenameTypeParameter(node);
|
|
else if (LA() == T_TEMPLATE)
|
|
return parseTemplateTypeParameter(node);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTypeId(ExpressionAST *&node)
|
|
{
|
|
SpecifierAST *type_specifier = 0;
|
|
if (parseTypeSpecifier(type_specifier)) {
|
|
TypeIdAST *ast = new (_pool) TypeIdAST;
|
|
ast->type_specifier = type_specifier;
|
|
parseAbstractDeclarator(ast->declarator);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node)
|
|
{
|
|
DeclarationAST *parameter_declarations = 0;
|
|
if (LA() != T_DOT_DOT_DOT)
|
|
parseParameterDeclarationList(parameter_declarations);
|
|
unsigned dot_dot_dot_token = 0;
|
|
if (LA() == T_DOT_DOT_DOT || (LA() == T_COMMA && LA(2) == T_DOT_DOT_DOT)) {
|
|
if (LA() == T_COMMA)
|
|
consumeToken();
|
|
dot_dot_dot_token = consumeToken();
|
|
}
|
|
ParameterDeclarationClauseAST *ast = new (_pool) ParameterDeclarationClauseAST;
|
|
ast->parameter_declarations = parameter_declarations;
|
|
ast->dot_dot_dot_token = dot_dot_dot_token;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseParameterDeclarationList(DeclarationAST *&node)
|
|
{
|
|
DeclarationAST **parameter_declaration_ptr = &node;
|
|
if (parseParameterDeclaration(*parameter_declaration_ptr)) {
|
|
parameter_declaration_ptr = &(*parameter_declaration_ptr)->next;
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
|
|
if (LA() == T_DOT_DOT_DOT)
|
|
break;
|
|
|
|
if (parseParameterDeclaration(*parameter_declaration_ptr))
|
|
parameter_declaration_ptr = &(*parameter_declaration_ptr)->next;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseParameterDeclaration(DeclarationAST *&node)
|
|
{
|
|
SpecifierAST *decl_specifier_seq = 0;
|
|
if (parseDeclSpecifierSeq(decl_specifier_seq)) {
|
|
ParameterDeclarationAST *ast = new (_pool) ParameterDeclarationAST;
|
|
ast->type_specifier = decl_specifier_seq;
|
|
parseDeclaratorOrAbstractDeclarator(ast->declarator);
|
|
if (LA() == T_EQUAL) {
|
|
ast->equal_token = consumeToken();
|
|
parseLogicalOrExpression(ast->expression);
|
|
}
|
|
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseClassSpecifier(SpecifierAST *&node)
|
|
{
|
|
if (! lookAtClassKey())
|
|
return false;
|
|
|
|
unsigned classkey_token = consumeToken();
|
|
|
|
SpecifierAST *attributes = 0, **attr_ptr = &attributes;
|
|
while (LA() == T___ATTRIBUTE__) {
|
|
parseAttributeSpecifier(*attr_ptr);
|
|
attr_ptr = &(*attr_ptr)->next;
|
|
}
|
|
|
|
if (LA(1) == T_IDENTIFIER && LA(2) == T_IDENTIFIER) {
|
|
_translationUnit->warning(cursor(), "skip identifier `%s'",
|
|
tok().spell());
|
|
consumeToken();
|
|
}
|
|
|
|
NameAST *name = 0;
|
|
parseName(name);
|
|
|
|
bool parsed = false;
|
|
|
|
const bool previousInFunctionBody = _inFunctionBody;
|
|
_inFunctionBody = false;
|
|
|
|
unsigned colon_token = 0;
|
|
|
|
if (LA() == T_COLON || LA() == T_LBRACE) {
|
|
BaseSpecifierAST *base_clause = 0;
|
|
if (LA() == T_COLON) {
|
|
colon_token = cursor();
|
|
parseBaseClause(base_clause);
|
|
if (LA() != T_LBRACE) {
|
|
_translationUnit->error(cursor(), "expected `{' before `%s'", tok().spell());
|
|
unsigned saved = cursor();
|
|
for (int n = 0; n < 3 && LA() != T_EOF_SYMBOL; ++n, consumeToken()) {
|
|
if (LA() == T_LBRACE)
|
|
break;
|
|
}
|
|
if (LA() != T_LBRACE)
|
|
rewind(saved);
|
|
}
|
|
}
|
|
|
|
ClassSpecifierAST *ast = new (_pool) ClassSpecifierAST;
|
|
ast->classkey_token = classkey_token;
|
|
ast->attributes = attributes;
|
|
ast->name = name;
|
|
ast->colon_token = colon_token;
|
|
ast->base_clause = base_clause;
|
|
|
|
if (LA() == T_LBRACE)
|
|
ast->lbrace_token = consumeToken();
|
|
|
|
DeclarationAST **declaration_ptr = &ast->member_specifiers;
|
|
while (int tk = LA()) {
|
|
if (tk == T_RBRACE) {
|
|
ast->rbrace_token = consumeToken();
|
|
break;
|
|
}
|
|
|
|
unsigned start_declaration = cursor();
|
|
if (parseMemberSpecification(*declaration_ptr)) {
|
|
if (*declaration_ptr)
|
|
declaration_ptr = &(*declaration_ptr)->next;
|
|
} else {
|
|
rewind(start_declaration + 1);
|
|
skipUntilDeclaration();
|
|
}
|
|
}
|
|
node = ast;
|
|
parsed = true;
|
|
}
|
|
|
|
_inFunctionBody = previousInFunctionBody;
|
|
|
|
return parsed;
|
|
}
|
|
|
|
bool Parser::parseAccessSpecifier(SpecifierAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_PUBLIC:
|
|
case T_PROTECTED:
|
|
case T_PRIVATE: {
|
|
SimpleSpecifierAST *ast = new (_pool) SimpleSpecifierAST;
|
|
ast->specifier_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
default:
|
|
return false;
|
|
} // switch
|
|
}
|
|
|
|
bool Parser::parseAccessDeclaration(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_PUBLIC || LA() == T_PROTECTED || LA() == T_PRIVATE || LA() == T_SIGNALS) {
|
|
bool isSignals = LA() == T_SIGNALS;
|
|
AccessDeclarationAST *ast = new (_pool) AccessDeclarationAST;
|
|
ast->access_specifier_token = consumeToken();
|
|
if (! isSignals && LA() == T_SLOTS)
|
|
ast->slots_token = consumeToken();
|
|
match(T_COLON, &ast->colon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseMemberSpecification(DeclarationAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_SEMICOLON:
|
|
return parseEmptyDeclaration(node);
|
|
|
|
case T_USING:
|
|
return parseUsing(node);
|
|
|
|
case T_TEMPLATE:
|
|
return parseTemplateDeclaration(node);
|
|
|
|
case T_SIGNALS:
|
|
case T_PUBLIC:
|
|
case T_PROTECTED:
|
|
case T_PRIVATE:
|
|
return parseAccessDeclaration(node);
|
|
|
|
default:
|
|
return parseSimpleDeclaration(node, /*acceptStructDeclarator=*/true);
|
|
} // switch
|
|
}
|
|
|
|
bool Parser::parseCtorInitializer(CtorInitializerAST *&node)
|
|
{
|
|
if (LA() == T_COLON) {
|
|
unsigned colon_token = consumeToken();
|
|
|
|
CtorInitializerAST *ast = new (_pool) CtorInitializerAST;
|
|
ast->colon_token = colon_token;
|
|
|
|
parseMemInitializerList(ast->member_initializers);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseElaboratedTypeSpecifier(SpecifierAST *&node)
|
|
{
|
|
if (lookAtClassKey() || LA() == T_ENUM || LA() == T_TYPENAME) {
|
|
unsigned classkey_token = consumeToken();
|
|
NameAST *name = 0;
|
|
if (parseName(name)) {
|
|
ElaboratedTypeSpecifierAST *ast =
|
|
new (_pool) ElaboratedTypeSpecifierAST;
|
|
|
|
ast->classkey_token = classkey_token;
|
|
ast->name = name;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node)
|
|
{
|
|
if (LA() == T_THROW) {
|
|
ExceptionSpecificationAST *ast = new (_pool) ExceptionSpecificationAST;
|
|
ast->throw_token = consumeToken();
|
|
if (LA() == T_LPAREN)
|
|
ast->lparen_token = consumeToken();
|
|
if (LA() == T_DOT_DOT_DOT)
|
|
ast->dot_dot_dot_token = consumeToken();
|
|
else
|
|
parseTypeIdList(ast->type_ids);
|
|
if (LA() == T_RPAREN)
|
|
ast->rparen_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseEnumerator(EnumeratorAST *&node)
|
|
{
|
|
if (LA() == T_IDENTIFIER) {
|
|
EnumeratorAST *ast = new (_pool) EnumeratorAST;
|
|
ast->identifier_token = consumeToken();
|
|
|
|
if (LA() == T_EQUAL) {
|
|
ast->equal_token = consumeToken();
|
|
parseConstantExpression(ast->expression);
|
|
}
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseInitDeclarator(DeclaratorAST *&node,
|
|
bool acceptStructDeclarator)
|
|
{
|
|
unsigned start = cursor();
|
|
|
|
if (acceptStructDeclarator && LA() == T_COLON) {
|
|
// anonymous bit-field declaration.
|
|
// ### TODO create the AST
|
|
} else if (! parseDeclarator(node)) {
|
|
return false;
|
|
}
|
|
|
|
if (LA() == T_ASM && LA(2) == T_LPAREN) { // ### FIXME
|
|
consumeToken();
|
|
|
|
if (skip(T_LPAREN, T_RPAREN))
|
|
consumeToken();
|
|
}
|
|
|
|
if (acceptStructDeclarator && node &&
|
|
! node->postfix_declarators &&
|
|
node->core_declarator &&
|
|
node->core_declarator->asNestedDeclarator()) {
|
|
rewind(start);
|
|
return false;
|
|
}
|
|
|
|
if (acceptStructDeclarator && LA() == T_COLON
|
|
&& (! node || ! node->postfix_declarators)) {
|
|
unsigned colon_token = consumeToken();
|
|
ExpressionAST *expression = 0;
|
|
if (parseConstantExpression(expression) && (LA() == T_COMMA ||
|
|
LA() == T_SEMICOLON)) {
|
|
// recognized a bitfielddeclarator.
|
|
// ### TODO create the AST
|
|
return true;
|
|
}
|
|
rewind(colon_token);
|
|
} else if (LA() == T_EQUAL || (! acceptStructDeclarator && LA() == T_LPAREN)) {
|
|
parseInitializer(node->initializer);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseBaseClause(BaseSpecifierAST *&node)
|
|
{
|
|
if (LA() == T_COLON) {
|
|
consumeToken();
|
|
|
|
BaseSpecifierAST **ast = &node;
|
|
if (parseBaseSpecifier(*ast)) {
|
|
ast = &(*ast)->next;
|
|
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
|
|
if (parseBaseSpecifier(*ast))
|
|
ast = &(*ast)->next;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseInitializer(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_LPAREN) {
|
|
return parsePrimaryExpression(node);
|
|
} else if (LA() == T_EQUAL) {
|
|
consumeToken();
|
|
return parseInitializerClause(node);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseMemInitializerList(MemInitializerAST *&node)
|
|
{
|
|
MemInitializerAST **initializer = &node;
|
|
|
|
if (parseMemInitializer(*initializer)) {
|
|
initializer = &(*initializer)->next;
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
if (parseMemInitializer(*initializer))
|
|
initializer = &(*initializer)->next;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseMemInitializer(MemInitializerAST *&node)
|
|
{
|
|
NameAST *name = 0;
|
|
if (parseName(name) && LA() == T_LPAREN) {
|
|
MemInitializerAST *ast = new (_pool) MemInitializerAST;
|
|
ast->name = name;
|
|
ast->lparen_token = consumeToken();
|
|
parseExpression(ast->expression);
|
|
if (LA() == T_RPAREN)
|
|
ast->rparen_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseTypeIdList(ExpressionListAST *&node)
|
|
{
|
|
ExpressionListAST **expression_list_ptr = &node;
|
|
ExpressionAST *typeId = 0;
|
|
if (parseTypeId(typeId)) {
|
|
*expression_list_ptr = new (_pool) ExpressionListAST;
|
|
(*expression_list_ptr)->expression = typeId;
|
|
expression_list_ptr = &(*expression_list_ptr)->next;
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
|
|
if (parseTypeId(typeId)) {
|
|
*expression_list_ptr = new (_pool) ExpressionListAST;
|
|
(*expression_list_ptr)->expression = typeId;
|
|
expression_list_ptr = &(*expression_list_ptr)->next;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseExpressionList(ExpressionListAST *&node)
|
|
{
|
|
ExpressionListAST **expression_list_ptr = &node;
|
|
ExpressionAST *expression = 0;
|
|
if (parseAssignmentExpression(expression)) {
|
|
*expression_list_ptr = new (_pool) ExpressionListAST;
|
|
(*expression_list_ptr)->expression = expression;
|
|
expression_list_ptr = &(*expression_list_ptr)->next;
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
|
|
if (parseExpression(expression)) {
|
|
*expression_list_ptr = new (_pool) ExpressionListAST;
|
|
(*expression_list_ptr)->expression = expression;
|
|
expression_list_ptr = &(*expression_list_ptr)->next;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node)
|
|
{
|
|
BaseSpecifierAST *ast = new (_pool) BaseSpecifierAST;
|
|
|
|
if (LA() == T_VIRTUAL) {
|
|
ast->token_virtual = consumeToken();
|
|
|
|
int tk = LA();
|
|
if (tk == T_PUBLIC || tk == T_PROTECTED || tk == T_PRIVATE)
|
|
ast->token_access_specifier = consumeToken();
|
|
} else {
|
|
int tk = LA();
|
|
if (tk == T_PUBLIC || tk == T_PROTECTED || tk == T_PRIVATE)
|
|
ast->token_access_specifier = consumeToken();
|
|
|
|
if (LA() == T_VIRTUAL)
|
|
ast->token_virtual = consumeToken();
|
|
}
|
|
|
|
parseName(ast->name);
|
|
if (! ast->name)
|
|
_translationUnit->error(cursor(), "expected class-name");
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseInitializerList(ExpressionListAST *&node)
|
|
{
|
|
ExpressionListAST **initializer_ptr = &node;
|
|
ExpressionAST *initializer = 0;
|
|
if (parseInitializerClause(initializer)) {
|
|
*initializer_ptr = new (_pool) ExpressionListAST;
|
|
(*initializer_ptr)->expression = initializer;
|
|
initializer_ptr = &(*initializer_ptr)->next;
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
initializer = 0;
|
|
parseInitializerClause(initializer);
|
|
*initializer_ptr = new (_pool) ExpressionListAST;
|
|
(*initializer_ptr)->expression = initializer;
|
|
initializer_ptr = &(*initializer_ptr)->next;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseInitializerClause(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_LBRACE) {
|
|
ArrayInitializerAST *ast = new (_pool) ArrayInitializerAST;
|
|
ast->lbrace_token = consumeToken();
|
|
parseInitializerList(ast->expression_list);
|
|
match(T_RBRACE, &ast->rbrace_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return parseAssignmentExpression(node);
|
|
}
|
|
|
|
bool Parser::parseUnqualifiedName(NameAST *&node, bool acceptTemplateId)
|
|
{
|
|
if (LA() == T_TILDE && LA(2) == T_IDENTIFIER) {
|
|
DestructorNameAST *ast = new (_pool) DestructorNameAST;
|
|
ast->tilde_token = consumeToken();
|
|
ast->identifier_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
} else if (LA() == T_OPERATOR) {
|
|
unsigned operator_token = cursor();
|
|
if (parseOperatorFunctionId(node))
|
|
return true;
|
|
rewind(operator_token);
|
|
return parseConversionFunctionId(node);
|
|
} else if (LA() == T_IDENTIFIER) {
|
|
unsigned identifier_token = cursor();
|
|
if (acceptTemplateId && LA(2) == T_LESS && parseTemplateId(node)) {
|
|
if (! _templateArguments || (LA() == T_COMMA || LA() == T_GREATER ||
|
|
LA() == T_LPAREN || LA() == T_RPAREN ||
|
|
LA() == T_COLON_COLON))
|
|
return true;
|
|
}
|
|
rewind(identifier_token);
|
|
SimpleNameAST *ast = new (_pool) SimpleNameAST;
|
|
ast->identifier_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
} else if (LA() == T_TEMPLATE) {
|
|
unsigned template_token = consumeToken();
|
|
if (parseTemplateId(node))
|
|
return true;
|
|
rewind(template_token);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseStringLiteral(ExpressionAST *&node)
|
|
{
|
|
if (! (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL))
|
|
return false;
|
|
|
|
StringLiteralAST **ast = reinterpret_cast<StringLiteralAST **> (&node);
|
|
|
|
while (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL) {
|
|
*ast = new (_pool) StringLiteralAST;
|
|
(*ast)->token = consumeToken();
|
|
ast = &(*ast)->next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseExpressionStatement(StatementAST *&node)
|
|
{
|
|
ExpressionAST *expression = 0;
|
|
if (LA() == T_SEMICOLON || parseExpression(expression)) {
|
|
ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST;
|
|
ast->expression = expression;
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseStatement(StatementAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_WHILE:
|
|
return parseWhileStatement(node);
|
|
|
|
case T_DO:
|
|
return parseDoStatement(node);
|
|
|
|
case T_FOR:
|
|
return parseForStatement(node);
|
|
|
|
case T_IF:
|
|
return parseIfStatement(node);
|
|
|
|
case T_SWITCH:
|
|
return parseSwitchStatement(node);
|
|
|
|
case T_TRY:
|
|
return parseTryBlockStatement(node);
|
|
|
|
case T_CASE:
|
|
case T_DEFAULT:
|
|
return parseLabeledStatement(node);
|
|
|
|
case T_BREAK:
|
|
return parseBreakStatement(node);
|
|
|
|
case T_CONTINUE:
|
|
return parseContinueStatement(node);
|
|
|
|
case T_GOTO:
|
|
return parseGotoStatement(node);
|
|
|
|
case T_RETURN:
|
|
return parseReturnStatement(node);
|
|
|
|
case T_LBRACE:
|
|
return parseCompoundStatement(node);
|
|
|
|
case T_ASM:
|
|
case T_NAMESPACE:
|
|
case T_USING:
|
|
case T_TEMPLATE:
|
|
case T_CLASS: case T_STRUCT: case T_UNION:
|
|
return parseDeclarationStatement(node);
|
|
|
|
case T_SEMICOLON: {
|
|
ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST;
|
|
ast->semicolon_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
default:
|
|
if (LA() == T_IDENTIFIER && LA(2) == T_COLON)
|
|
return parseLabeledStatement(node);
|
|
|
|
return parseExpressionOrDeclarationStatement(node);
|
|
} // switch
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseBreakStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_BREAK) {
|
|
BreakStatementAST *ast = new (_pool) BreakStatementAST;
|
|
ast->break_token = consumeToken();
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseContinueStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_CONTINUE) {
|
|
ContinueStatementAST *ast = new (_pool) ContinueStatementAST;
|
|
ast->continue_token = consumeToken();
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseGotoStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_GOTO) {
|
|
GotoStatementAST *ast = new (_pool) GotoStatementAST;
|
|
ast->goto_token = consumeToken();
|
|
match(T_IDENTIFIER, &ast->identifier_token);
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseReturnStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_RETURN) {
|
|
ReturnStatementAST *ast = new (_pool) ReturnStatementAST;
|
|
ast->return_token = consumeToken();
|
|
parseExpression(ast->expression);
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::maybeFunctionCall(SimpleDeclarationAST *simpleDecl) const
|
|
{
|
|
if (! simpleDecl)
|
|
return false;
|
|
else if (! simpleDecl->decl_specifier_seq)
|
|
return false;
|
|
else if (simpleDecl->decl_specifier_seq->next)
|
|
return false;
|
|
|
|
NamedTypeSpecifierAST *type_spec = simpleDecl->decl_specifier_seq->asNamedTypeSpecifier();
|
|
if (! type_spec)
|
|
return false;
|
|
|
|
DeclaratorListAST *first_declarator = simpleDecl->declarators;
|
|
if (! first_declarator)
|
|
return false;
|
|
else if (first_declarator->next)
|
|
return false;
|
|
|
|
DeclaratorAST *declarator = first_declarator->declarator;
|
|
if (! declarator)
|
|
return false;
|
|
else if (declarator->ptr_operators)
|
|
return false;
|
|
else if (declarator->postfix_declarators)
|
|
return false;
|
|
else if (declarator->initializer)
|
|
return false;
|
|
else if (! declarator->core_declarator)
|
|
return false;
|
|
|
|
NestedDeclaratorAST *nested_declarator = declarator->core_declarator->asNestedDeclarator();
|
|
if (! nested_declarator)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Parser::maybeSimpleExpression(SimpleDeclarationAST *simpleDecl) const
|
|
{
|
|
if (! simpleDecl->declarators) {
|
|
SpecifierAST *spec = simpleDecl->decl_specifier_seq;
|
|
if (spec && ! spec->next && spec->asNamedTypeSpecifier()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_SEMICOLON)
|
|
return parseExpressionStatement(node);
|
|
|
|
unsigned start = cursor();
|
|
bool blocked = blockErrors(true);
|
|
if (parseDeclarationStatement(node)) {
|
|
DeclarationStatementAST *stmt = static_cast<DeclarationStatementAST *>(node);
|
|
SimpleDeclarationAST *simpleDecl = 0;
|
|
if (stmt->declaration)
|
|
simpleDecl = stmt->declaration->asSimpleDeclaration();
|
|
|
|
if (simpleDecl && simpleDecl->decl_specifier_seq &&
|
|
! maybeFunctionCall(simpleDecl) && ! maybeSimpleExpression(simpleDecl)) {
|
|
unsigned end_of_declaration_statement = cursor();
|
|
rewind(start);
|
|
StatementAST *expression = 0;
|
|
if (! parseExpressionStatement(expression) || cursor() != end_of_declaration_statement) {
|
|
rewind(end_of_declaration_statement);
|
|
} else {
|
|
ExpressionOrDeclarationStatementAST *ast =
|
|
new (_pool) ExpressionOrDeclarationStatementAST;
|
|
ast->declaration = node;
|
|
ast->expression = expression;
|
|
node = ast;
|
|
}
|
|
blockErrors(blocked);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
blockErrors(blocked);
|
|
rewind(start);
|
|
return parseExpressionStatement(node);
|
|
}
|
|
|
|
bool Parser::parseCondition(ExpressionAST *&node)
|
|
{
|
|
unsigned start = cursor();
|
|
|
|
bool blocked = blockErrors(true);
|
|
SpecifierAST *type_specifier = 0;
|
|
if (parseTypeSpecifier(type_specifier)) {
|
|
DeclaratorAST *declarator = 0;
|
|
if (parseInitDeclarator(declarator, /*acceptStructDeclarator=*/false)) {
|
|
if (declarator->initializer) {
|
|
ConditionAST *ast = new (_pool) ConditionAST;
|
|
ast->type_specifier = type_specifier;
|
|
ast->declarator = declarator;
|
|
node = ast;
|
|
blockErrors(blocked);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
blockErrors(blocked);
|
|
rewind(start);
|
|
return parseExpression(node);
|
|
}
|
|
|
|
bool Parser::parseWhileStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_WHILE) {
|
|
WhileStatementAST *ast = new (_pool) WhileStatementAST;
|
|
ast->while_token = consumeToken();
|
|
match(T_LPAREN, &ast->lparen_token);
|
|
parseCondition(ast->condition);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
parseStatement(ast->statement);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseDoStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_DO) {
|
|
DoStatementAST *ast = new (_pool) DoStatementAST;
|
|
ast->do_token = consumeToken();
|
|
parseStatement(ast->statement);
|
|
match(T_WHILE, &ast->while_token);
|
|
match(T_LPAREN, &ast->lparen_token);
|
|
parseExpression(ast->expression);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseForStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_FOR) {
|
|
ForStatementAST *ast = new (_pool) ForStatementAST;
|
|
ast->for_token = consumeToken();
|
|
match(T_LPAREN, &ast->lparen_token);
|
|
parseForInitStatement(ast->initializer);
|
|
parseExpression(ast->condition);
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
parseExpression(ast->expression);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
parseStatement(ast->statement);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseForInitStatement(StatementAST *&node)
|
|
{
|
|
return parseExpressionOrDeclarationStatement(node);
|
|
}
|
|
|
|
bool Parser::parseCompoundStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_LBRACE) {
|
|
CompoundStatementAST *ast = new (_pool) CompoundStatementAST;
|
|
ast->lbrace_token = consumeToken();
|
|
StatementAST **statement_ptr = &ast->statements;
|
|
while (int tk = LA()) {
|
|
if (tk == T_RBRACE)
|
|
break;
|
|
|
|
unsigned start_statement = cursor();
|
|
if (! parseStatement(*statement_ptr)) {
|
|
rewind(start_statement + 1);
|
|
skipUntilStatement();
|
|
} else {
|
|
statement_ptr = &(*statement_ptr)->next;
|
|
}
|
|
}
|
|
match(T_RBRACE, &ast->rbrace_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseIfStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_IF) {
|
|
IfStatementAST *ast = new (_pool) IfStatementAST;
|
|
ast->if_token = consumeToken();
|
|
match(T_LPAREN, &ast->lparen_token);
|
|
parseCondition(ast->condition);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
if (! parseStatement(ast->statement))
|
|
_translationUnit->error(cursor(), "expected statement");
|
|
if (LA() == T_ELSE) {
|
|
ast->else_token = consumeToken();
|
|
if (! parseStatement(ast->else_statement))
|
|
_translationUnit->error(cursor(), "expected statement");
|
|
}
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseSwitchStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_SWITCH) {
|
|
SwitchStatementAST *ast = new (_pool) SwitchStatementAST;
|
|
ast->switch_token = consumeToken();
|
|
match(T_LPAREN, &ast->lparen_token);
|
|
parseCondition(ast->condition);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
parseStatement(ast->statement);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseLabeledStatement(StatementAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_IDENTIFIER:
|
|
if (LA(2) == T_COLON) {
|
|
LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
|
|
ast->label_token = consumeToken();
|
|
ast->colon_token = consumeToken();
|
|
parseStatement(ast->statement);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case T_DEFAULT: {
|
|
LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
|
|
ast->label_token = consumeToken();
|
|
match(T_COLON, &ast->colon_token);
|
|
parseStatement(ast->statement);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
case T_CASE: {
|
|
CaseStatementAST *ast = new (_pool) CaseStatementAST;
|
|
ast->case_token = consumeToken();
|
|
parseConstantExpression(ast->expression);
|
|
match(T_COLON, &ast->colon_token);
|
|
parseStatement(ast->statement);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
} // switch
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseBlockDeclaration(DeclarationAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_USING:
|
|
return parseUsing(node);
|
|
|
|
case T_ASM:
|
|
return parseAsmDefinition(node);
|
|
|
|
case T_NAMESPACE:
|
|
return parseNamespaceAliasDefinition(node);
|
|
|
|
default:
|
|
return parseSimpleDeclaration(node);
|
|
} // switch
|
|
|
|
}
|
|
|
|
bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node)
|
|
{
|
|
if (LA() == T_NAMESPACE && LA(2) == T_IDENTIFIER && LA(3) == T_EQUAL) {
|
|
NamespaceAliasDefinitionAST *ast = new (_pool) NamespaceAliasDefinitionAST;
|
|
ast->namespace_token = consumeToken();
|
|
ast->namespace_name = consumeToken();
|
|
ast->equal_token = consumeToken();
|
|
parseName(ast->name);
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseDeclarationStatement(StatementAST *&node)
|
|
{
|
|
DeclarationAST *declaration = 0;
|
|
if (! parseBlockDeclaration(declaration))
|
|
return false;
|
|
|
|
DeclarationStatementAST *ast = new (_pool) DeclarationStatementAST;
|
|
ast->declaration = declaration;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::lookAtCVQualifier() const
|
|
{
|
|
switch (LA()) {
|
|
case T_CONST:
|
|
case T_VOLATILE:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Parser::lookAtFunctionSpecifier() const
|
|
{
|
|
switch (LA()) {
|
|
case T_INLINE:
|
|
case T_VIRTUAL:
|
|
case T_EXPLICIT:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Parser::lookAtStorageClassSpecifier() const
|
|
{
|
|
switch (LA()) {
|
|
case T_FRIEND:
|
|
case T_AUTO:
|
|
case T_REGISTER:
|
|
case T_STATIC:
|
|
case T_EXTERN:
|
|
case T_MUTABLE:
|
|
case T_TYPEDEF:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Parser::lookAtBuiltinTypeSpecifier() const
|
|
{
|
|
switch (LA()) {
|
|
case T_CHAR:
|
|
case T_WCHAR_T:
|
|
case T_BOOL:
|
|
case T_SHORT:
|
|
case T_INT:
|
|
case T_LONG:
|
|
case T_SIGNED:
|
|
case T_UNSIGNED:
|
|
case T_FLOAT:
|
|
case T_DOUBLE:
|
|
case T_VOID:
|
|
return true;
|
|
// [gcc] extensions
|
|
case T___TYPEOF__:
|
|
case T___ATTRIBUTE__:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Parser::lookAtClassKey() const
|
|
{
|
|
switch (LA()) {
|
|
case T_CLASS:
|
|
case T_STRUCT:
|
|
case T_UNION:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Parser::parseAttributeSpecifier(SpecifierAST *&node)
|
|
{
|
|
if (LA() != T___ATTRIBUTE__)
|
|
return false;
|
|
|
|
AttributeSpecifierAST *ast = new (_pool) AttributeSpecifierAST;
|
|
ast->attribute_token = consumeToken();
|
|
match(T_LPAREN, &ast->first_lparen_token);
|
|
match(T_LPAREN, &ast->second_lparen_token);
|
|
parseAttributeList(ast->attributes);
|
|
match(T_RPAREN, &ast->first_rparen_token);
|
|
match(T_RPAREN, &ast->second_rparen_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseAttributeList(AttributeAST *&node)
|
|
{
|
|
AttributeAST **attribute_ptr = &node;
|
|
while (LA() == T_IDENTIFIER || LA() == T_CONST) {
|
|
AttributeAST *ast = new (_pool) AttributeAST;
|
|
ast->identifier_token = consumeToken();
|
|
if (LA() == T_LPAREN) {
|
|
consumeToken();
|
|
if (LA() == T_IDENTIFIER && (LA(2) == T_COMMA || LA(2) == T_RPAREN)) {
|
|
ast->tag_token = consumeToken();
|
|
if (LA() == T_COMMA) {
|
|
consumeToken();
|
|
parseExpressionList(ast->expression_list);
|
|
}
|
|
} else {
|
|
parseExpressionList(ast->expression_list);
|
|
}
|
|
unsigned rparen_token = 0;
|
|
match(T_RPAREN, &rparen_token);
|
|
}
|
|
*attribute_ptr = ast;
|
|
|
|
if (LA() != T_COMMA)
|
|
break;
|
|
|
|
consumeToken();
|
|
attribute_ptr = &(*attribute_ptr)->next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseBuiltinTypeSpecifier(SpecifierAST *&node)
|
|
{
|
|
if (LA() == T___ATTRIBUTE__) {
|
|
return parseAttributeSpecifier(node);
|
|
} else if (LA() == T___TYPEOF__) {
|
|
TypeofSpecifierAST *ast = new (_pool) TypeofSpecifierAST;
|
|
ast->typeof_token = consumeToken();
|
|
if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
if (parseTypeId(ast->expression) && LA() == T_RPAREN) {
|
|
consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
rewind(lparen_token);
|
|
}
|
|
parseUnaryExpression(ast->expression);
|
|
node = ast;
|
|
return true;
|
|
} else if (lookAtBuiltinTypeSpecifier()) {
|
|
SimpleSpecifierAST *ast = new (_pool) SimpleSpecifierAST;
|
|
ast->specifier_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseSimpleDeclaration(DeclarationAST *&node,
|
|
bool acceptStructDeclarator)
|
|
{
|
|
// parse a simple declaration, a function definition,
|
|
// or a contructor declaration.
|
|
cursor();
|
|
|
|
bool has_type_specifier = false;
|
|
bool has_complex_type_specifier = false;
|
|
unsigned startOfNamedTypeSpecifier = 0;
|
|
NameAST *named_type_specifier = 0;
|
|
SpecifierAST *decl_specifier_seq = 0,
|
|
**decl_specifier_seq_ptr = &decl_specifier_seq;
|
|
for (;;) {
|
|
if (lookAtCVQualifier() || lookAtFunctionSpecifier()
|
|
|| lookAtStorageClassSpecifier()) {
|
|
SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
|
|
spec->specifier_token = consumeToken();
|
|
*decl_specifier_seq_ptr = spec;
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
} else if (LA() == T___ATTRIBUTE__) {
|
|
parseAttributeSpecifier(*decl_specifier_seq_ptr);
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
} else if (! named_type_specifier && ! has_complex_type_specifier && lookAtBuiltinTypeSpecifier()) {
|
|
parseBuiltinTypeSpecifier(*decl_specifier_seq_ptr);
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
has_type_specifier = true;
|
|
} else if (! has_type_specifier && (LA() == T_COLON_COLON ||
|
|
LA() == T_IDENTIFIER)) {
|
|
startOfNamedTypeSpecifier = cursor();
|
|
if (parseName(named_type_specifier)) {
|
|
NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
|
|
spec->name = named_type_specifier;
|
|
*decl_specifier_seq_ptr = spec;
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
has_type_specifier = true;
|
|
} else {
|
|
rewind(startOfNamedTypeSpecifier);
|
|
break;
|
|
}
|
|
} else if (! has_type_specifier && LA() == T_ENUM) {
|
|
unsigned startOfTypeSpecifier = cursor();
|
|
if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) || LA() == T_LBRACE) {
|
|
rewind(startOfTypeSpecifier);
|
|
if (! parseEnumSpecifier(*decl_specifier_seq_ptr)) {
|
|
_translationUnit->error(startOfTypeSpecifier,
|
|
"expected an enum specifier");
|
|
break;
|
|
}
|
|
has_complex_type_specifier = true;
|
|
}
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
has_type_specifier = true;
|
|
} else if (! has_type_specifier && LA() == T_TYPENAME) {
|
|
unsigned startOfElaboratedTypeSpecifier = cursor();
|
|
if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr)) {
|
|
_translationUnit->error(startOfElaboratedTypeSpecifier,
|
|
"expected an elaborated type specifier");
|
|
break;
|
|
}
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
has_type_specifier = true;
|
|
} else if (! has_type_specifier && lookAtClassKey()) {
|
|
unsigned startOfTypeSpecifier = cursor();
|
|
if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) ||
|
|
(LA() == T_COLON || LA() == T_LBRACE || (LA(0) == T_IDENTIFIER && LA(1) == T_IDENTIFIER &&
|
|
(LA(2) == T_COLON || LA(2) == T_LBRACE)))) {
|
|
rewind(startOfTypeSpecifier);
|
|
if (! parseClassSpecifier(*decl_specifier_seq_ptr)) {
|
|
_translationUnit->error(startOfTypeSpecifier,
|
|
"wrong type specifier");
|
|
break;
|
|
}
|
|
has_complex_type_specifier = true;
|
|
}
|
|
decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
|
|
has_type_specifier = true;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
DeclaratorListAST *declarator_list = 0,
|
|
**declarator_ptr = &declarator_list;
|
|
|
|
const bool maybeCtor = (LA() == T_LPAREN && named_type_specifier);
|
|
DeclaratorAST *declarator = 0;
|
|
if (! parseInitDeclarator(declarator, acceptStructDeclarator) && maybeCtor) {
|
|
rewind(startOfNamedTypeSpecifier);
|
|
named_type_specifier = 0;
|
|
// pop the named type specifier from the decl-specifier-seq
|
|
SpecifierAST **spec_ptr = &decl_specifier_seq;
|
|
for (; *spec_ptr; spec_ptr = &(*spec_ptr)->next) {
|
|
if (! (*spec_ptr)->next) {
|
|
*spec_ptr = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (! parseInitDeclarator(declarator, acceptStructDeclarator))
|
|
return false;
|
|
}
|
|
|
|
DeclaratorAST *firstDeclarator = declarator;
|
|
|
|
if (declarator) {
|
|
*declarator_ptr = new (_pool) DeclaratorListAST;
|
|
(*declarator_ptr)->declarator = declarator;
|
|
declarator_ptr = &(*declarator_ptr)->next;
|
|
}
|
|
|
|
if (LA() == T_COMMA || LA() == T_SEMICOLON || has_complex_type_specifier) {
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
declarator = 0;
|
|
if (parseInitDeclarator(declarator, acceptStructDeclarator)) {
|
|
*declarator_ptr = new (_pool) DeclaratorListAST;
|
|
(*declarator_ptr)->declarator = declarator;
|
|
declarator_ptr = &(*declarator_ptr)->next;
|
|
}
|
|
}
|
|
SimpleDeclarationAST *ast = new (_pool) SimpleDeclarationAST;
|
|
ast->decl_specifier_seq = decl_specifier_seq;
|
|
ast->declarators = declarator_list;
|
|
match(T_SEMICOLON, &ast->semicolon_token);
|
|
node = ast;
|
|
return true;
|
|
} else if (! _inFunctionBody && declarator && (LA() == T_COLON || LA() == T_LBRACE || LA() == T_TRY)) {
|
|
CtorInitializerAST *ctor_initializer = 0;
|
|
if (LA() == T_COLON)
|
|
parseCtorInitializer(ctor_initializer);
|
|
|
|
if (LA() == T_LBRACE) {
|
|
FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
|
|
ast->decl_specifier_seq = decl_specifier_seq;
|
|
ast->declarator = firstDeclarator;
|
|
ast->ctor_initializer = ctor_initializer;
|
|
parseFunctionBody(ast->function_body);
|
|
node = ast;
|
|
return true; // recognized a function definition.
|
|
} else if (LA() == T_TRY) {
|
|
FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
|
|
ast->decl_specifier_seq = decl_specifier_seq;
|
|
ast->declarator = firstDeclarator;
|
|
ast->ctor_initializer = ctor_initializer;
|
|
parseTryBlockStatement(ast->function_body);
|
|
node = ast;
|
|
return true; // recognized a function definition.
|
|
}
|
|
}
|
|
|
|
_translationUnit->error(cursor(), "unexpected token `%s'", tok().spell());
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseFunctionBody(StatementAST *&node)
|
|
{
|
|
if (_translationUnit->skipFunctionBody()) {
|
|
unsigned token_lbrace = 0;
|
|
match(T_LBRACE, &token_lbrace);
|
|
if (! token_lbrace)
|
|
return false;
|
|
|
|
const Token &tk = _translationUnit->tokenAt(token_lbrace);
|
|
if (tk.close_brace)
|
|
rewind(tk.close_brace);
|
|
unsigned token_rbrace = 0;
|
|
match(T_RBRACE, &token_rbrace);
|
|
return true;
|
|
}
|
|
|
|
_inFunctionBody = true;
|
|
const bool parsed = parseCompoundStatement(node);
|
|
_inFunctionBody = false;
|
|
return parsed;
|
|
}
|
|
|
|
bool Parser::parseTryBlockStatement(StatementAST *&node)
|
|
{
|
|
if (LA() == T_TRY) {
|
|
TryBlockStatementAST *ast = new (_pool) TryBlockStatementAST;
|
|
ast->try_token = consumeToken();
|
|
parseCompoundStatement(ast->statement);
|
|
CatchClauseAST **catch_clause_ptr = &ast->catch_clause_seq;
|
|
while (parseCatchClause(*catch_clause_ptr))
|
|
catch_clause_ptr = &(*catch_clause_ptr)->next;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseCatchClause(CatchClauseAST *&node)
|
|
{
|
|
if (LA() == T_CATCH) {
|
|
CatchClauseAST *ast = new (_pool) CatchClauseAST;
|
|
ast->catch_token = consumeToken();
|
|
match(T_LPAREN, &ast->lparen_token);
|
|
parseExceptionDeclaration(ast->exception_declaration);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
parseCompoundStatement(ast->statement);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseExceptionDeclaration(ExceptionDeclarationAST *&node)
|
|
{
|
|
if (LA() == T_DOT_DOT_DOT) {
|
|
ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST;
|
|
ast->dot_dot_dot_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
SpecifierAST *type_specifier = 0;
|
|
if (parseTypeSpecifier(type_specifier)) {
|
|
ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST;
|
|
ast->type_specifier = type_specifier;
|
|
parseDeclaratorOrAbstractDeclarator(ast->declarator);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseBoolLiteral(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_TRUE || LA() == T_FALSE) {
|
|
BoolLiteralAST *ast = new (_pool) BoolLiteralAST;
|
|
ast->token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseNumericLiteral(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_INT_LITERAL || LA() == T_FLOAT_LITERAL || LA() == T_CHAR_LITERAL) {
|
|
NumericLiteralAST *ast = new (_pool) NumericLiteralAST;
|
|
ast->token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseThisExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_THIS) {
|
|
ThisExpressionAST *ast = new (_pool) ThisExpressionAST;
|
|
ast->this_token = consumeToken();
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parsePrimaryExpression(ExpressionAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_STRING_LITERAL:
|
|
case T_WIDE_STRING_LITERAL:
|
|
return parseStringLiteral(node);
|
|
|
|
case T_INT_LITERAL:
|
|
case T_FLOAT_LITERAL:
|
|
case T_CHAR_LITERAL:
|
|
case T_WIDE_CHAR_LITERAL:
|
|
return parseNumericLiteral(node);
|
|
|
|
case T_TRUE:
|
|
case T_FALSE:
|
|
return parseBoolLiteral(node);
|
|
|
|
case T_THIS:
|
|
return parseThisExpression(node);
|
|
|
|
case T_LPAREN:
|
|
return parseNestedExpression(node);
|
|
|
|
case T_SIGNAL:
|
|
case T_SLOT:
|
|
return parseQtMethod(node);
|
|
|
|
default: {
|
|
unsigned startOfName = cursor();
|
|
NameAST *name = 0;
|
|
if (parseName(name)) {
|
|
if (LA() == T_IDENTIFIER || tok().isLiteral() || (tok().isOperator() && LA() != T_LPAREN &&
|
|
LA() != T_LBRACKET)) {
|
|
rewind(startOfName);
|
|
parseName(name, false);
|
|
}
|
|
// literal
|
|
// identifier <unop> ?
|
|
// identifier <binop>
|
|
// identifier <access>
|
|
// identifier rparen
|
|
// lparen type rparen identifier [[cast-expression]]
|
|
|
|
node = name;
|
|
return true;
|
|
}
|
|
} // default
|
|
|
|
} // switch
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseNestedExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
|
|
if (LA() == T_LBRACE) {
|
|
NestedExpressionAST *ast = new (_pool) NestedExpressionAST;
|
|
ast->lparen_token = lparen_token;
|
|
|
|
// ### ast
|
|
StatementAST *statement = 0;
|
|
parseCompoundStatement(statement);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool previousTemplateArguments = switchTemplateArguments(false);
|
|
|
|
ExpressionAST *expression = 0;
|
|
if (parseExpression(expression) && LA() == T_RPAREN) {
|
|
NestedExpressionAST *ast = new (_pool) NestedExpressionAST;
|
|
ast->lparen_token = lparen_token;
|
|
ast->expression = expression;
|
|
ast->rparen_token = consumeToken();
|
|
node = ast;
|
|
(void) switchTemplateArguments(previousTemplateArguments);
|
|
return true;
|
|
}
|
|
(void) switchTemplateArguments(previousTemplateArguments);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseCppCastExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_DYNAMIC_CAST || LA() == T_STATIC_CAST ||
|
|
LA() == T_REINTERPRET_CAST || LA() == T_CONST_CAST) {
|
|
CppCastExpressionAST *ast = new (_pool) CppCastExpressionAST;
|
|
ast->cast_token = consumeToken();
|
|
match(T_LESS, &ast->less_token);
|
|
parseTypeId(ast->type_id);
|
|
match(T_GREATER, &ast->greater_token);
|
|
match(T_LPAREN, &ast->lparen_token);
|
|
parseExpression(ast->expression);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// typename ::opt nested-name-specifier identifier ( expression-listopt )
|
|
// typename ::opt nested-name-specifier templateopt template-id ( expression-listopt )
|
|
bool Parser::parseTypenameCallExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_TYPENAME) {
|
|
unsigned typename_token = consumeToken();
|
|
NameAST *name = 0;
|
|
if (parseName(name) && LA() == T_LPAREN) {
|
|
TypenameCallExpressionAST *ast = new (_pool) TypenameCallExpressionAST;
|
|
ast->typename_token = typename_token;
|
|
ast->name = name;
|
|
ast->lparen_token = consumeToken();
|
|
parseExpressionList(ast->expression_list);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// typeid ( expression )
|
|
// typeid ( type-id )
|
|
bool Parser::parseTypeidExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_TYPEID) {
|
|
TypeidExpressionAST *ast = new (_pool) TypeidExpressionAST;
|
|
ast->typeid_token = consumeToken();
|
|
if (LA() == T_LPAREN)
|
|
ast->lparen_token = consumeToken();
|
|
unsigned saved = cursor();
|
|
if (! (parseTypeId(ast->expression) && LA() == T_RPAREN)) {
|
|
rewind(saved);
|
|
parseExpression(ast->expression);
|
|
}
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseCorePostfixExpression(ExpressionAST *&node)
|
|
{
|
|
if (parseCppCastExpression(node))
|
|
return true;
|
|
else if (parseTypenameCallExpression(node))
|
|
return true;
|
|
else if (parseTypeidExpression(node))
|
|
return true;
|
|
else {
|
|
unsigned start = cursor();
|
|
SpecifierAST *type_specifier = 0;
|
|
bool blocked = blockErrors(true);
|
|
if (lookAtBuiltinTypeSpecifier() &&
|
|
parseSimpleTypeSpecifier(type_specifier) &&
|
|
LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
ExpressionListAST *expression_list = 0;
|
|
parseExpressionList(expression_list);
|
|
if (LA() == T_RPAREN) {
|
|
unsigned rparen_token = consumeToken();
|
|
TypeConstructorCallAST *ast = new (_pool) TypeConstructorCallAST;
|
|
ast->type_specifier = type_specifier;
|
|
ast->lparen_token = lparen_token;
|
|
ast->expression_list = expression_list;
|
|
ast->rparen_token = rparen_token;
|
|
node = ast;
|
|
blockErrors(blocked);
|
|
return true;
|
|
}
|
|
}
|
|
rewind(start);
|
|
|
|
// look for compound literals
|
|
if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
ExpressionAST *type_id = 0;
|
|
if (parseTypeId(type_id) && LA() == T_RPAREN) {
|
|
unsigned rparen_token = consumeToken();
|
|
if (LA() == T_LBRACE) {
|
|
blockErrors(blocked);
|
|
|
|
CompoundLiteralAST *ast = new (_pool) CompoundLiteralAST;
|
|
ast->lparen_token = lparen_token;
|
|
ast->type_id = type_id;
|
|
ast->rparen_token = rparen_token;
|
|
parseInitializerClause(ast->initializer);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
rewind(start);
|
|
}
|
|
|
|
blockErrors(blocked);
|
|
return parsePrimaryExpression(node);
|
|
}
|
|
}
|
|
|
|
bool Parser::parsePostfixExpression(ExpressionAST *&node)
|
|
{
|
|
if (parseCorePostfixExpression(node)) {
|
|
PostfixAST *postfix_expressions = 0,
|
|
**postfix_ptr = &postfix_expressions;
|
|
while (LA()) {
|
|
if (LA() == T_LPAREN) {
|
|
CallAST *ast = new (_pool) CallAST;
|
|
ast->lparen_token = consumeToken();
|
|
parseExpressionList(ast->expression_list);
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
*postfix_ptr = ast;
|
|
postfix_ptr = &(*postfix_ptr)->next;
|
|
} else if (LA() == T_LBRACKET) {
|
|
ArrayAccessAST *ast = new (_pool) ArrayAccessAST;
|
|
ast->lbracket_token = consumeToken();
|
|
parseExpression(ast->expression);
|
|
match(T_RBRACKET, &ast->rbracket_token);
|
|
*postfix_ptr = ast;
|
|
postfix_ptr = &(*postfix_ptr)->next;
|
|
} else if (LA() == T_PLUS_PLUS || LA() == T_MINUS_MINUS) {
|
|
PostIncrDecrAST *ast = new (_pool) PostIncrDecrAST;
|
|
ast->incr_decr_token = consumeToken();
|
|
*postfix_ptr = ast;
|
|
postfix_ptr = &(*postfix_ptr)->next;
|
|
} else if (LA() == T_DOT || LA() == T_ARROW) {
|
|
MemberAccessAST *ast = new (_pool) MemberAccessAST;
|
|
ast->access_token = consumeToken();
|
|
if (LA() == T_TEMPLATE)
|
|
ast->template_token = consumeToken();
|
|
if (! parseName(ast->member_name))
|
|
_translationUnit->error(cursor(), "expected unqualified-id before token `%s'",
|
|
tok().spell());
|
|
*postfix_ptr = ast;
|
|
postfix_ptr = &(*postfix_ptr)->next;
|
|
} else break;
|
|
} // while
|
|
|
|
if (postfix_expressions) {
|
|
PostfixExpressionAST *ast = new (_pool) PostfixExpressionAST;
|
|
ast->base_expression = node;
|
|
ast->postfix_expressions = postfix_expressions;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseUnaryExpression(ExpressionAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_PLUS_PLUS:
|
|
case T_MINUS_MINUS:
|
|
case T_STAR:
|
|
case T_AMPER:
|
|
case T_PLUS:
|
|
case T_MINUS:
|
|
case T_EXCLAIM: {
|
|
UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
|
|
ast->unary_op_token = consumeToken();
|
|
parseCastExpression(ast->expression);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
case T_TILDE: {
|
|
if (LA(2) == T_IDENTIFIER && LA(3) == T_LPAREN)
|
|
break; // prefer destructor names
|
|
|
|
UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
|
|
ast->unary_op_token = consumeToken();
|
|
parseCastExpression(ast->expression);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
case T_SIZEOF: {
|
|
SizeofExpressionAST *ast = new (_pool) SizeofExpressionAST;
|
|
ast->sizeof_token = consumeToken();
|
|
|
|
if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
if (parseTypeId(ast->expression) && LA() == T_RPAREN) {
|
|
consumeToken();
|
|
node = ast;
|
|
return true;
|
|
} else {
|
|
rewind(lparen_token);
|
|
}
|
|
}
|
|
|
|
parseUnaryExpression(ast->expression);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
} // switch
|
|
|
|
if (LA() == T_NEW || (LA(1) == T_COLON_COLON &&
|
|
LA(2) == T_NEW))
|
|
return parseNewExpression(node);
|
|
else if (LA() == T_DELETE || (LA(1) == T_COLON_COLON &&
|
|
LA(2) == T_DELETE))
|
|
return parseDeleteExpression(node);
|
|
else
|
|
return parsePostfixExpression(node);
|
|
}
|
|
|
|
bool Parser::parseNewExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_NEW || (LA() == T_COLON_COLON && LA(2) == T_NEW)) {
|
|
NewExpressionAST *ast = new (_pool) NewExpressionAST;
|
|
|
|
if (LA() == T_COLON_COLON)
|
|
ast->scope_token = consumeToken();
|
|
|
|
ast->new_token = consumeToken();
|
|
|
|
if (LA() == T_LPAREN) {
|
|
consumeToken();
|
|
parseExpression(ast->expression);
|
|
if (LA() == T_RPAREN)
|
|
consumeToken();
|
|
}
|
|
|
|
if (LA() == T_LPAREN) {
|
|
consumeToken();
|
|
parseTypeId(ast->type_id);
|
|
if (LA() == T_RPAREN)
|
|
consumeToken();
|
|
} else {
|
|
parseNewTypeId(ast->new_type_id);
|
|
}
|
|
|
|
parseNewInitializer(ast->new_initializer);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseNewTypeId(NewTypeIdAST *&node)
|
|
{
|
|
SpecifierAST *typeSpec = 0;
|
|
if (! parseTypeSpecifier(typeSpec))
|
|
return false;
|
|
|
|
NewTypeIdAST *ast = new (_pool) NewTypeIdAST;
|
|
ast->type_specifier = typeSpec;
|
|
parseNewDeclarator(ast->new_declarator);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseNewDeclarator(NewDeclaratorAST *&node)
|
|
{
|
|
NewDeclaratorAST *ast = new (_pool) NewDeclaratorAST;
|
|
|
|
PtrOperatorAST **ptr_operators_tail = &ast->ptr_operators;
|
|
while (parsePtrOperator(*ptr_operators_tail))
|
|
ptr_operators_tail = &(*ptr_operators_tail)->next;
|
|
|
|
while (LA() == T_LBRACKET) { // ### create the AST
|
|
consumeToken();
|
|
ExpressionAST *expression = 0;
|
|
parseExpression(expression);
|
|
unsigned rbracket_token = 0;
|
|
match(T_RBRACKET, &rbracket_token);
|
|
}
|
|
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseNewInitializer(NewInitializerAST *&node)
|
|
{
|
|
if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
ExpressionAST *expression = 0;
|
|
if (LA() == T_RPAREN || parseExpression(expression)) {
|
|
NewInitializerAST *ast = new (_pool) NewInitializerAST;
|
|
ast->lparen_token = lparen_token;
|
|
ast->expression = expression;
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseDeleteExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_DELETE || (LA() == T_COLON_COLON && LA(2) == T_DELETE)) {
|
|
DeleteExpressionAST *ast = new (_pool) DeleteExpressionAST;
|
|
|
|
if (LA() == T_COLON_COLON)
|
|
ast->scope_token = consumeToken();
|
|
|
|
ast->delete_token = consumeToken();
|
|
|
|
if (LA() == T_LBRACKET) {
|
|
ast->lbracket_token = consumeToken();
|
|
match(T_RBRACKET, &ast->rbracket_token);
|
|
}
|
|
|
|
parseCastExpression(ast->expression);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseCastExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = consumeToken();
|
|
ExpressionAST *type_id = 0;
|
|
if (parseTypeId(type_id) && LA() == T_RPAREN) {
|
|
unsigned rparen_token = consumeToken();
|
|
ExpressionAST *expression = 0;
|
|
if (parseCastExpression(expression)) {
|
|
CastExpressionAST *ast = new (_pool) CastExpressionAST;
|
|
ast->lparen_token = lparen_token;
|
|
ast->type_id = type_id;
|
|
ast->rparen_token = rparen_token;
|
|
ast->expression = expression;
|
|
node = ast;
|
|
return true;
|
|
}
|
|
}
|
|
rewind(lparen_token);
|
|
}
|
|
return parseUnaryExpression(node);
|
|
}
|
|
|
|
bool Parser::parsePmExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseCastExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_ARROW_STAR || LA() == T_DOT_STAR) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseCastExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseMultiplicativeExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parsePmExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_STAR || LA() == T_SLASH || LA() == T_PERCENT) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parsePmExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseAdditiveExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseMultiplicativeExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_PLUS || LA() == T_MINUS) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseMultiplicativeExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseShiftExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseAdditiveExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_LESS_LESS || LA() == T_GREATER_GREATER) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseAdditiveExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseRelationalExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseShiftExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_LESS || (LA() == T_GREATER && ! _templateArguments) ||
|
|
LA() == T_LESS_EQUAL || LA() == T_GREATER_EQUAL) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseShiftExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseEqualityExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseRelationalExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_EQUAL_EQUAL || LA() == T_EXCLAIM_EQUAL) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseRelationalExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseAndExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseEqualityExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_AMPER) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseEqualityExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseExclusiveOrExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseAndExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_CARET) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseAndExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseInclusiveOrExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseExclusiveOrExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_PIPE) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseExclusiveOrExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseLogicalAndExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseInclusiveOrExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_AMPER_AMPER) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseInclusiveOrExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseLogicalOrExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseLogicalAndExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_PIPE_PIPE) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseLogicalAndExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseConditionalExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseLogicalOrExpression(node))
|
|
return false;
|
|
|
|
if (LA() != T_QUESTION)
|
|
return true;
|
|
|
|
ConditionalExpressionAST *ast = new (_pool) ConditionalExpressionAST;
|
|
ast->condition = node;
|
|
ast->question_token = consumeToken();
|
|
parseAssignmentExpression(ast->left_expression);
|
|
match(T_COLON, &ast->colon_token);
|
|
parseAssignmentExpression(ast->right_expression);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
|
|
bool Parser::lookAtAssignmentOperator() const
|
|
{
|
|
switch (LA()) {
|
|
case T_EQUAL:
|
|
case T_AMPER_EQUAL:
|
|
case T_CARET_EQUAL:
|
|
case T_SLASH_EQUAL:
|
|
case T_GREATER_GREATER_EQUAL:
|
|
case T_LESS_LESS_EQUAL:
|
|
case T_MINUS_EQUAL:
|
|
case T_PERCENT_EQUAL:
|
|
case T_PIPE_EQUAL:
|
|
case T_PLUS_EQUAL:
|
|
case T_STAR_EQUAL:
|
|
case T_TILDE_EQUAL:
|
|
return true;
|
|
default:
|
|
return false;
|
|
} // switch
|
|
}
|
|
|
|
bool Parser::parseAssignmentExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_THROW)
|
|
return parseThrowExpression(node);
|
|
else if (! parseConditionalExpression(node))
|
|
return false;
|
|
|
|
if (lookAtAssignmentOperator()) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseAssignmentExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseQtMethod(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_SIGNAL || LA() == T_SLOT) {
|
|
QtMethodAST *ast = new (_pool) QtMethodAST;
|
|
ast->method_token = consumeToken();
|
|
match(T_LPAREN, &ast->lparen_token);
|
|
if (! parseDeclarator(ast->declarator))
|
|
_translationUnit->error(cursor(), "expected a function declarator before token `%s'",
|
|
tok().spell());
|
|
match(T_RPAREN, &ast->rparen_token);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::parseConstantExpression(ExpressionAST *&node)
|
|
{
|
|
return parseConditionalExpression(node);
|
|
}
|
|
|
|
bool Parser::parseExpression(ExpressionAST *&node)
|
|
{
|
|
return parseCommaExpression(node);
|
|
}
|
|
|
|
bool Parser::parseCommaExpression(ExpressionAST *&node)
|
|
{
|
|
if (! parseAssignmentExpression(node))
|
|
return false;
|
|
|
|
while (LA() == T_COMMA) {
|
|
unsigned op = consumeToken();
|
|
|
|
ExpressionAST *rightExpr = 0;
|
|
if (! parseAssignmentExpression(rightExpr))
|
|
return false;
|
|
|
|
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
|
|
ast->binary_op_token = op;
|
|
ast->left_expression = node;
|
|
ast->right_expression = rightExpr;
|
|
node = ast;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseThrowExpression(ExpressionAST *&node)
|
|
{
|
|
if (LA() == T_THROW) {
|
|
ThrowExpressionAST *ast = new (_pool) ThrowExpressionAST;
|
|
ast->throw_token = consumeToken();
|
|
parseAssignmentExpression(ast->expression);
|
|
node = ast;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Parser::lookAtObjCSelector() const
|
|
{
|
|
switch (LA()) {
|
|
case T_IDENTIFIER:
|
|
case T_OR:
|
|
case T_AND:
|
|
case T_NOT:
|
|
case T_XOR:
|
|
case T_BITOR:
|
|
case T_COMPL:
|
|
case T_OR_EQ:
|
|
case T_AND_EQ:
|
|
case T_BITAND:
|
|
case T_NOT_EQ:
|
|
case T_XOR_EQ:
|
|
return true;
|
|
|
|
default:
|
|
if (tok().isKeyword())
|
|
return true;
|
|
} // switch
|
|
|
|
return false;
|
|
}
|
|
|
|
// objc-class-declaraton ::= T_AT_CLASS (T_IDENTIFIER @ T_COMMA) T_SEMICOLON
|
|
//
|
|
bool Parser::parseObjCClassDeclaration(DeclarationAST *&)
|
|
{
|
|
if (LA() != T_AT_CLASS)
|
|
return false;
|
|
|
|
/*unsigned objc_class_token = */ consumeToken();
|
|
unsigned identifier_token = 0;
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
while (LA() == T_COMMA) {
|
|
consumeToken(); // skip T_COMMA
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
}
|
|
|
|
unsigned semicolon_token = 0;
|
|
match(T_SEMICOLON, &semicolon_token);
|
|
return true;
|
|
}
|
|
|
|
// objc-interface ::= attribute-specifier-list-opt objc-class-interface
|
|
// objc-interface ::= objc-category-interface
|
|
//
|
|
// objc-class-interface ::= T_AT_INTERFACE T_IDENTIFIER (T_COLON T_IDENTIFIER)?
|
|
// objc-protocol-refs-opt
|
|
// objc-class-instance-variables-opt
|
|
// objc-interface-declaration-list
|
|
// T_AT_END
|
|
//
|
|
// objc-category-interface ::= T_AT_INTERFACE T_IDENTIFIER
|
|
// T_LPAREN T_IDENTIFIER? T_RPAREN
|
|
// objc-protocol-refs-opt
|
|
// objc-interface-declaration-list
|
|
// T_AT_END
|
|
//
|
|
bool Parser::parseObjCInterface(DeclarationAST *&,
|
|
SpecifierAST *attributes)
|
|
{
|
|
if (! attributes && LA() == T___ATTRIBUTE__) {
|
|
SpecifierAST **attr = &attributes;
|
|
while (parseAttributeSpecifier(*attr))
|
|
attr = &(*attr)->next;
|
|
}
|
|
|
|
if (LA() != T_AT_INTERFACE)
|
|
return false;
|
|
|
|
/*unsigned objc_interface_token = */ consumeToken();
|
|
unsigned identifier_token = 0;
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
|
|
if (LA() == T_LPAREN) {
|
|
// a category interface
|
|
|
|
if (attributes)
|
|
_translationUnit->error(attributes->firstToken(),
|
|
"invalid attributes for category interface declaration");
|
|
|
|
unsigned lparen_token = 0, rparen_token = 0;
|
|
match(T_LPAREN, &lparen_token);
|
|
if (LA() == T_IDENTIFIER)
|
|
consumeToken();
|
|
|
|
match(T_RPAREN, &rparen_token);
|
|
|
|
parseObjCProtocolRefs();
|
|
while (parseObjCInterfaceMemberDeclaration()) {
|
|
}
|
|
unsigned objc_end_token = 0;
|
|
match(T_AT_END, &objc_end_token);
|
|
return true;
|
|
}
|
|
|
|
// a class interface declaration
|
|
if (LA() == T_COLON) {
|
|
consumeToken();
|
|
unsigned identifier_token = 0;
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
}
|
|
|
|
parseObjCProtocolRefs();
|
|
parseObjClassInstanceVariables();
|
|
while (parseObjCInterfaceMemberDeclaration()) {
|
|
}
|
|
unsigned objc_end_token = 0;
|
|
match(T_AT_END, &objc_end_token);
|
|
return true;
|
|
}
|
|
|
|
// objc-protocol ::= T_AT_PROTOCOL (T_IDENTIFIER @ T_COMMA) T_SEMICOLON
|
|
//
|
|
bool Parser::parseObjCProtocol(DeclarationAST *&,
|
|
SpecifierAST *attributes)
|
|
{
|
|
if (! attributes && LA() == T___ATTRIBUTE__) {
|
|
SpecifierAST **attr = &attributes;
|
|
while (parseAttributeSpecifier(*attr))
|
|
attr = &(*attr)->next;
|
|
}
|
|
|
|
if (LA() != T_AT_PROTOCOL)
|
|
return false;
|
|
|
|
/*unsigned objc_protocol_token = */ consumeToken();
|
|
unsigned identifier_token = 0;
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
|
|
if (LA() == T_COMMA || LA() == T_SEMICOLON) {
|
|
// a protocol forward declaration
|
|
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
}
|
|
unsigned semicolon_token = 0;
|
|
match(T_SEMICOLON, &semicolon_token);
|
|
return true;
|
|
}
|
|
|
|
// a protocol definition
|
|
parseObjCProtocolRefs();
|
|
|
|
while (parseObjCInterfaceMemberDeclaration()) {
|
|
}
|
|
|
|
unsigned objc_end_token = 0;
|
|
match(T_AT_END, &objc_end_token);
|
|
|
|
return true;
|
|
}
|
|
|
|
// objc-implementation ::= T_AT_IMPLEMENTAION T_IDENTIFIER (T_COLON T_IDENTIFIER)?
|
|
// objc-class-instance-variables-opt
|
|
// objc-implementation ::= T_AT_IMPLEMENTAION T_IDENTIFIER T_LPAREN T_IDENTIFIER T_RPAREN
|
|
//
|
|
bool Parser::parseObjCImplementation(DeclarationAST *&)
|
|
{
|
|
if (LA() != T_AT_IMPLEMENTATION)
|
|
return false;
|
|
|
|
consumeToken();
|
|
|
|
unsigned identifier_token = 0;
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
|
|
if (LA() == T_LPAREN) {
|
|
// a category implementation
|
|
unsigned lparen_token = 0, rparen_token = 0;
|
|
unsigned category_name_token = 0;
|
|
match(T_LPAREN, &lparen_token);
|
|
match(T_IDENTIFIER, &category_name_token);
|
|
match(T_RPAREN, &rparen_token);
|
|
return true;
|
|
}
|
|
|
|
// a class implementation
|
|
if (LA() == T_COLON) {
|
|
consumeToken();
|
|
unsigned super_class_name_token = 0;
|
|
match(T_IDENTIFIER, &super_class_name_token);
|
|
}
|
|
|
|
parseObjClassInstanceVariables();
|
|
return true;
|
|
}
|
|
|
|
// objc-protocol-refs ::= T_LESS (T_IDENTIFIER @ T_COMMA) T_GREATER
|
|
//
|
|
bool Parser::parseObjCProtocolRefs()
|
|
{
|
|
if (LA() != T_LESS)
|
|
return false;
|
|
unsigned less_token = 0, greater_token = 0;
|
|
unsigned identifier_token = 0;
|
|
match(T_LESS, &less_token);
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
}
|
|
match(T_GREATER, &greater_token);
|
|
return true;
|
|
}
|
|
|
|
// objc-class-instance-variables ::= T_LBRACE
|
|
// objc-instance-variable-decl-list-opt
|
|
// T_RBRACE
|
|
//
|
|
bool Parser::parseObjClassInstanceVariables()
|
|
{
|
|
if (LA() != T_LBRACE)
|
|
return false;
|
|
|
|
unsigned lbrace_token = 0, rbrace_token = 0;
|
|
|
|
match(T_LBRACE, &lbrace_token);
|
|
while (LA()) {
|
|
if (LA() == T_RBRACE)
|
|
break;
|
|
|
|
const unsigned start = cursor();
|
|
|
|
DeclarationAST *declaration = 0;
|
|
parseObjCInstanceVariableDeclaration(declaration);
|
|
|
|
if (start == cursor()) {
|
|
// skip stray token.
|
|
_translationUnit->error(cursor(), "skip stray token `%s'", tok().spell());
|
|
consumeToken();
|
|
}
|
|
}
|
|
|
|
match(T_RBRACE, &rbrace_token);
|
|
return true;
|
|
}
|
|
|
|
// objc-interface-declaration ::= T_AT_REQUIRED
|
|
// objc-interface-declaration ::= T_AT_OPTIONAL
|
|
// objc-interface-declaration ::= T_SEMICOLON
|
|
// objc-interface-declaration ::= objc-property-declaration
|
|
// objc-interface-declaration ::= objc-method-prototype
|
|
bool Parser::parseObjCInterfaceMemberDeclaration()
|
|
{
|
|
switch (LA()) {
|
|
case T_AT_END:
|
|
return false;
|
|
|
|
case T_AT_REQUIRED:
|
|
case T_AT_OPTIONAL:
|
|
consumeToken();
|
|
return true;
|
|
|
|
case T_SEMICOLON:
|
|
consumeToken();
|
|
return true;
|
|
|
|
case T_AT_PROPERTY: {
|
|
DeclarationAST *declaration = 0;
|
|
return parseObjCPropertyDeclaration(declaration);
|
|
}
|
|
|
|
case T_PLUS:
|
|
case T_MINUS:
|
|
return parseObjCMethodPrototype();
|
|
|
|
case T_ENUM:
|
|
case T_CLASS:
|
|
case T_STRUCT:
|
|
case T_UNION: {
|
|
DeclarationAST *declaration = 0;
|
|
return parseSimpleDeclaration(declaration, /*accept struct declarators */ true);
|
|
}
|
|
|
|
default: {
|
|
DeclarationAST *declaration = 0;
|
|
return parseSimpleDeclaration(declaration, /*accept struct declarators */ true);
|
|
} // default
|
|
|
|
} // switch
|
|
}
|
|
|
|
// objc-instance-variable-declaration ::= objc-visibility-specifier
|
|
// objc-instance-variable-declaration ::= block-declaration
|
|
//
|
|
bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node)
|
|
{
|
|
switch (LA()) {
|
|
case T_AT_PRIVATE:
|
|
case T_AT_PROTECTED:
|
|
case T_AT_PUBLIC:
|
|
case T_AT_PACKAGE:
|
|
consumeToken();
|
|
return true;
|
|
|
|
default:
|
|
return parseSimpleDeclaration(node, true);
|
|
}
|
|
}
|
|
|
|
// objc-property-declaration ::=
|
|
// T_AT_PROPERTY T_LPAREN (property-attribute @ T_COMMA) T_RPAREN simple-declaration
|
|
//
|
|
bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&, SpecifierAST *)
|
|
{
|
|
if (LA() != T_AT_PROPERTY)
|
|
return false;
|
|
|
|
/*unsigned objc_property_token = */ consumeToken();
|
|
|
|
if (LA() == T_LPAREN) {
|
|
unsigned lparen_token = 0, rparen_token = 0;
|
|
match(T_LPAREN, &lparen_token);
|
|
while (parseObjCPropertyAttribute()) {
|
|
}
|
|
match(T_RPAREN, &rparen_token);
|
|
}
|
|
|
|
DeclarationAST *simple_declaration = 0;
|
|
parseSimpleDeclaration(simple_declaration, /*accept-struct-declarators = */ true);
|
|
return true;
|
|
}
|
|
|
|
// objc-method-prototype ::= (T_PLUS | T_MINUS) objc-method-decl objc-method-attrs-opt
|
|
//
|
|
// objc-method-decl ::= objc-type-name? objc-selector
|
|
// objc-method-decl ::= objc-type-name? objc-keyword-decl-list objc-parmlist-opt
|
|
//
|
|
bool Parser::parseObjCMethodPrototype()
|
|
{
|
|
if (LA() != T_PLUS && LA() != T_MINUS)
|
|
return false;
|
|
|
|
/*unsigned method_type_token = */ consumeToken();
|
|
|
|
parseObjCTypeName();
|
|
|
|
if ((lookAtObjCSelector() && LA(2) == T_COLON) || LA() == T_COLON) {
|
|
while (parseObjCKeywordDeclaration()) {
|
|
}
|
|
|
|
while (LA() == T_COMMA) {
|
|
consumeToken();
|
|
|
|
if (LA() == T_DOT_DOT_DOT) {
|
|
consumeToken();
|
|
break;
|
|
}
|
|
|
|
DeclarationAST *parameter_declaration = 0;
|
|
parseParameterDeclaration(parameter_declaration);
|
|
}
|
|
} else if (lookAtObjCSelector()) {
|
|
parseObjCSelector();
|
|
} else {
|
|
_translationUnit->error(cursor(), "expected a selector");
|
|
}
|
|
|
|
SpecifierAST *attributes = 0, **attr = &attributes;
|
|
while (parseAttributeSpecifier(*attr))
|
|
attr = &(*attr)->next;
|
|
|
|
return true;
|
|
}
|
|
|
|
// objc-property-attribute ::= getter '=' identifier
|
|
// objc-property-attribute ::= setter '=' identifier ':'
|
|
// objc-property-attribute ::= readonly
|
|
// objc-property-attribute ::= readwrite
|
|
// objc-property-attribute ::= assign
|
|
// objc-property-attribute ::= retain
|
|
// objc-property-attribute ::= copy
|
|
// objc-property-attribute ::= nonatomic
|
|
bool Parser::parseObjCPropertyAttribute()
|
|
{
|
|
if (LA() != T_IDENTIFIER)
|
|
return false;
|
|
|
|
unsigned identifier_token = 0;
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
if (LA() == T_EQUAL) {
|
|
consumeToken();
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
if (LA() == T_COLON)
|
|
consumeToken();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// objc-type-name ::= T_LPAREN objc-type-qualifiers-opt type-id T_RPAREN
|
|
//
|
|
bool Parser::parseObjCTypeName()
|
|
{
|
|
if (LA() != T_LPAREN)
|
|
return false;
|
|
|
|
unsigned lparen_token = 0, rparen_token = 0;
|
|
match(T_LPAREN, &lparen_token);
|
|
parseObjCTypeQualifiers();
|
|
ExpressionAST *type_id = 0;
|
|
parseTypeId(type_id);
|
|
match(T_RPAREN, &rparen_token);
|
|
return true;
|
|
}
|
|
|
|
// objc-selector ::= T_IDENTIFIER | keyword
|
|
//
|
|
bool Parser::parseObjCSelector()
|
|
{
|
|
if (! lookAtObjCSelector())
|
|
return false;
|
|
|
|
consumeToken();
|
|
return true;
|
|
}
|
|
|
|
// objc-keyword-decl ::= objc-selector? T_COLON objc-type-name? objc-keyword-attributes-opt T_IDENTIFIER
|
|
//
|
|
bool Parser::parseObjCKeywordDeclaration()
|
|
{
|
|
if (! (LA() == T_COLON || (lookAtObjCSelector() && LA(2) == T_COLON)))
|
|
return false;
|
|
|
|
parseObjCSelector();
|
|
|
|
unsigned colon_token = 0;
|
|
match(T_COLON, &colon_token);
|
|
|
|
parseObjCTypeName();
|
|
|
|
SpecifierAST *attributes = 0, **attr = &attributes;
|
|
while (parseAttributeSpecifier(*attr))
|
|
attr = &(*attr)->next;
|
|
|
|
unsigned identifier_token = 0;
|
|
match(T_IDENTIFIER, &identifier_token);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseObjCTypeQualifiers()
|
|
{
|
|
if (LA() != T_IDENTIFIER)
|
|
return false;
|
|
|
|
Identifier *id = tok().identifier;
|
|
if (! strcmp("in", id->chars()) ||
|
|
! strcmp("out", id->chars()) ||
|
|
! strcmp("inout", id->chars()) ||
|
|
! strcmp("bycopy", id->chars()) ||
|
|
! strcmp("byref", id->chars()) ||
|
|
! strcmp("oneway", id->chars())) {
|
|
consumeToken();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// objc-end: T_AT_END
|
|
bool Parser::parseObjCEnd(DeclarationAST *&)
|
|
{
|
|
if (LA() != T_AT_END)
|
|
return false;
|
|
|
|
consumeToken();
|
|
return true;
|
|
}
|
|
|
|
|
|
CPLUSPLUS_END_NAMESPACE
|