From 9732e0c744e45a67094fc6ce08bdadb1f9a08d4a Mon Sep 17 00:00:00 2001 From: Hugo Lima Date: Mon, 17 Aug 2009 17:32:08 -0300 Subject: The genesis... --- parser/ast.cpp | 33 + parser/ast.h | 879 +++++++++ parser/binder.cpp | 852 +++++++++ parser/binder.h | 125 ++ parser/class_compiler.cpp | 66 + parser/class_compiler.h | 72 + parser/codemodel.cpp | 932 +++++++++ parser/codemodel.h | 838 +++++++++ parser/codemodel_finder.cpp | 98 + parser/codemodel_finder.h | 70 + parser/codemodel_fwd.h | 80 + parser/codemodel_pointer.h | 60 + parser/compiler_utils.cpp | 50 + parser/compiler_utils.h | 47 + parser/control.cpp | 130 ++ parser/control.h | 160 ++ parser/declarator_compiler.cpp | 147 ++ parser/declarator_compiler.h | 96 + parser/default_visitor.cpp | 459 +++++ parser/default_visitor.h | 118 ++ parser/dumptree.cpp | 125 ++ parser/dumptree.h | 46 + parser/lexer.cpp | 1695 +++++++++++++++++ parser/lexer.h | 290 +++ parser/list.cpp | 28 + parser/list.h | 100 + parser/name_compiler.cpp | 134 ++ parser/name_compiler.h | 69 + parser/parser.cpp | 4056 ++++++++++++++++++++++++++++++++++++++++ parser/parser.h | 198 ++ parser/r++.macros | 28 + parser/rpp-allocator.h | 24 + parser/rpp/builtin-macros.cpp | 23 + parser/rpp/pp-cctype.h | 57 + parser/rpp/pp-configuration | 86 + parser/rpp/pp-engine-bits.h | 1252 +++++++++++++ parser/rpp/pp-engine.h | 274 +++ parser/rpp/pp-environment.h | 137 ++ parser/rpp/pp-fwd.h | 39 + parser/rpp/pp-internal.h | 117 ++ parser/rpp/pp-iterator.h | 88 + parser/rpp/pp-macro-expander.h | 351 ++++ parser/rpp/pp-macro.h | 72 + parser/rpp/pp-main.cpp | 295 +++ parser/rpp/pp-qt-configuration | 24 + parser/rpp/pp-scanner.h | 313 ++++ parser/rpp/pp-string.h | 107 ++ parser/rpp/pp-symbol.h | 87 + parser/rpp/pp.h | 91 + parser/rpp/preprocessor.cpp | 158 ++ parser/rpp/preprocessor.h | 66 + parser/rxx_allocator.h | 130 ++ parser/smallobject.cpp | 28 + parser/smallobject.h | 47 + parser/symbol.h | 122 ++ parser/tokens.cpp | 249 +++ parser/tokens.h | 145 ++ parser/type_compiler.cpp | 129 ++ parser/type_compiler.h | 71 + parser/visitor.cpp | 122 ++ parser/visitor.h | 140 ++ 61 files changed, 16925 insertions(+) create mode 100644 parser/ast.cpp create mode 100644 parser/ast.h create mode 100644 parser/binder.cpp create mode 100644 parser/binder.h create mode 100644 parser/class_compiler.cpp create mode 100644 parser/class_compiler.h create mode 100644 parser/codemodel.cpp create mode 100644 parser/codemodel.h create mode 100644 parser/codemodel_finder.cpp create mode 100644 parser/codemodel_finder.h create mode 100644 parser/codemodel_fwd.h create mode 100644 parser/codemodel_pointer.h create mode 100644 parser/compiler_utils.cpp create mode 100644 parser/compiler_utils.h create mode 100644 parser/control.cpp create mode 100644 parser/control.h create mode 100644 parser/declarator_compiler.cpp create mode 100644 parser/declarator_compiler.h create mode 100644 parser/default_visitor.cpp create mode 100644 parser/default_visitor.h create mode 100644 parser/dumptree.cpp create mode 100644 parser/dumptree.h create mode 100644 parser/lexer.cpp create mode 100644 parser/lexer.h create mode 100644 parser/list.cpp create mode 100644 parser/list.h create mode 100644 parser/name_compiler.cpp create mode 100644 parser/name_compiler.h create mode 100644 parser/parser.cpp create mode 100644 parser/parser.h create mode 100644 parser/r++.macros create mode 100644 parser/rpp-allocator.h create mode 100644 parser/rpp/builtin-macros.cpp create mode 100644 parser/rpp/pp-cctype.h create mode 100644 parser/rpp/pp-configuration create mode 100644 parser/rpp/pp-engine-bits.h create mode 100644 parser/rpp/pp-engine.h create mode 100644 parser/rpp/pp-environment.h create mode 100644 parser/rpp/pp-fwd.h create mode 100644 parser/rpp/pp-internal.h create mode 100644 parser/rpp/pp-iterator.h create mode 100644 parser/rpp/pp-macro-expander.h create mode 100644 parser/rpp/pp-macro.h create mode 100644 parser/rpp/pp-main.cpp create mode 100644 parser/rpp/pp-qt-configuration create mode 100644 parser/rpp/pp-scanner.h create mode 100644 parser/rpp/pp-string.h create mode 100644 parser/rpp/pp-symbol.h create mode 100644 parser/rpp/pp.h create mode 100644 parser/rpp/preprocessor.cpp create mode 100644 parser/rpp/preprocessor.h create mode 100644 parser/rxx_allocator.h create mode 100644 parser/smallobject.cpp create mode 100644 parser/smallobject.h create mode 100644 parser/symbol.h create mode 100644 parser/tokens.cpp create mode 100644 parser/tokens.h create mode 100644 parser/type_compiler.cpp create mode 100644 parser/type_compiler.h create mode 100644 parser/visitor.cpp create mode 100644 parser/visitor.h (limited to 'parser') diff --git a/parser/ast.cpp b/parser/ast.cpp new file mode 100644 index 000000000..ff5b7dfc8 --- /dev/null +++ b/parser/ast.cpp @@ -0,0 +1,33 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "ast.h" +#include "lexer.h" + +QString AST::toString(TokenStream *stream) const +{ + const Token &tk = stream->token((int) start_token); + const Token &end_tk = stream->token((int) end_token); + return QString::fromLatin1(tk.text + tk.position, end_tk.position - tk.position); +} diff --git a/parser/ast.h b/parser/ast.h new file mode 100644 index 000000000..aa98ee4db --- /dev/null +++ b/parser/ast.h @@ -0,0 +1,879 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef AST_H +#define AST_H + +#include "smallobject.h" +#include "list.h" + +class QString; + +#define DECLARE_AST_NODE(k) \ + enum { __node_kind = Kind_##k }; + +class TokenStream; + +struct AccessSpecifierAST; +struct AsmDefinitionAST; +struct BaseClauseAST; +struct BaseSpecifierAST; +struct BinaryExpressionAST; +struct CastExpressionAST; +struct ClassMemberAccessAST; +struct ClassSpecifierAST; +struct CompoundStatementAST; +struct ConditionAST; +struct ConditionalExpressionAST; +struct CppCastExpressionAST; +struct CtorInitializerAST; +struct DeclarationAST; +struct DeclarationStatementAST; +struct DeclaratorAST; +struct DeleteExpressionAST; +struct DoStatementAST; +struct ElaboratedTypeSpecifierAST; +struct EnumSpecifierAST; +struct EnumeratorAST; +struct ExceptionSpecificationAST; +struct ExpressionAST; +struct ExpressionOrDeclarationStatementAST; +struct ExpressionStatementAST; +struct ForStatementAST; +struct FunctionCallAST; +struct FunctionDefinitionAST; +struct IfStatementAST; +struct IncrDecrExpressionAST; +struct InitDeclaratorAST; +struct InitializerAST; +struct InitializerClauseAST; +struct LabeledStatementAST; +struct LinkageBodyAST; +struct LinkageSpecificationAST; +struct MemInitializerAST; +struct NameAST; +struct NamespaceAST; +struct NamespaceAliasDefinitionAST; +struct NewDeclaratorAST; +struct NewExpressionAST; +struct NewInitializerAST; +struct NewTypeIdAST; +struct OperatorAST; +struct OperatorFunctionIdAST; +struct ParameterDeclarationAST; +struct ParameterDeclarationClauseAST; +struct PostfixExpressionAST; +struct PrimaryExpressionAST; +struct PtrOperatorAST; +struct PtrToMemberAST; +struct ReturnStatementAST; +struct SimpleDeclarationAST; +struct SimpleTypeSpecifierAST; +struct SizeofExpressionAST; +struct StatementAST; +struct StringLiteralAST; +struct SubscriptExpressionAST; +struct SwitchStatementAST; +struct TemplateArgumentAST; +struct TemplateDeclarationAST; +struct TemplateParameterAST; +struct ThrowExpressionAST; +struct TranslationUnitAST; +struct TryBlockStatementAST; +struct TypeIdAST; +struct TypeIdentificationAST; +struct TypeParameterAST; +struct TypeSpecifierAST; +struct TypedefAST; +struct UnaryExpressionAST; +struct UnqualifiedNameAST; +struct UsingAST; +struct UsingDirectiveAST; +struct WhileStatementAST; +struct WinDeclSpecAST; +struct QPropertyAST; +struct QEnumsAST; + +struct AST +{ + enum NODE_KIND { + Kind_UNKNOWN = 0, + + Kind_AccessSpecifier, + Kind_AsmDefinition, + Kind_BaseClause, + Kind_BaseSpecifier, + Kind_BinaryExpression, + Kind_CastExpression, + Kind_ClassMemberAccess, + Kind_ClassSpecifier, + Kind_CompoundStatement, + Kind_Condition, + Kind_ConditionalExpression, + Kind_CppCastExpression, + Kind_CtorInitializer, + Kind_DeclarationStatement, + Kind_Declarator, + Kind_DeleteExpression, + Kind_DoStatement, + Kind_ElaboratedTypeSpecifier, + Kind_EnumSpecifier, + Kind_Enumerator, + Kind_ExceptionSpecification, + Kind_ExpressionOrDeclarationStatement, + Kind_ExpressionStatement, + Kind_ForStatement, + Kind_FunctionCall, + Kind_FunctionDefinition, + Kind_IfStatement, + Kind_IncrDecrExpression, + Kind_InitDeclarator, + Kind_Initializer, + Kind_InitializerClause, + Kind_LabeledStatement, + Kind_LinkageBody, + Kind_LinkageSpecification, + Kind_MemInitializer, + Kind_Name, + Kind_Namespace, + Kind_NamespaceAliasDefinition, + Kind_NewDeclarator, + Kind_NewExpression, + Kind_NewInitializer, + Kind_NewTypeId, + Kind_Operator, + Kind_OperatorFunctionId, + Kind_ParameterDeclaration, + Kind_ParameterDeclarationClause, + Kind_PostfixExpression, + Kind_PrimaryExpression, + Kind_PtrOperator, + Kind_PtrToMember, + Kind_ReturnStatement, + Kind_SimpleDeclaration, + Kind_SimpleTypeSpecifier, + Kind_SizeofExpression, + Kind_StringLiteral, + Kind_SubscriptExpression, + Kind_SwitchStatement, + Kind_TemplateArgument, + Kind_TemplateDeclaration, + Kind_TemplateParameter, + Kind_ThrowExpression, + Kind_TranslationUnit, + Kind_TryBlockStatement, + Kind_TypeId, + Kind_TypeIdentification, + Kind_TypeParameter, + Kind_Typedef, + Kind_UnaryExpression, + Kind_UnqualifiedName, + Kind_Using, + Kind_UsingDirective, + Kind_WhileStatement, + Kind_WinDeclSpec, + Kind_QPropertyAST, + Kind_ForwardDeclarationSpecifier, + Kind_QEnumsAST, + + NODE_KIND_COUNT + }; + + QString toString(TokenStream *stream) const; + + int kind; + + std::size_t start_token; + std::size_t end_token; +}; + +struct TypeSpecifierAST: public AST +{ + const ListNode *cv; +}; + +struct StatementAST: public AST +{ +}; + +struct ExpressionAST: public AST +{ +}; + +struct DeclarationAST: public AST +{ +}; + +struct AccessSpecifierAST: public DeclarationAST +{ + DECLARE_AST_NODE(AccessSpecifier) + + const ListNode *specs; +}; + +struct AsmDefinitionAST: public DeclarationAST +{ + DECLARE_AST_NODE(AsmDefinition) + + const ListNode *cv; +}; + +struct BaseClauseAST: public AST +{ // ### kill me + DECLARE_AST_NODE(BaseClause) + + const ListNode *base_specifiers; +}; + +struct BaseSpecifierAST: public AST +{ + DECLARE_AST_NODE(BaseSpecifier) + + std::size_t virt; + std::size_t access_specifier; + NameAST *name; +}; + +struct BinaryExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(BinaryExpression) + + std::size_t op; + ExpressionAST *left_expression; + ExpressionAST *right_expression; +}; + +struct CastExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(CastExpression) + + TypeIdAST *type_id; + ExpressionAST *expression; +}; + +struct ClassMemberAccessAST: public ExpressionAST +{ + DECLARE_AST_NODE(ClassMemberAccess) + + std::size_t op; + NameAST *name; +}; + +struct ClassSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(ClassSpecifier) + + WinDeclSpecAST *win_decl_specifiers; + std::size_t class_key; + NameAST *name; + BaseClauseAST *base_clause; + const ListNode *member_specs; +}; + +struct ForwardDeclarationSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(ForwardDeclarationSpecifier) + + std::size_t class_key; + NameAST *name; + BaseClauseAST *base_clause; +}; + +struct CompoundStatementAST: public StatementAST +{ + DECLARE_AST_NODE(CompoundStatement) + + const ListNode *statements; +}; + +struct ConditionAST: public AST +{ + DECLARE_AST_NODE(Condition) + + TypeSpecifierAST *type_specifier; + DeclaratorAST *declarator; + ExpressionAST *expression; +}; + +struct ConditionalExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(ConditionalExpression) + + ExpressionAST *condition; + ExpressionAST *left_expression; + ExpressionAST *right_expression; +}; + +struct CppCastExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(CppCastExpression) + + std::size_t op; + TypeIdAST *type_id; + ExpressionAST *expression; + const ListNode *sub_expressions; +}; + +struct CtorInitializerAST: public AST +{ + DECLARE_AST_NODE(CtorInitializer) + + std::size_t colon; + const ListNode *member_initializers; +}; + +struct DeclarationStatementAST: public StatementAST +{ + DECLARE_AST_NODE(DeclarationStatement) + + DeclarationAST *declaration; +}; + +struct DeclaratorAST: public AST +{ + DECLARE_AST_NODE(Declarator) + + const ListNode *ptr_ops; + DeclaratorAST *sub_declarator; + NameAST *id; + ExpressionAST *bit_expression; + const ListNode *array_dimensions; + ParameterDeclarationClauseAST *parameter_declaration_clause; + const ListNode *fun_cv; + ExceptionSpecificationAST *exception_spec; +}; + +struct DeleteExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(DeleteExpression) + + std::size_t scope_token; + std::size_t delete_token; + std::size_t lbracket_token; + std::size_t rbracket_token; + ExpressionAST *expression; +}; + +struct DoStatementAST: public StatementAST +{ + DECLARE_AST_NODE(DoStatement) + + StatementAST *statement; + ExpressionAST *expression; +}; + +struct ElaboratedTypeSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(ElaboratedTypeSpecifier) + + std::size_t type; + NameAST *name; +}; + +struct EnumSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(EnumSpecifier) + + NameAST *name; + const ListNode *enumerators; +}; + +struct EnumeratorAST: public AST +{ + DECLARE_AST_NODE(Enumerator) + + std::size_t id; + ExpressionAST *expression; +}; + +struct ExceptionSpecificationAST: public AST +{ + DECLARE_AST_NODE(ExceptionSpecification) + + std::size_t ellipsis; + const ListNode *type_ids; +}; + +struct ExpressionOrDeclarationStatementAST: public StatementAST +{ + DECLARE_AST_NODE(ExpressionOrDeclarationStatement) + + StatementAST *expression; + StatementAST *declaration; +}; + +struct ExpressionStatementAST: public StatementAST +{ + DECLARE_AST_NODE(ExpressionStatement) + + ExpressionAST *expression; +}; + +struct FunctionCallAST: public ExpressionAST +{ + DECLARE_AST_NODE(FunctionCall) + + ExpressionAST *arguments; +}; + +struct FunctionDefinitionAST: public DeclarationAST +{ + DECLARE_AST_NODE(FunctionDefinition) + + const ListNode *storage_specifiers; + const ListNode *function_specifiers; + TypeSpecifierAST *type_specifier; + InitDeclaratorAST *init_declarator; + StatementAST *function_body; + WinDeclSpecAST *win_decl_specifiers; +}; + +struct ForStatementAST: public StatementAST +{ + DECLARE_AST_NODE(ForStatement) + + StatementAST *init_statement; + ConditionAST *condition; + ExpressionAST *expression; + StatementAST *statement; +}; + +struct IfStatementAST: public StatementAST +{ + DECLARE_AST_NODE(IfStatement) + + ConditionAST *condition; + StatementAST *statement; + StatementAST *else_statement; +}; + +struct IncrDecrExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(IncrDecrExpression) + + std::size_t op; +}; + +struct InitDeclaratorAST: public AST +{ + DECLARE_AST_NODE(InitDeclarator) + + DeclaratorAST *declarator; + InitializerAST *initializer; +}; + +struct InitializerAST: public AST +{ + DECLARE_AST_NODE(Initializer) + + InitializerClauseAST *initializer_clause; + ExpressionAST *expression; +}; + +struct InitializerClauseAST: public AST +{ + DECLARE_AST_NODE(InitializerClause) + + ExpressionAST *expression; +}; + +struct LabeledStatementAST: public StatementAST +{ + DECLARE_AST_NODE(LabeledStatement) +}; + +struct LinkageBodyAST: public AST +{ + DECLARE_AST_NODE(LinkageBody) + + const ListNode *declarations; +}; + +struct LinkageSpecificationAST: public DeclarationAST +{ + DECLARE_AST_NODE(LinkageSpecification) + + std::size_t extern_type; + LinkageBodyAST *linkage_body; + DeclarationAST *declaration; +}; + +struct MemInitializerAST: public AST +{ + DECLARE_AST_NODE(MemInitializer) + + NameAST *initializer_id; + ExpressionAST *expression; +}; + +struct NameAST: public AST +{ + DECLARE_AST_NODE(Name) + + bool global; + const ListNode *qualified_names; + UnqualifiedNameAST *unqualified_name; +}; + +struct NamespaceAST: public DeclarationAST +{ + DECLARE_AST_NODE(Namespace) + + std::size_t namespace_name; + LinkageBodyAST *linkage_body; +}; + +struct NamespaceAliasDefinitionAST: public DeclarationAST +{ + DECLARE_AST_NODE(NamespaceAliasDefinition) + + std::size_t namespace_name; + NameAST *alias_name; +}; + +struct NewDeclaratorAST: public AST +{ + DECLARE_AST_NODE(NewDeclarator) + + PtrOperatorAST *ptr_op; + NewDeclaratorAST *sub_declarator; + const ListNode *expressions; +}; + +struct NewExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(NewExpression) + + std::size_t scope_token; + std::size_t new_token; + ExpressionAST *expression; + TypeIdAST *type_id; + NewTypeIdAST *new_type_id; + NewInitializerAST *new_initializer; +}; + +struct NewInitializerAST: public AST +{ + DECLARE_AST_NODE(NewInitializer) + + ExpressionAST *expression; +}; + +struct NewTypeIdAST: public AST +{ + DECLARE_AST_NODE(NewTypeId) + + TypeSpecifierAST *type_specifier; + NewInitializerAST *new_initializer; + NewDeclaratorAST *new_declarator; +}; + +struct OperatorAST: public AST +{ + DECLARE_AST_NODE(Operator) + + std::size_t op; + std::size_t open; + std::size_t close; +}; + +struct OperatorFunctionIdAST: public AST +{ + DECLARE_AST_NODE(OperatorFunctionId) + + OperatorAST *op; + TypeSpecifierAST *type_specifier; + const ListNode *ptr_ops; +}; + +struct ParameterDeclarationAST: public AST +{ + DECLARE_AST_NODE(ParameterDeclaration) + + TypeSpecifierAST *type_specifier; + DeclaratorAST *declarator; + ExpressionAST *expression; +}; + +struct ParameterDeclarationClauseAST: public AST +{ + DECLARE_AST_NODE(ParameterDeclarationClause) + + const ListNode *parameter_declarations; + std::size_t ellipsis; +}; + +struct PostfixExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(PostfixExpression) + + TypeSpecifierAST *type_specifier; + ExpressionAST *expression; + const ListNode *sub_expressions; +}; + +struct PrimaryExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(PrimaryExpression) + + StringLiteralAST *literal; + std::size_t token; + StatementAST *expression_statement; + ExpressionAST *sub_expression; + NameAST *name; +}; + +struct PtrOperatorAST: public AST +{ + DECLARE_AST_NODE(PtrOperator) + + const ListNode *cv; + std::size_t op; + PtrToMemberAST *mem_ptr; +}; + +struct PtrToMemberAST: public AST +{ + DECLARE_AST_NODE(PtrToMember) +}; + +struct ReturnStatementAST: public StatementAST +{ + DECLARE_AST_NODE(ReturnStatement) + + ExpressionAST *expression; +}; + +struct SimpleDeclarationAST: public DeclarationAST +{ + DECLARE_AST_NODE(SimpleDeclaration) + + const ListNode *storage_specifiers; + const ListNode *function_specifiers; + TypeSpecifierAST *type_specifier; + const ListNode *init_declarators; + WinDeclSpecAST *win_decl_specifiers; +}; + +struct SimpleTypeSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(SimpleTypeSpecifier) + + const ListNode *integrals; + std::size_t type_of; + TypeIdAST *type_id; + ExpressionAST *expression; + NameAST *name; +}; + +struct SizeofExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(SizeofExpression) + + std::size_t sizeof_token; + TypeIdAST *type_id; + ExpressionAST *expression; +}; + +struct StringLiteralAST: public AST +{ + DECLARE_AST_NODE(StringLiteral) + + const ListNode *literals; +}; + +struct SubscriptExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(SubscriptExpression) + + ExpressionAST *subscript; +}; + +struct SwitchStatementAST: public StatementAST +{ + DECLARE_AST_NODE(SwitchStatement) + + ConditionAST *condition; + StatementAST *statement; +}; + +struct TemplateArgumentAST: public AST +{ + DECLARE_AST_NODE(TemplateArgument) + + TypeIdAST *type_id; + ExpressionAST *expression; +}; + +struct TemplateDeclarationAST: public DeclarationAST +{ + DECLARE_AST_NODE(TemplateDeclaration) + + std::size_t exported; + const ListNode *template_parameters; + DeclarationAST* declaration; +}; + +struct TemplateParameterAST: public AST +{ + DECLARE_AST_NODE(TemplateParameter) + + TypeParameterAST *type_parameter; + ParameterDeclarationAST *parameter_declaration; +}; + +struct ThrowExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(ThrowExpression) + + std::size_t throw_token; + ExpressionAST *expression; +}; + +struct TranslationUnitAST: public AST +{ + DECLARE_AST_NODE(TranslationUnit) + + const ListNode *declarations; +}; + +struct TryBlockStatementAST: public StatementAST +{ + DECLARE_AST_NODE(TryBlockStatement) +}; + +struct TypeIdAST: public AST +{ + DECLARE_AST_NODE(TypeId) + + TypeSpecifierAST *type_specifier; + DeclaratorAST *declarator; +}; + +struct TypeIdentificationAST: public ExpressionAST +{ + DECLARE_AST_NODE(TypeIdentification) + + std::size_t typename_token; + NameAST *name; + ExpressionAST *expression; +}; + +struct TypeParameterAST: public AST +{ + DECLARE_AST_NODE(TypeParameter) + + std::size_t type; + NameAST *name; + TypeIdAST *type_id; + const ListNode *template_parameters; + NameAST *template_name; +}; + +struct TypedefAST: public DeclarationAST +{ + DECLARE_AST_NODE(Typedef) + + TypeSpecifierAST *type_specifier; + const ListNode *init_declarators; +}; + +struct UnaryExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(UnaryExpression) + + std::size_t op; + ExpressionAST *expression; +}; + +struct UnqualifiedNameAST: public AST +{ + DECLARE_AST_NODE(UnqualifiedName) + + std::size_t tilde; + std::size_t id; + OperatorFunctionIdAST *operator_id; + const ListNode *template_arguments; +}; + +struct UsingAST: public DeclarationAST +{ + DECLARE_AST_NODE(Using) + + std::size_t type_name; + NameAST *name; +}; + +struct UsingDirectiveAST: public DeclarationAST +{ + DECLARE_AST_NODE(UsingDirective) + + NameAST *name; +}; + +struct WhileStatementAST: public StatementAST +{ + DECLARE_AST_NODE(WhileStatement) + + ConditionAST *condition; + StatementAST *statement; +}; + +struct WinDeclSpecAST: public AST +{ + DECLARE_AST_NODE(WinDeclSpec) + + std::size_t specifier; + std::size_t modifier; +}; + +struct QPropertyAST : public DeclarationAST +{ + DECLARE_AST_NODE(QPropertyAST) +}; + +struct QEnumsAST : public DeclarationAST +{ + DECLARE_AST_NODE(QEnumsAST) +}; + +template +_Tp *CreateNode(pool *memory_pool) +{ + _Tp *node = reinterpret_cast<_Tp*>(memory_pool->allocate(sizeof(_Tp))); + node->kind = _Tp::__node_kind; + return node; +} + +template +_Tp ast_cast(AST *item) +{ + if (item && static_cast<_Tp>(0)->__node_kind == item->kind) + return static_cast<_Tp>(item); + + return 0; +} + +#endif // AST_H diff --git a/parser/binder.cpp b/parser/binder.cpp new file mode 100644 index 000000000..8b6c4c024 --- /dev/null +++ b/parser/binder.cpp @@ -0,0 +1,852 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "binder.h" +#include "lexer.h" +#include "control.h" +#include "symbol.h" +#include "codemodel_finder.h" +#include "class_compiler.h" +#include "compiler_utils.h" +#include "tokens.h" +#include "dumptree.h" + +#include +#include + +Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__control) + : _M_model(__model), + _M_location(__location), + _M_token_stream(&_M_location.token_stream), + _M_control(__control), + _M_current_function_type(CodeModel::Normal), + type_cc(this), + name_cc(this), + decl_cc(this) +{ + _M_qualified_types["char"] = QString(); + _M_qualified_types["double"] = QString(); + _M_qualified_types["float"] = QString(); + _M_qualified_types["int"] = QString(); + _M_qualified_types["long"] = QString(); + _M_qualified_types["short"] = QString(); + _M_qualified_types["void"] = QString(); +} + +Binder::~Binder() +{ +} + +FileModelItem Binder::run(AST *node) +{ + FileModelItem old = _M_current_file; + _M_current_access = CodeModel::Public; + + _M_current_file = model()->create(); + updateItemPosition(_M_current_file->toItem(), node); + visit(node); + FileModelItem result = _M_current_file; + + _M_current_file = old; // restore + + return result; +} + +ScopeModelItem Binder::currentScope() +{ + if (_M_current_class) + return model_static_cast(_M_current_class); + else if (_M_current_namespace) + return model_static_cast(_M_current_namespace); + + return model_static_cast(_M_current_file); +} + +TemplateParameterList Binder::changeTemplateParameters(TemplateParameterList templateParameters) +{ + TemplateParameterList old = _M_current_template_parameters; + _M_current_template_parameters = templateParameters; + return old; +} + +CodeModel::FunctionType Binder::changeCurrentFunctionType(CodeModel::FunctionType functionType) +{ + CodeModel::FunctionType old = _M_current_function_type; + _M_current_function_type = functionType; + return old; +} + +CodeModel::AccessPolicy Binder::changeCurrentAccess(CodeModel::AccessPolicy accessPolicy) +{ + CodeModel::AccessPolicy old = _M_current_access; + _M_current_access = accessPolicy; + return old; +} + +NamespaceModelItem Binder::changeCurrentNamespace(NamespaceModelItem item) +{ + NamespaceModelItem old = _M_current_namespace; + _M_current_namespace = item; + return old; +} + +ClassModelItem Binder::changeCurrentClass(ClassModelItem item) +{ + ClassModelItem old = _M_current_class; + _M_current_class = item; + return old; +} + +FunctionDefinitionModelItem Binder::changeCurrentFunction(FunctionDefinitionModelItem item) +{ + FunctionDefinitionModelItem old = _M_current_function; + _M_current_function = item; + return old; +} + +int Binder::decode_token(std::size_t index) const +{ + return _M_token_stream->kind(index); +} + +CodeModel::AccessPolicy Binder::decode_access_policy(std::size_t index) const +{ + switch (decode_token(index)) { + case Token_class: + return CodeModel::Private; + + case Token_struct: + case Token_union: + return CodeModel::Public; + + default: + return CodeModel::Public; + } +} + +CodeModel::ClassType Binder::decode_class_type(std::size_t index) const +{ + switch (decode_token(index)) { + case Token_class: + return CodeModel::Class; + case Token_struct: + return CodeModel::Struct; + case Token_union: + return CodeModel::Union; + default: + std::cerr << "** WARNING unrecognized class type" << std::endl; + } + return CodeModel::Class; +} + +const NameSymbol *Binder::decode_symbol(std::size_t index) const +{ + return _M_token_stream->symbol(index); +} + +void Binder::visitAccessSpecifier(AccessSpecifierAST *node) +{ + const ListNode *it = node->specs; + if (!it) + return; + + it = it->toFront(); + const ListNode *end = it; + + do { + switch (decode_token(it->element)) { + default: + break; + + case Token_public: + changeCurrentAccess(CodeModel::Public); + changeCurrentFunctionType(CodeModel::Normal); + break; + case Token_protected: + changeCurrentAccess(CodeModel::Protected); + changeCurrentFunctionType(CodeModel::Normal); + break; + case Token_private: + changeCurrentAccess(CodeModel::Private); + changeCurrentFunctionType(CodeModel::Normal); + break; + case Token_signals: + changeCurrentAccess(CodeModel::Protected); + changeCurrentFunctionType(CodeModel::Signal); + break; + case Token_slots: + changeCurrentFunctionType(CodeModel::Slot); + break; + } + it = it->next; + } while (it != end); +} + +void Binder::visitSimpleDeclaration(SimpleDeclarationAST *node) +{ + visit(node->type_specifier); + + if (const ListNode *it = node->init_declarators) { + it = it->toFront(); + const ListNode *end = it; + do { + InitDeclaratorAST *init_declarator = it->element; + declare_symbol(node, init_declarator); + it = it->next; + } while (it != end); + } +} + +void Binder::declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator) +{ + DeclaratorAST *declarator = init_declarator->declarator; + + while (declarator && declarator->sub_declarator) + declarator = declarator->sub_declarator; + + NameAST *id = declarator->id; + if (!declarator->id) { + std::cerr << "** WARNING expected a declarator id" << std::endl; + return; + } + + CodeModelFinder finder(model(), this); + ScopeModelItem symbolScope = finder.resolveScope(id, currentScope()); + if (!symbolScope) { + name_cc.run(id); + std::cerr << "** WARNING scope not found for symbol:" + << qPrintable(name_cc.name()) << std::endl; + return; + } + + decl_cc.run(declarator); + + if (decl_cc.isFunction()) { + name_cc.run(id->unqualified_name); + + FunctionModelItem fun = model()->create(); + updateItemPosition(fun->toItem(), node); + fun->setAccessPolicy(_M_current_access); + fun->setFunctionType(_M_current_function_type); + fun->setName(name_cc.name()); + fun->setAbstract(init_declarator->initializer != 0); + fun->setConstant(declarator->fun_cv != 0); + fun->setTemplateParameters(_M_current_template_parameters); + applyStorageSpecifiers(node->storage_specifiers, model_static_cast(fun)); + applyFunctionSpecifiers(node->function_specifiers, fun); + + // build the type + TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier, + declarator, + this); + + fun->setType(qualifyType(typeInfo, symbolScope->qualifiedName())); + + + fun->setVariadics(decl_cc.isVariadics()); + + // ... and the signature + foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) { + ArgumentModelItem arg = model()->create(); + arg->setType(qualifyType(p.type, _M_context)); + arg->setName(p.name); + arg->setDefaultValue(p.defaultValue); + if (p.defaultValue) + arg->setDefaultValueExpression(p.defaultValueExpression); + fun->addArgument(arg); + } + + fun->setScope(symbolScope->qualifiedName()); + symbolScope->addFunction(fun); + } else { + VariableModelItem var = model()->create(); + updateItemPosition(var->toItem(), node); + var->setTemplateParameters(_M_current_template_parameters); + var->setAccessPolicy(_M_current_access); + name_cc.run(id->unqualified_name); + var->setName(name_cc.name()); + TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier, + declarator, + this); + if (declarator != init_declarator->declarator + && init_declarator->declarator->parameter_declaration_clause) { + typeInfo.setFunctionPointer(true); + decl_cc.run(init_declarator->declarator); + foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) + typeInfo.addArgument(p.type); + } + + var->setType(qualifyType(typeInfo, _M_context)); + applyStorageSpecifiers(node->storage_specifiers, model_static_cast(var)); + + var->setScope(symbolScope->qualifiedName()); + symbolScope->addVariable(var); + } +} + +void Binder::visitFunctionDefinition(FunctionDefinitionAST *node) +{ + Q_ASSERT(node->init_declarator); + + ScopeModelItem scope = currentScope(); + + InitDeclaratorAST *init_declarator = node->init_declarator; + DeclaratorAST *declarator = init_declarator->declarator; + + // in the case of "void (func)()" or "void ((func))()" we need to + // skip to the inner most. This is in line with how the declarator + // node is generated in 'parser.cpp' + while (declarator && declarator->sub_declarator) + declarator = declarator->sub_declarator; + Q_ASSERT(declarator->id); + + CodeModelFinder finder(model(), this); + + ScopeModelItem functionScope = finder.resolveScope(declarator->id, scope); + if (!functionScope) { + name_cc.run(declarator->id); + std::cerr << "** WARNING scope not found for function definition:" + << qPrintable(name_cc.name()) << std::endl + << "\tdefinition *ignored*" + << std::endl; + return; + } + + decl_cc.run(declarator); + + Q_ASSERT(!decl_cc.id().isEmpty()); + + FunctionDefinitionModelItem + old = changeCurrentFunction(_M_model->create()); + _M_current_function->setScope(functionScope->qualifiedName()); + updateItemPosition(_M_current_function->toItem(), node); + + Q_ASSERT(declarator->id->unqualified_name); + name_cc.run(declarator->id->unqualified_name); + QString unqualified_name = name_cc.name(); + + _M_current_function->setName(unqualified_name); + TypeInfo tmp_type = CompilerUtils::typeDescription(node->type_specifier, + declarator, this); + + _M_current_function->setType(qualifyType(tmp_type, _M_context)); + _M_current_function->setAccessPolicy(_M_current_access); + _M_current_function->setFunctionType(_M_current_function_type); + _M_current_function->setConstant(declarator->fun_cv); + _M_current_function->setTemplateParameters(_M_current_template_parameters); + + applyStorageSpecifiers(node->storage_specifiers, + model_static_cast(_M_current_function)); + applyFunctionSpecifiers(node->function_specifiers, + model_static_cast(_M_current_function)); + + _M_current_function->setVariadics(decl_cc.isVariadics()); + + foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) { + ArgumentModelItem arg = model()->create(); + arg->setType(qualifyType(p.type, functionScope->qualifiedName())); + arg->setName(p.name); + arg->setDefaultValue(p.defaultValue); + if (p.defaultValue) + arg->setDefaultValueExpression(p.defaultValueExpression); + _M_current_function->addArgument(arg); + } + + functionScope->addFunctionDefinition(_M_current_function); + + FunctionModelItem prototype = model_static_cast(_M_current_function); + FunctionModelItem declared = functionScope->declaredFunction(prototype); + + // try to find a function declaration for this definition.. + if (!declared) { + functionScope->addFunction(prototype); + } else { + applyFunctionSpecifiers(node->function_specifiers, declared); + + // fix the function type and the access policy + _M_current_function->setAccessPolicy(declared->accessPolicy()); + _M_current_function->setFunctionType(declared->functionType()); + } + + changeCurrentFunction(old); +} + +void Binder::visitTemplateDeclaration(TemplateDeclarationAST *node) +{ + const ListNode *it = node->template_parameters; + if (!it) { + // QtScript: we want to visit the declaration still, so that + // e.g. QMetaTypeId is added to the code model + visit(node->declaration); + return; + } + + TemplateParameterList savedTemplateParameters = changeTemplateParameters(TemplateParameterList()); + + it = it->toFront(); + const ListNode *end = it; + + TemplateParameterList templateParameters; + do { + TemplateParameterAST *parameter = it->element; + TypeParameterAST *type_parameter = parameter->type_parameter; + + NameAST *name; + if (!type_parameter) { + // A hacky hack to work around missing support for parameter declarations in + // templates. We just need the to get the name of the variable, since we + // aren't actually compiling these anyway. We are still not supporting much + // more, but we are refusing to fail for a few more declarations + if (!parameter->parameter_declaration || + !parameter->parameter_declaration->declarator || + !parameter->parameter_declaration->declarator->id) { + + /*std::cerr << "** WARNING template declaration not supported ``"; + Token const &tk = _M_token_stream->token ((int) node->start_token); + Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token); + + std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''" + << std::endl << std::endl;*/ + + changeTemplateParameters(savedTemplateParameters); + return; + + } + + name = parameter->parameter_declaration->declarator->id; + } else { + int tk = decode_token(type_parameter->type); + if (tk != Token_typename && tk != Token_class) { + /*std::cerr << "** WARNING template declaration not supported ``"; + Token const &tk = _M_token_stream->token ((int) node->start_token); + Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token); + + std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''" + << std::endl << std::endl;*/ + + changeTemplateParameters(savedTemplateParameters); + return; + } + assert(tk == Token_typename || tk == Token_class); + + name = type_parameter->name; + } + + TemplateParameterModelItem p = model()->create(); + name_cc.run(name); + p->setName(name_cc.name()); + + _M_current_template_parameters.append(p); + it = it->next; + } while (it != end); + + visit(node->declaration); + + changeTemplateParameters(savedTemplateParameters); +} + +void Binder::visitTypedef(TypedefAST *node) +{ + const ListNode *it = node->init_declarators; + if (!it) + return; + + it = it->toFront(); + const ListNode *end = it; + + do { + InitDeclaratorAST *init_declarator = it->element; + it = it->next; + + Q_ASSERT(init_declarator->declarator); + + // the name + decl_cc.run(init_declarator->declarator); + QString alias_name = decl_cc.id(); + + if (alias_name.isEmpty()) { + std::cerr << "** WARNING anonymous typedef not supported! ``"; + Token const &tk = _M_token_stream->token((int) node->start_token); + Token const &end_tk = _M_token_stream->token((int) node->end_token); + + std::cerr << std::string(&tk.text[tk.position], end_tk.position - tk.position) << "''" + << std::endl << std::endl; + continue; + } + + // build the type + TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier, + init_declarator->declarator, + this); + DeclaratorAST *decl = init_declarator->declarator; + while (decl && decl->sub_declarator) + decl = decl->sub_declarator; + + if (decl != init_declarator->declarator + && init_declarator->declarator->parameter_declaration_clause) { + typeInfo.setFunctionPointer(true); + decl_cc.run(init_declarator->declarator); + foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) + typeInfo.addArgument(p.type); + } + + ScopeModelItem scope = currentScope(); + DeclaratorAST *declarator = init_declarator->declarator; + CodeModelFinder finder(model(), this); + ScopeModelItem typedefScope = finder.resolveScope(declarator->id, scope); + + TypeAliasModelItem typeAlias = model()->create (); + updateItemPosition(typeAlias->toItem(), node); + typeAlias->setName(alias_name); + typeAlias->setType(qualifyType(typeInfo, currentScope()->qualifiedName())); + typeAlias->setScope(typedefScope->qualifiedName()); + _M_qualified_types[typeAlias->qualifiedName().join(".")] = QString(); + currentScope()->addTypeAlias(typeAlias); + } while (it != end); +} + +void Binder::visitNamespace(NamespaceAST *node) +{ + bool anonymous = (node->namespace_name == 0); + + ScopeModelItem scope = currentScope(); + + NamespaceModelItem old; + if (!anonymous) { + QString name = decode_symbol(node->namespace_name)->as_string(); + + QStringList qualified_name = scope->qualifiedName(); + qualified_name += name; + NamespaceModelItem ns = + model_safe_cast(_M_model->findItem(qualified_name, + _M_current_file->toItem())); + if (!ns) { + ns = _M_model->create(); + updateItemPosition(ns->toItem(), node); + ns->setName(name); + ns->setScope(scope->qualifiedName()); + } + old = changeCurrentNamespace(ns); + + _M_context.append(name); + } + + DefaultVisitor::visitNamespace(node); + + if (!anonymous) { + Q_ASSERT(scope->kind() == _CodeModelItem::Kind_Namespace + || scope->kind() == _CodeModelItem::Kind_File); + + _M_context.removeLast(); + + if (NamespaceModelItem ns = model_static_cast(scope)) + ns->addNamespace(_M_current_namespace); + + changeCurrentNamespace(old); + } +} + +void Binder::visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *node) +{ + name_cc.run(node->name); + if (name_cc.name().isEmpty()) + return; + + ScopeModelItem scope = currentScope(); + _M_qualified_types[(scope->qualifiedName() + name_cc.qualifiedName()).join(".")] = QString(); +} + +void Binder::visitClassSpecifier(ClassSpecifierAST *node) +{ + ClassCompiler class_cc(this); + class_cc.run(node); + + if (class_cc.name().isEmpty()) { + // anonymous not supported + return; + } + + Q_ASSERT(node->name && node->name->unqualified_name); + + ScopeModelItem scope = currentScope(); + + ClassModelItem old = changeCurrentClass(_M_model->create()); + updateItemPosition(_M_current_class->toItem(), node); + _M_current_class->setName(class_cc.name()); + + QStringList baseClasses = class_cc.baseClasses(); + TypeInfo info; + for (int i = 0; i < baseClasses.size(); ++i) { + info.setQualifiedName(baseClasses.at(i).split("::")); + baseClasses[i] = qualifyType(info, scope->qualifiedName()).qualifiedName().join("::"); + } + + _M_current_class->setBaseClasses(baseClasses); + _M_current_class->setClassType(decode_class_type(node->class_key)); + _M_current_class->setTemplateParameters(_M_current_template_parameters); + + if (!_M_current_template_parameters.isEmpty()) { + QString name = _M_current_class->name(); + name += "<"; + for (int i = 0; i < _M_current_template_parameters.size(); ++i) { + if (i > 0) + name += ","; + + name += _M_current_template_parameters.at(i)->name(); + } + + name += ">"; + _M_current_class->setName(name); + } + + CodeModel::AccessPolicy oldAccessPolicy = changeCurrentAccess(decode_access_policy(node->class_key)); + CodeModel::FunctionType oldFunctionType = changeCurrentFunctionType(CodeModel::Normal); + + _M_current_class->setScope(scope->qualifiedName()); + _M_qualified_types[_M_current_class->qualifiedName().join(".")] = QString(); + + scope->addClass(_M_current_class); + + name_cc.run(node->name->unqualified_name); + _M_context.append(name_cc.name()); + visitNodes(this, node->member_specs); + _M_context.removeLast(); + + changeCurrentClass(old); + changeCurrentAccess(oldAccessPolicy); + changeCurrentFunctionType(oldFunctionType); +} + +void Binder::visitLinkageSpecification(LinkageSpecificationAST *node) +{ + DefaultVisitor::visitLinkageSpecification(node); +} + +void Binder::visitUsing(UsingAST *node) +{ + DefaultVisitor::visitUsing(node); +} + +void Binder::visitEnumSpecifier(EnumSpecifierAST *node) +{ + CodeModelFinder finder(model(), this); + ScopeModelItem scope = currentScope(); + ScopeModelItem enumScope = finder.resolveScope(node->name, scope); + + name_cc.run(node->name); + QString name = name_cc.name(); + + if (name.isEmpty()) { + // anonymous enum + QString key = _M_context.join("::"); + int current = ++_M_anonymous_enums[key]; + name += QLatin1String("enum_"); + name += QString::number(current); + } + + _M_current_enum = model()->create(); + _M_current_enum->setAccessPolicy(_M_current_access); + updateItemPosition(_M_current_enum->toItem(), node); + _M_current_enum->setName(name); + _M_current_enum->setScope(enumScope->qualifiedName()); + + _M_qualified_types[_M_current_enum->qualifiedName().join(".")] = QString(); + + enumScope->addEnum(_M_current_enum); + + DefaultVisitor::visitEnumSpecifier(node); + + _M_current_enum = 0; +} + +static QString strip_preprocessor_lines(const QString &name) +{ + QStringList lst = name.split("\n"); + QString s; + for (int i = 0; i < lst.size(); ++i) { + if (!lst.at(i).startsWith('#')) + s += lst.at(i); + } + return s.trimmed(); +} + +void Binder::visitEnumerator(EnumeratorAST *node) +{ + Q_ASSERT(_M_current_enum); + EnumeratorModelItem e = model()->create(); + updateItemPosition(e->toItem(), node); + e->setName(decode_symbol(node->id)->as_string()); + + if (ExpressionAST *expr = node->expression) { + const Token &start_token = _M_token_stream->token((int) expr->start_token); + const Token &end_token = _M_token_stream->token((int) expr->end_token); + + e->setValue(strip_preprocessor_lines(QString::fromUtf8(&start_token.text[start_token.position], + (int)(end_token.position - start_token.position)).trimmed()).remove(' ')); + } + + _M_current_enum->addEnumerator(e); +} + +void Binder::visitUsingDirective(UsingDirectiveAST *node) +{ + DefaultVisitor::visitUsingDirective(node); +} + +void Binder::visitQEnums(QEnumsAST *node) +{ + const Token &start = _M_token_stream->token((int) node->start_token); + const Token &end = _M_token_stream->token((int) node->end_token); + QStringList enum_list = QString::fromLatin1(start.text + start.position, + end.position - start.position).split(' '); + + ScopeModelItem scope = currentScope(); + for (int i = 0; i < enum_list.size(); ++i) + scope->addEnumsDeclaration(enum_list.at(i)); +} + +void Binder::visitQProperty(QPropertyAST *node) +{ + const Token &start = _M_token_stream->token((int) node->start_token); + const Token &end = _M_token_stream->token((int) node->end_token); + QString property = QString::fromLatin1(start.text + start.position, + end.position - start.position); + _M_current_class->addPropertyDeclaration(property); +} + +void Binder::applyStorageSpecifiers(const ListNode *it, MemberModelItem item) +{ + if (!it) + return; + + it = it->toFront(); + const ListNode *end = it; + + do { + switch (decode_token(it->element)) { + default: + break; + + case Token_friend: + item->setFriend(true); + break; + case Token_auto: + item->setAuto(true); + break; + case Token_register: + item->setRegister(true); + break; + case Token_static: + item->setStatic(true); + break; + case Token_extern: + item->setExtern(true); + break; + case Token_mutable: + item->setMutable(true); + break; + } + it = it->next; + } while (it != end); +} + +void Binder::applyFunctionSpecifiers(const ListNode *it, FunctionModelItem item) +{ + if (!it) + return; + + it = it->toFront(); + const ListNode *end = it; + + do { + switch (decode_token(it->element)) { + default: + break; + + case Token_inline: + item->setInline(true); + break; + + case Token_virtual: + item->setVirtual(true); + break; + + case Token_explicit: + item->setExplicit(true); + break; + + case Token_Q_INVOKABLE: + item->setInvokable(true); + break; + } + it = it->next; + } while (it != end); +} + +TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) const +{ + // ### Potentially improve to use string list in the name table to + if (!context.size()) { + // ### We can assume that this means global namespace for now... + return type; + } else if (_M_qualified_types.contains(type.qualifiedName().join("."))) { + return type; + } else { + QStringList expanded = context; + expanded << type.qualifiedName(); + if (_M_qualified_types.contains(expanded.join("."))) { + TypeInfo modified_type = type; + modified_type.setQualifiedName(expanded); + return modified_type; + } else { + CodeModelItem scope = model()->findItem(context, _M_current_file->toItem()); + + if (ClassModelItem klass = model_dynamic_cast (scope)) { + foreach (QString base, klass->baseClasses()) { + QStringList ctx = context; + ctx.removeLast(); + ctx.append(base); + + TypeInfo qualified = qualifyType(type, ctx); + if (qualified != type) + return qualified; + } + } + + QStringList copy = context; + copy.removeLast(); + return qualifyType(type, copy); + } + } +} + +void Binder::updateItemPosition(CodeModelItem item, AST *node) +{ + QString filename; + int line, column; + + assert(node); + _M_location.positionAt(_M_token_stream->position(node->start_token), &line, &column, &filename); + item->setFileName(filename); +} diff --git a/parser/binder.h b/parser/binder.h new file mode 100644 index 000000000..b4d4da667 --- /dev/null +++ b/parser/binder.h @@ -0,0 +1,125 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef BINDER_H +#define BINDER_H + +#include "default_visitor.h" +#include "codemodel.h" +#include "type_compiler.h" +#include "name_compiler.h" +#include "declarator_compiler.h" + +class TokenStream; +class LocationManager; +class Control; +struct NameSymbol; + +class Binder: protected DefaultVisitor +{ +public: + Binder(CodeModel *__model, LocationManager &__location, Control *__control = 0); + virtual ~Binder(); + + inline TokenStream *tokenStream() const + { + return _M_token_stream; + } + + inline CodeModel *model() const + { + return _M_model; + } + + ScopeModelItem currentScope(); + + FileModelItem run(AST *node); + +// utils + TypeInfo qualifyType(const TypeInfo &type, const QStringList &context) const; + +protected: + virtual void visitAccessSpecifier(AccessSpecifierAST *); + virtual void visitClassSpecifier(ClassSpecifierAST *); + virtual void visitEnumSpecifier(EnumSpecifierAST *); + virtual void visitEnumerator(EnumeratorAST *); + virtual void visitFunctionDefinition(FunctionDefinitionAST *); + virtual void visitLinkageSpecification(LinkageSpecificationAST *); + virtual void visitNamespace(NamespaceAST *); + virtual void visitSimpleDeclaration(SimpleDeclarationAST *); + virtual void visitTemplateDeclaration(TemplateDeclarationAST *); + virtual void visitTypedef(TypedefAST *); + virtual void visitUsing(UsingAST *); + virtual void visitUsingDirective(UsingDirectiveAST *); + virtual void visitQProperty(QPropertyAST *); + virtual void visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *); + virtual void visitQEnums(QEnumsAST *); + +private: + + int decode_token(std::size_t index) const; + const NameSymbol *decode_symbol(std::size_t index) const; + CodeModel::AccessPolicy decode_access_policy(std::size_t index) const; + CodeModel::ClassType decode_class_type(std::size_t index) const; + + CodeModel::FunctionType changeCurrentFunctionType(CodeModel::FunctionType functionType); + CodeModel::AccessPolicy changeCurrentAccess(CodeModel::AccessPolicy accessPolicy); + NamespaceModelItem changeCurrentNamespace(NamespaceModelItem item); + ClassModelItem changeCurrentClass(ClassModelItem item); + FunctionDefinitionModelItem changeCurrentFunction(FunctionDefinitionModelItem item); + TemplateParameterList changeTemplateParameters(TemplateParameterList templateParameters); + + void declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator); + + void applyStorageSpecifiers(const ListNode *storage_specifiers, MemberModelItem item); + void applyFunctionSpecifiers(const ListNode *it, FunctionModelItem item); + + void updateItemPosition(CodeModelItem item, AST *node); + +private: + CodeModel *_M_model; + LocationManager &_M_location; + TokenStream *_M_token_stream; + Control *_M_control; + + CodeModel::FunctionType _M_current_function_type; + CodeModel::AccessPolicy _M_current_access; + FileModelItem _M_current_file; + NamespaceModelItem _M_current_namespace; + ClassModelItem _M_current_class; + FunctionDefinitionModelItem _M_current_function; + EnumModelItem _M_current_enum; + QStringList _M_context; + TemplateParameterList _M_current_template_parameters; // ### check me + QHash _M_qualified_types; + QHash _M_anonymous_enums; + +protected: + TypeCompiler type_cc; + NameCompiler name_cc; + DeclaratorCompiler decl_cc; +}; + +#endif // BINDER_H diff --git a/parser/class_compiler.cpp b/parser/class_compiler.cpp new file mode 100644 index 000000000..e04ffe109 --- /dev/null +++ b/parser/class_compiler.cpp @@ -0,0 +1,66 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "class_compiler.h" +#include "lexer.h" +#include "binder.h" + +ClassCompiler::ClassCompiler(Binder *binder) + : _M_binder(binder), + _M_token_stream(binder->tokenStream()), + name_cc(_M_binder), + type_cc(_M_binder) +{ +} + +ClassCompiler::~ClassCompiler() +{ +} + +void ClassCompiler::run(ClassSpecifierAST *node) +{ + name_cc.run(node->name); + _M_name = name_cc.name(); + _M_base_classes.clear(); + + visit(node); +} + +void ClassCompiler::visitClassSpecifier(ClassSpecifierAST *node) +{ + visit(node->base_clause); +} + +void ClassCompiler::visitBaseSpecifier(BaseSpecifierAST *node) +{ + name_cc.run(node->name); + QString name = name_cc.name(); + + if (!name.isEmpty()) + _M_base_classes.append(name); +} + + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/class_compiler.h b/parser/class_compiler.h new file mode 100644 index 000000000..69fccf757 --- /dev/null +++ b/parser/class_compiler.h @@ -0,0 +1,72 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef CLASS_COMPILER_H +#define CLASS_COMPILER_H + +#include +#include + +#include +#include +#include + +class TokenStream; +class Binder; + +class ClassCompiler: protected DefaultVisitor +{ +public: + ClassCompiler(Binder *binder); + virtual ~ClassCompiler(); + + inline QString name() const + { + return _M_name; + } + + inline QStringList baseClasses() const + { + return _M_base_classes; + } + + void run(ClassSpecifierAST *node); + +protected: + virtual void visitClassSpecifier(ClassSpecifierAST *node); + virtual void visitBaseSpecifier(BaseSpecifierAST *node); + +private: + Binder *_M_binder; + TokenStream *_M_token_stream; + QString _M_name; + QStringList _M_base_classes; + NameCompiler name_cc; + TypeCompiler type_cc; +}; + +#endif // CLASS_COMPILER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/codemodel.cpp b/parser/codemodel.cpp new file mode 100644 index 000000000..ecc8e3036 --- /dev/null +++ b/parser/codemodel.cpp @@ -0,0 +1,932 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "codemodel.h" + +// --------------------------------------------------------------------------- +CodeModel::CodeModel() + : _M_creation_id(0) +{ + _M_globalNamespace = create(); +} + +CodeModel::~CodeModel() +{ +} + +void CodeModel::wipeout() +{ + _M_globalNamespace = create(); + _M_files.clear(); +} + +FileList CodeModel::files() const +{ + return _M_files.values(); +} + +NamespaceModelItem CodeModel::globalNamespace() const +{ + return _M_globalNamespace; +} + +void CodeModel::addFile(FileModelItem item) +{ + _M_creation_id = 0; // reset the creation id + _M_files.insert(item->name(), item); +} + +void CodeModel::removeFile(FileModelItem item) +{ + QHash::Iterator it = _M_files.find(item->name()); + + if (it != _M_files.end() && it.value() == item) + _M_files.erase(it); +} + +FileModelItem CodeModel::findFile(const QString &name) const +{ + return _M_files.value(name); +} + +QHash CodeModel::fileMap() const +{ + return _M_files; +} + +CodeModelItem CodeModel::findItem(const QStringList &qualifiedName, CodeModelItem scope) const +{ + for (int i = 0; i < qualifiedName.size(); ++i) { + // ### Extend to look for members etc too. + const QString &name = qualifiedName.at(i); + + if (NamespaceModelItem ns = model_dynamic_cast(scope)) { + if (NamespaceModelItem tmp_ns = ns->findNamespace(name)) { + scope = tmp_ns; + continue; + } + } + + if (ScopeModelItem ss = model_dynamic_cast(scope)) { + if (ClassModelItem cs = ss->findClass(name)) { + scope = cs; + } else if (EnumModelItem es = ss->findEnum(name)) { + if (i == qualifiedName.size() - 1) + return es->toItem(); + } else if (TypeAliasModelItem tp = ss->findTypeAlias(name)) { + if (i == qualifiedName.size() - 1) + return tp->toItem(); + } else { + // If we don't find the name in the scope chain we + // need to return an empty item to indicate failure... + return CodeModelItem(); + } + } + } + + return scope; +} + + +// --------------------------------------------------------------------------- +TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs) +{ + TypeInfo __result = __lhs; + + __result.setConstant(__result.isConstant() || __rhs.isConstant()); + __result.setVolatile(__result.isVolatile() || __rhs.isVolatile()); + __result.setReference(__result.isReference() || __rhs.isReference()); + __result.setIndirections(__result.indirections() + __rhs.indirections()); + __result.setArrayElements(__result.arrayElements() + __rhs.arrayElements()); + + return __result; +} + +TypeInfo TypeInfo::resolveType(TypeInfo const &__type, CodeModelItem __scope) +{ + CodeModel *__model = __scope->model(); + Q_ASSERT(__model != 0); + + CodeModelItem __item = __model->findItem(__type.qualifiedName(), __scope); + + // Copy the type and replace with the proper qualified name. This + // only makes sence to do if we're actually getting a resolved + // type with a namespace. We only get this if the returned type + // has more than 2 entries in the qualified name... This test + // could be improved by returning if the type was found or not. + TypeInfo otherType(__type); + if (__item && __item->qualifiedName().size() > 1) { + otherType.setQualifiedName(__item->qualifiedName()); + } + + if (TypeAliasModelItem __alias = model_dynamic_cast (__item)) + return resolveType(TypeInfo::combine(__alias->type(), otherType), __scope); + + return otherType; +} + +QString TypeInfo::toString() const +{ + QString tmp; + + tmp += m_qualifiedName.join("::"); + if (isConstant()) + tmp += QLatin1String(" const"); + + if (isVolatile()) + tmp += QLatin1String(" volatile"); + + if (indirections()) + tmp += QString(indirections(), QLatin1Char('*')); + + if (isReference()) + tmp += QLatin1Char('&'); + + if (isFunctionPointer()) { + tmp += QLatin1String(" (*)("); + for (int i = 0; i < m_arguments.count(); ++i) { + if (i != 0) + tmp += QLatin1String(", "); + + tmp += m_arguments.at(i).toString(); + } + tmp += QLatin1String(")"); + } + + foreach(QString elt, arrayElements()) { + tmp += QLatin1String("["); + tmp += elt; + tmp += QLatin1String("]"); + } + + return tmp; +} + +bool TypeInfo::operator==(const TypeInfo &other) +{ + if (arrayElements().count() != other.arrayElements().count()) + return false; + +#if defined (RXX_CHECK_ARRAY_ELEMENTS) // ### it'll break + for (int i = 0; i < arrayElements().count(); ++i) { + QString elt1 = arrayElements().at(i).trimmed(); + QString elt2 = other.arrayElements().at(i).trimmed(); + + if (elt1 != elt2) + return false; + } +#endif + + return flags == other.flags + && m_qualifiedName == other.m_qualifiedName + && (!m_functionPointer || m_arguments == other.m_arguments); +} + +// --------------------------------------------------------------------------- +_CodeModelItem::_CodeModelItem(CodeModel *model, int kind) + : _M_model(model), + _M_kind(kind), + _M_startLine(0), + _M_startColumn(0), + _M_endLine(0), + _M_endColumn(0), + _M_creation_id(0) +{ +} + +_CodeModelItem::~_CodeModelItem() +{ +} + +CodeModelItem _CodeModelItem::toItem() const +{ + return CodeModelItem(const_cast<_CodeModelItem*>(this)); +} + +int _CodeModelItem::kind() const +{ + return _M_kind; +} + +void _CodeModelItem::setKind(int kind) +{ + _M_kind = kind; +} + +QStringList _CodeModelItem::qualifiedName() const +{ + QStringList q = scope(); + + if (!name().isEmpty()) + q += name(); + + return q; +} + +QString _CodeModelItem::name() const +{ + return _M_name; +} + +void _CodeModelItem::setName(const QString &name) +{ + _M_name = name; +} + +QStringList _CodeModelItem::scope() const +{ + return _M_scope; +} + +void _CodeModelItem::setScope(const QStringList &scope) +{ + _M_scope = scope; +} + +QString _CodeModelItem::fileName() const +{ + return _M_fileName; +} + +void _CodeModelItem::setFileName(const QString &fileName) +{ + _M_fileName = fileName; +} + +FileModelItem _CodeModelItem::file() const +{ + return model()->findFile(fileName()); +} + +void _CodeModelItem::getStartPosition(int *line, int *column) +{ + *line = _M_startLine; + *column = _M_startColumn; +} + +void _CodeModelItem::setStartPosition(int line, int column) +{ + _M_startLine = line; + _M_startColumn = column; +} + +void _CodeModelItem::getEndPosition(int *line, int *column) +{ + *line = _M_endLine; + *column = _M_endColumn; +} + +void _CodeModelItem::setEndPosition(int line, int column) +{ + _M_endLine = line; + _M_endColumn = column; +} + +// --------------------------------------------------------------------------- +QStringList _ClassModelItem::baseClasses() const +{ + return _M_baseClasses; +} + +void _ClassModelItem::setBaseClasses(const QStringList &baseClasses) +{ + _M_baseClasses = baseClasses; +} + +TemplateParameterList _ClassModelItem::templateParameters() const +{ + return _M_templateParameters; +} + +void _ClassModelItem::setTemplateParameters(const TemplateParameterList &templateParameters) +{ + _M_templateParameters = templateParameters; +} + +void _ClassModelItem::addBaseClass(const QString &baseClass) +{ + _M_baseClasses.append(baseClass); +} + +void _ClassModelItem::removeBaseClass(const QString &baseClass) +{ + _M_baseClasses.removeAt(_M_baseClasses.indexOf(baseClass)); +} + +bool _ClassModelItem::extendsClass(const QString &name) const +{ + return _M_baseClasses.contains(name); +} + +void _ClassModelItem::setClassType(CodeModel::ClassType type) +{ + _M_classType = type; +} + +CodeModel::ClassType _ClassModelItem::classType() const +{ + return _M_classType; +} + +void _ClassModelItem::addPropertyDeclaration(const QString &propertyDeclaration) +{ + _M_propertyDeclarations << propertyDeclaration; +} + + +// --------------------------------------------------------------------------- +FunctionModelItem _ScopeModelItem::declaredFunction(FunctionModelItem item) +{ + FunctionList function_list = findFunctions(item->name()); + + foreach(FunctionModelItem fun, function_list) { + if (fun->isSimilar(item)) + return fun; + } + + return FunctionModelItem(); +} + +ClassList _ScopeModelItem::classes() const +{ + return _M_classes.values(); +} + +TypeAliasList _ScopeModelItem::typeAliases() const +{ + return _M_typeAliases.values(); +} + +VariableList _ScopeModelItem::variables() const +{ + return _M_variables.values(); +} + +FunctionList _ScopeModelItem::functions() const +{ + return _M_functions.values(); +} + +void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration) +{ + _M_enumsDeclarations << enumsDeclaration; +} + +FunctionDefinitionList _ScopeModelItem::functionDefinitions() const +{ + return _M_functionDefinitions.values(); +} + +EnumList _ScopeModelItem::enums() const +{ + return _M_enums.values(); +} + +void _ScopeModelItem::addClass(ClassModelItem item) +{ + QString name = item->name(); + int idx = name.indexOf("<"); + if (idx > 0) + _M_classes.insert(name.left(idx), item); + _M_classes.insert(name, item); +} + +void _ScopeModelItem::addFunction(FunctionModelItem item) +{ + _M_functions.insert(item->name(), item); +} + +void _ScopeModelItem::addFunctionDefinition(FunctionDefinitionModelItem item) +{ + _M_functionDefinitions.insert(item->name(), item); +} + +void _ScopeModelItem::addVariable(VariableModelItem item) +{ + _M_variables.insert(item->name(), item); +} + +void _ScopeModelItem::addTypeAlias(TypeAliasModelItem item) +{ + _M_typeAliases.insert(item->name(), item); +} + +void _ScopeModelItem::addEnum(EnumModelItem item) +{ + _M_enums.insert(item->name(), item); +} + +void _ScopeModelItem::removeClass(ClassModelItem item) +{ + QHash::Iterator it = _M_classes.find(item->name()); + + if (it != _M_classes.end() && it.value() == item) + _M_classes.erase(it); +} + +void _ScopeModelItem::removeFunction(FunctionModelItem item) +{ + QMultiHash::Iterator it = _M_functions.find(item->name()); + + while (it != _M_functions.end() && it.key() == item->name() + && it.value() != item) { + ++it; + } + + if (it != _M_functions.end() && it.value() == item) { + _M_functions.erase(it); + } +} + +void _ScopeModelItem::removeFunctionDefinition(FunctionDefinitionModelItem item) +{ + QMultiHash::Iterator it = _M_functionDefinitions.find(item->name()); + + while (it != _M_functionDefinitions.end() && it.key() == item->name() + && it.value() != item) { + ++it; + } + + if (it != _M_functionDefinitions.end() && it.value() == item) { + _M_functionDefinitions.erase(it); + } +} + +void _ScopeModelItem::removeVariable(VariableModelItem item) +{ + QHash::Iterator it = _M_variables.find(item->name()); + + if (it != _M_variables.end() && it.value() == item) + _M_variables.erase(it); +} + +void _ScopeModelItem::removeTypeAlias(TypeAliasModelItem item) +{ + QHash::Iterator it = _M_typeAliases.find(item->name()); + + if (it != _M_typeAliases.end() && it.value() == item) + _M_typeAliases.erase(it); +} + +void _ScopeModelItem::removeEnum(EnumModelItem item) +{ + QHash::Iterator it = _M_enums.find(item->name()); + + if (it != _M_enums.end() && it.value() == item) + _M_enums.erase(it); +} + +ClassModelItem _ScopeModelItem::findClass(const QString &name) const +{ + return _M_classes.value(name); +} + +VariableModelItem _ScopeModelItem::findVariable(const QString &name) const +{ + return _M_variables.value(name); +} + +TypeAliasModelItem _ScopeModelItem::findTypeAlias(const QString &name) const +{ + return _M_typeAliases.value(name); +} + +EnumModelItem _ScopeModelItem::findEnum(const QString &name) const +{ + return _M_enums.value(name); +} + +FunctionList _ScopeModelItem::findFunctions(const QString &name) const +{ + return _M_functions.values(name); +} + +FunctionDefinitionList _ScopeModelItem::findFunctionDefinitions(const QString &name) const +{ + return _M_functionDefinitions.values(name); +} + +// --------------------------------------------------------------------------- +NamespaceList _NamespaceModelItem::namespaces() const +{ + return _M_namespaces.values(); +} +void _NamespaceModelItem::addNamespace(NamespaceModelItem item) +{ + _M_namespaces.insert(item->name(), item); +} +void _NamespaceModelItem::removeNamespace(NamespaceModelItem item) +{ + QHash::Iterator it = _M_namespaces.find(item->name()); + + if (it != _M_namespaces.end() && it.value() == item) + _M_namespaces.erase(it); +} + +NamespaceModelItem _NamespaceModelItem::findNamespace(const QString &name) const +{ + return _M_namespaces.value(name); +} + +// --------------------------------------------------------------------------- +TypeInfo _ArgumentModelItem::type() const +{ + return _M_type; +} + +void _ArgumentModelItem::setType(const TypeInfo &type) +{ + _M_type = type; +} + +bool _ArgumentModelItem::defaultValue() const +{ + return _M_defaultValue; +} + +void _ArgumentModelItem::setDefaultValue(bool defaultValue) +{ + _M_defaultValue = defaultValue; +} + +// --------------------------------------------------------------------------- +bool _FunctionModelItem::isSimilar(FunctionModelItem other) const +{ + if (name() != other->name()) + return false; + + if (isConstant() != other->isConstant()) + return false; + + if (isVariadics() != other->isVariadics()) + return false; + + if (arguments().count() != other->arguments().count()) + return false; + + // ### check the template parameters + + for (int i = 0; i < arguments().count(); ++i) { + ArgumentModelItem arg1 = arguments().at(i); + ArgumentModelItem arg2 = other->arguments().at(i); + + if (arg1->type() != arg2->type()) + return false; + } + + return true; +} + +ArgumentList _FunctionModelItem::arguments() const +{ + return _M_arguments; +} + +void _FunctionModelItem::addArgument(ArgumentModelItem item) +{ + _M_arguments.append(item); +} + +void _FunctionModelItem::removeArgument(ArgumentModelItem item) +{ + _M_arguments.removeAt(_M_arguments.indexOf(item)); +} + +CodeModel::FunctionType _FunctionModelItem::functionType() const +{ + return _M_functionType; +} + +void _FunctionModelItem::setFunctionType(CodeModel::FunctionType functionType) +{ + _M_functionType = functionType; +} + +bool _FunctionModelItem::isVariadics() const +{ + return _M_isVariadics; +} + +void _FunctionModelItem::setVariadics(bool isVariadics) +{ + _M_isVariadics = isVariadics; +} + +bool _FunctionModelItem::isVirtual() const +{ + return _M_isVirtual; +} + +void _FunctionModelItem::setVirtual(bool isVirtual) +{ + _M_isVirtual = isVirtual; +} + +bool _FunctionModelItem::isInline() const +{ + return _M_isInline; +} + +void _FunctionModelItem::setInline(bool isInline) +{ + _M_isInline = isInline; +} + +bool _FunctionModelItem::isExplicit() const +{ + return _M_isExplicit; +} + +void _FunctionModelItem::setExplicit(bool isExplicit) +{ + _M_isExplicit = isExplicit; +} + +bool _FunctionModelItem::isAbstract() const +{ + return _M_isAbstract; +} + +void _FunctionModelItem::setAbstract(bool isAbstract) +{ + _M_isAbstract = isAbstract; +} + +// Qt +bool _FunctionModelItem::isInvokable() const +{ + return _M_isInvokable; +} + +void _FunctionModelItem::setInvokable(bool isInvokable) +{ + _M_isInvokable = isInvokable; +} + +// --------------------------------------------------------------------------- +TypeInfo _TypeAliasModelItem::type() const +{ + return _M_type; +} + +void _TypeAliasModelItem::setType(const TypeInfo &type) +{ + _M_type = type; +} + +// --------------------------------------------------------------------------- +CodeModel::AccessPolicy _EnumModelItem::accessPolicy() const +{ + return _M_accessPolicy; +} + +void _EnumModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy) +{ + _M_accessPolicy = accessPolicy; +} + +EnumeratorList _EnumModelItem::enumerators() const +{ + return _M_enumerators; +} + +void _EnumModelItem::addEnumerator(EnumeratorModelItem item) +{ + _M_enumerators.append(item); +} + +void _EnumModelItem::removeEnumerator(EnumeratorModelItem item) +{ + _M_enumerators.removeAt(_M_enumerators.indexOf(item)); +} + +// --------------------------------------------------------------------------- +QString _EnumeratorModelItem::value() const +{ + return _M_value; +} + +void _EnumeratorModelItem::setValue(const QString &value) +{ + _M_value = value; +} + +// --------------------------------------------------------------------------- +TypeInfo _TemplateParameterModelItem::type() const +{ + return _M_type; +} + +void _TemplateParameterModelItem::setType(const TypeInfo &type) +{ + _M_type = type; +} + +bool _TemplateParameterModelItem::defaultValue() const +{ + return _M_defaultValue; +} + +void _TemplateParameterModelItem::setDefaultValue(bool defaultValue) +{ + _M_defaultValue = defaultValue; +} + +// --------------------------------------------------------------------------- +ScopeModelItem _ScopeModelItem::create(CodeModel *model) +{ + ScopeModelItem item(new _ScopeModelItem(model)); + return item; +} + +ClassModelItem _ClassModelItem::create(CodeModel *model) +{ + ClassModelItem item(new _ClassModelItem(model)); + return item; +} + +NamespaceModelItem _NamespaceModelItem::create(CodeModel *model) +{ + NamespaceModelItem item(new _NamespaceModelItem(model)); + return item; +} + +FileModelItem _FileModelItem::create(CodeModel *model) +{ + FileModelItem item(new _FileModelItem(model)); + return item; +} + +ArgumentModelItem _ArgumentModelItem::create(CodeModel *model) +{ + ArgumentModelItem item(new _ArgumentModelItem(model)); + return item; +} + +FunctionModelItem _FunctionModelItem::create(CodeModel *model) +{ + FunctionModelItem item(new _FunctionModelItem(model)); + return item; +} + +FunctionDefinitionModelItem _FunctionDefinitionModelItem::create(CodeModel *model) +{ + FunctionDefinitionModelItem item(new _FunctionDefinitionModelItem(model)); + return item; +} + +VariableModelItem _VariableModelItem::create(CodeModel *model) +{ + VariableModelItem item(new _VariableModelItem(model)); + return item; +} + +TypeAliasModelItem _TypeAliasModelItem::create(CodeModel *model) +{ + TypeAliasModelItem item(new _TypeAliasModelItem(model)); + return item; +} + +EnumModelItem _EnumModelItem::create(CodeModel *model) +{ + EnumModelItem item(new _EnumModelItem(model)); + return item; +} + +EnumeratorModelItem _EnumeratorModelItem::create(CodeModel *model) +{ + EnumeratorModelItem item(new _EnumeratorModelItem(model)); + return item; +} + +TemplateParameterModelItem _TemplateParameterModelItem::create(CodeModel *model) +{ + TemplateParameterModelItem item(new _TemplateParameterModelItem(model)); + return item; +} + +// --------------------------------------------------------------------------- +TypeInfo _MemberModelItem::type() const +{ + return _M_type; +} + +void _MemberModelItem::setType(const TypeInfo &type) +{ + _M_type = type; +} + +CodeModel::AccessPolicy _MemberModelItem::accessPolicy() const +{ + return _M_accessPolicy; +} + +void _MemberModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy) +{ + _M_accessPolicy = accessPolicy; +} + +bool _MemberModelItem::isStatic() const +{ + return _M_isStatic; +} + +void _MemberModelItem::setStatic(bool isStatic) +{ + _M_isStatic = isStatic; +} + +bool _MemberModelItem::isConstant() const +{ + return _M_isConstant; +} + +void _MemberModelItem::setConstant(bool isConstant) +{ + _M_isConstant = isConstant; +} + +bool _MemberModelItem::isVolatile() const +{ + return _M_isVolatile; +} + +void _MemberModelItem::setVolatile(bool isVolatile) +{ + _M_isVolatile = isVolatile; +} + +bool _MemberModelItem::isAuto() const +{ + return _M_isAuto; +} + +void _MemberModelItem::setAuto(bool isAuto) +{ + _M_isAuto = isAuto; +} + +bool _MemberModelItem::isFriend() const +{ + return _M_isFriend; +} + +void _MemberModelItem::setFriend(bool isFriend) +{ + _M_isFriend = isFriend; +} + +bool _MemberModelItem::isRegister() const +{ + return _M_isRegister; +} + +void _MemberModelItem::setRegister(bool isRegister) +{ + _M_isRegister = isRegister; +} + +bool _MemberModelItem::isExtern() const +{ + return _M_isExtern; +} + +void _MemberModelItem::setExtern(bool isExtern) +{ + _M_isExtern = isExtern; +} + +bool _MemberModelItem::isMutable() const +{ + return _M_isMutable; +} + +void _MemberModelItem::setMutable(bool isMutable) +{ + _M_isMutable = isMutable; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/parser/codemodel.h b/parser/codemodel.h new file mode 100644 index 000000000..3ea94480f --- /dev/null +++ b/parser/codemodel.h @@ -0,0 +1,838 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef CODEMODEL_H +#define CODEMODEL_H + +#include "codemodel_fwd.h" +#include "codemodel_pointer.h" + +#include +#include +#include +#include +#include + +#define DECLARE_MODEL_NODE(k) \ + enum { __node_kind = Kind_##k }; \ + typedef CodeModelPointer Pointer; + +template +_Target model_static_cast(_Source item) +{ + typedef typename _Target::Type * _Target_pointer; + + _Target ptr(static_cast<_Target_pointer>(item.data())); + return ptr; +} + +class CodeModel +{ +public: + enum AccessPolicy { + Public, + Protected, + Private + }; + + enum FunctionType { + Normal, + Signal, + Slot + }; + + enum ClassType { + Class, + Struct, + Union + }; + +public: + CodeModel(); + virtual ~CodeModel(); + + template _Target create() + { + typedef typename _Target::Type _Target_type; + + _Target result = _Target_type::create(this); + result->setCreationId(_M_creation_id++); + return result; + } + + FileList files() const; + NamespaceModelItem globalNamespace() const; + + void addFile(FileModelItem item); + void removeFile(FileModelItem item); + FileModelItem findFile(const QString &name) const; + QHash fileMap() const; + + CodeModelItem findItem(const QStringList &qualifiedName, CodeModelItem scope) const; + + void wipeout(); + +private: + QHash _M_files; + NamespaceModelItem _M_globalNamespace; + std::size_t _M_creation_id; + +private: + CodeModel(const CodeModel &other); + void operator = (const CodeModel &other); +}; + +class TypeInfo +{ +public: + TypeInfo(const TypeInfo &other) + : flags(other.flags), + m_qualifiedName(other.m_qualifiedName), + m_arrayElements(other.m_arrayElements), + m_arguments(other.m_arguments) + {} + + TypeInfo(): + flags(0) {} + + QStringList qualifiedName() const + { + return m_qualifiedName; + } + + void setQualifiedName(const QStringList &qualified_name) + { + m_qualifiedName = qualified_name; + } + + bool isConstant() const + { + return m_constant; + } + + void setConstant(bool is) + { + m_constant = is; + } + + bool isVolatile() const + { + return m_volatile; + } + + void setVolatile(bool is) + { + m_volatile = is; + } + + bool isReference() const + { + return m_reference; + } + + void setReference(bool is) + { + m_reference = is; + } + + int indirections() const + { + return m_indirections; + } + + void setIndirections(int indirections) + { + m_indirections = indirections; + } + + bool isFunctionPointer() const + { + return m_functionPointer; + } + void setFunctionPointer(bool is) + { + m_functionPointer = is; + } + + QStringList arrayElements() const + { + return m_arrayElements; + } + void setArrayElements(const QStringList &arrayElements) + { + m_arrayElements = arrayElements; + } + + QList arguments() const + { + return m_arguments; + } + + void setArguments(const QList &arguments); + + void addArgument(const TypeInfo &arg) + { + m_arguments.append(arg); + } + + bool operator==(const TypeInfo &other); + + bool operator!=(const TypeInfo &other) + { + return !(*this == other); + } + + // ### arrays and templates?? + + QString toString() const; + + static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs); + static TypeInfo resolveType(TypeInfo const &__type, CodeModelItem __scope); + +private: + union { + uint flags; + + struct { + uint m_constant: 1; + uint m_volatile: 1; + uint m_reference: 1; + uint m_functionPointer: 1; + uint m_indirections: 6; + uint m_padding: 22; + }; + }; + + QStringList m_qualifiedName; + QStringList m_arrayElements; + QList m_arguments; +}; + +class _CodeModelItem: public QSharedData +{ +public: + enum Kind { + /* These are bit-flags resembling inheritance */ + Kind_Scope = 0x1, + Kind_Namespace = 0x2 | Kind_Scope, + Kind_Member = 0x4, + Kind_Function = 0x8 | Kind_Member, + KindMask = 0xf, + + /* These are for classes that are not inherited from */ + FirstKind = 0x8, + Kind_Argument = 1 << FirstKind, + Kind_Class = 2 << FirstKind | Kind_Scope, + Kind_Enum = 3 << FirstKind, + Kind_Enumerator = 4 << FirstKind, + Kind_File = 5 << FirstKind | Kind_Namespace, + Kind_FunctionDefinition = 6 << FirstKind | Kind_Function, + Kind_TemplateParameter = 7 << FirstKind, + Kind_TypeAlias = 8 << FirstKind, + Kind_Variable = 9 << FirstKind | Kind_Member + }; + +public: + virtual ~_CodeModelItem(); + + int kind() const; + + QStringList qualifiedName() const; + + QString name() const; + void setName(const QString &name); + + QStringList scope() const; + void setScope(const QStringList &scope); + + QString fileName() const; + void setFileName(const QString &fileName); + + FileModelItem file() const; + + void getStartPosition(int *line, int *column); + void setStartPosition(int line, int column); + + void getEndPosition(int *line, int *column); + void setEndPosition(int line, int column); + + inline std::size_t creationId() const + { + return _M_creation_id; + } + + inline void setCreationId(std::size_t creation_id) + { + _M_creation_id = creation_id; + } + + inline CodeModel *model() const + { + return _M_model; + } + + CodeModelItem toItem() const; + +protected: + _CodeModelItem(CodeModel *model, int kind); + void setKind(int kind); + +private: + CodeModel *_M_model; + int _M_kind; + int _M_startLine; + int _M_startColumn; + int _M_endLine; + int _M_endColumn; + std::size_t _M_creation_id; + QString _M_name; + QString _M_fileName; + QStringList _M_scope; + +private: + _CodeModelItem(const _CodeModelItem &other); + void operator = (const _CodeModelItem &other); +}; + +class _ScopeModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Scope) + + static ScopeModelItem create(CodeModel *model); + +public: + ClassList classes() const; + EnumList enums() const; + FunctionDefinitionList functionDefinitions() const; + FunctionList functions() const; + TypeAliasList typeAliases() const; + VariableList variables() const; + + void addClass(ClassModelItem item); + void addEnum(EnumModelItem item); + void addFunction(FunctionModelItem item); + void addFunctionDefinition(FunctionDefinitionModelItem item); + void addTypeAlias(TypeAliasModelItem item); + void addVariable(VariableModelItem item); + + void removeClass(ClassModelItem item); + void removeEnum(EnumModelItem item); + void removeFunction(FunctionModelItem item); + void removeFunctionDefinition(FunctionDefinitionModelItem item); + void removeTypeAlias(TypeAliasModelItem item); + void removeVariable(VariableModelItem item); + + ClassModelItem findClass(const QString &name) const; + EnumModelItem findEnum(const QString &name) const; + FunctionDefinitionList findFunctionDefinitions(const QString &name) const; + FunctionList findFunctions(const QString &name) const; + TypeAliasModelItem findTypeAlias(const QString &name) const; + VariableModelItem findVariable(const QString &name) const; + + void addEnumsDeclaration(const QString &enumsDeclaration); + QStringList enumsDeclarations() const + { + return _M_enumsDeclarations; + } + + inline QHash classMap() const + { + return _M_classes; + } + inline QHash enumMap() const + { + return _M_enums; + } + inline QHash typeAliasMap() const + { + return _M_typeAliases; + } + inline QHash variableMap() const + { + return _M_variables; + } + inline QMultiHash functionDefinitionMap() const + { + return _M_functionDefinitions; + } + inline QMultiHash functionMap() const + { + return _M_functions; + } + + FunctionModelItem declaredFunction(FunctionModelItem item); + +protected: + _ScopeModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind) {} + +private: + QHash _M_classes; + QHash _M_enums; + QHash _M_typeAliases; + QHash _M_variables; + QMultiHash _M_functionDefinitions; + QMultiHash _M_functions; + +private: + _ScopeModelItem(const _ScopeModelItem &other); + void operator = (const _ScopeModelItem &other); + + QStringList _M_enumsDeclarations; +}; + +class _ClassModelItem: public _ScopeModelItem +{ +public: + DECLARE_MODEL_NODE(Class) + + static ClassModelItem create(CodeModel *model); + +public: + QStringList baseClasses() const; + + void setBaseClasses(const QStringList &baseClasses); + void addBaseClass(const QString &baseClass); + void removeBaseClass(const QString &baseClass); + + TemplateParameterList templateParameters() const; + void setTemplateParameters(const TemplateParameterList &templateParameters); + + bool extendsClass(const QString &name) const; + + void setClassType(CodeModel::ClassType type); + CodeModel::ClassType classType() const; + + void addPropertyDeclaration(const QString &propertyDeclaration); + QStringList propertyDeclarations() const + { + return _M_propertyDeclarations; + } + +protected: + _ClassModelItem(CodeModel *model, int kind = __node_kind) + : _ScopeModelItem(model, kind), _M_classType(CodeModel::Class) {} + +private: + QStringList _M_baseClasses; + TemplateParameterList _M_templateParameters; + CodeModel::ClassType _M_classType; + + QStringList _M_propertyDeclarations; + +private: + _ClassModelItem(const _ClassModelItem &other); + void operator = (const _ClassModelItem &other); +}; + +class _NamespaceModelItem: public _ScopeModelItem +{ +public: + DECLARE_MODEL_NODE(Namespace) + + static NamespaceModelItem create(CodeModel *model); + +public: + NamespaceList namespaces() const; + + void addNamespace(NamespaceModelItem item); + void removeNamespace(NamespaceModelItem item); + + NamespaceModelItem findNamespace(const QString &name) const; + + inline QHash namespaceMap() const + { + return _M_namespaces; + }; + +protected: + _NamespaceModelItem(CodeModel *model, int kind = __node_kind) + : _ScopeModelItem(model, kind) {} + +private: + QHash _M_namespaces; + +private: + _NamespaceModelItem(const _NamespaceModelItem &other); + void operator = (const _NamespaceModelItem &other); +}; + +class _FileModelItem: public _NamespaceModelItem +{ +public: + DECLARE_MODEL_NODE(File) + + static FileModelItem create(CodeModel *model); + +protected: + _FileModelItem(CodeModel *model, int kind = __node_kind) + : _NamespaceModelItem(model, kind) {} + +private: + _FileModelItem(const _FileModelItem &other); + void operator = (const _FileModelItem &other); +}; + +class _ArgumentModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Argument) + + static ArgumentModelItem create(CodeModel *model); + +public: + TypeInfo type() const; + void setType(const TypeInfo &type); + + bool defaultValue() const; + void setDefaultValue(bool defaultValue); + + QString defaultValueExpression() const + { + return _M_defaultValueExpression; + } + + void setDefaultValueExpression(const QString &expr) + { + _M_defaultValueExpression = expr; + } + +protected: + _ArgumentModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind), _M_defaultValue(false) {} + +private: + TypeInfo _M_type; + QString _M_defaultValueExpression; + bool _M_defaultValue; + +private: + _ArgumentModelItem(const _ArgumentModelItem &other); + void operator = (const _ArgumentModelItem &other); +}; + +class _MemberModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Member) + + bool isConstant() const; + void setConstant(bool isConstant); + + bool isVolatile() const; + void setVolatile(bool isVolatile); + + bool isStatic() const; + void setStatic(bool isStatic); + + bool isAuto() const; + void setAuto(bool isAuto); + + bool isFriend() const; + void setFriend(bool isFriend); + + bool isRegister() const; + void setRegister(bool isRegister); + + bool isExtern() const; + void setExtern(bool isExtern); + + bool isMutable() const; + void setMutable(bool isMutable); + + CodeModel::AccessPolicy accessPolicy() const; + void setAccessPolicy(CodeModel::AccessPolicy accessPolicy); + + TemplateParameterList templateParameters() const + { + return _M_templateParameters; + } + + void setTemplateParameters(const TemplateParameterList &templateParameters) + { + _M_templateParameters = templateParameters; + } + + TypeInfo type() const; + void setType(const TypeInfo &type); + +protected: + _MemberModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind), + _M_accessPolicy(CodeModel::Public), + _M_flags(0) {} + +private: + TemplateParameterList _M_templateParameters; + TypeInfo _M_type; + CodeModel::AccessPolicy _M_accessPolicy; + union { + struct { + uint _M_isConstant: 1; + uint _M_isVolatile: 1; + uint _M_isStatic: 1; + uint _M_isAuto: 1; + uint _M_isFriend: 1; + uint _M_isRegister: 1; + uint _M_isExtern: 1; + uint _M_isMutable: 1; + }; + uint _M_flags; + }; + +}; + +class _FunctionModelItem: public _MemberModelItem +{ +public: + DECLARE_MODEL_NODE(Function) + + static FunctionModelItem create(CodeModel *model); + +public: + ArgumentList arguments() const; + + void addArgument(ArgumentModelItem item); + void removeArgument(ArgumentModelItem item); + + CodeModel::FunctionType functionType() const; + void setFunctionType(CodeModel::FunctionType functionType); + + bool isVirtual() const; + void setVirtual(bool isVirtual); + + bool isInline() const; + void setInline(bool isInline); + + bool isExplicit() const; + void setExplicit(bool isExplicit); + + bool isInvokable() const; // Qt + void setInvokable(bool isInvokable); // Qt + + bool isAbstract() const; + void setAbstract(bool isAbstract); + + bool isVariadics() const; + void setVariadics(bool isVariadics); + + bool isSimilar(FunctionModelItem other) const; + +protected: + _FunctionModelItem(CodeModel *model, int kind = __node_kind) + : _MemberModelItem(model, kind), + _M_functionType(CodeModel::Normal), + _M_flags(0) {} + +private: + ArgumentList _M_arguments; + CodeModel::FunctionType _M_functionType; + union { + struct { + uint _M_isVirtual: 1; + uint _M_isInline: 1; + uint _M_isAbstract: 1; + uint _M_isExplicit: 1; + uint _M_isVariadics: 1; + uint _M_isInvokable : 1; // Qt + }; + uint _M_flags; + }; + +private: + _FunctionModelItem(const _FunctionModelItem &other); + void operator = (const _FunctionModelItem &other); +}; + +class _FunctionDefinitionModelItem: public _FunctionModelItem +{ +public: + DECLARE_MODEL_NODE(FunctionDefinition) + + static FunctionDefinitionModelItem create(CodeModel *model); + +protected: + _FunctionDefinitionModelItem(CodeModel *model, int kind = __node_kind) + : _FunctionModelItem(model, kind) {} + +private: + _FunctionDefinitionModelItem(const _FunctionDefinitionModelItem &other); + void operator = (const _FunctionDefinitionModelItem &other); +}; + +class _VariableModelItem: public _MemberModelItem +{ +public: + DECLARE_MODEL_NODE(Variable) + + static VariableModelItem create(CodeModel *model); + +protected: + _VariableModelItem(CodeModel *model, int kind = __node_kind) + : _MemberModelItem(model, kind) {} + +private: + _VariableModelItem(const _VariableModelItem &other); + void operator = (const _VariableModelItem &other); +}; + +class _TypeAliasModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(TypeAlias) + + static TypeAliasModelItem create(CodeModel *model); + +public: + TypeInfo type() const; + void setType(const TypeInfo &type); + +protected: + _TypeAliasModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind) {} + +private: + TypeInfo _M_type; + +private: + _TypeAliasModelItem(const _TypeAliasModelItem &other); + void operator = (const _TypeAliasModelItem &other); +}; + +class _EnumModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Enum) + + static EnumModelItem create(CodeModel *model); + +public: + CodeModel::AccessPolicy accessPolicy() const; + void setAccessPolicy(CodeModel::AccessPolicy accessPolicy); + + EnumeratorList enumerators() const; + void addEnumerator(EnumeratorModelItem item); + void removeEnumerator(EnumeratorModelItem item); + +protected: + _EnumModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind), + _M_accessPolicy(CodeModel::Public) {} + +private: + CodeModel::AccessPolicy _M_accessPolicy; + EnumeratorList _M_enumerators; + +private: + _EnumModelItem(const _EnumModelItem &other); + void operator = (const _EnumModelItem &other); +}; + +class _EnumeratorModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Enumerator) + + static EnumeratorModelItem create(CodeModel *model); + +public: + QString value() const; + void setValue(const QString &value); + +protected: + _EnumeratorModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind) {} + +private: + QString _M_value; + +private: + _EnumeratorModelItem(const _EnumeratorModelItem &other); + void operator = (const _EnumeratorModelItem &other); +}; + +class _TemplateParameterModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(TemplateParameter) + + static TemplateParameterModelItem create(CodeModel *model); + +public: + TypeInfo type() const; + void setType(const TypeInfo &type); + + bool defaultValue() const; + void setDefaultValue(bool defaultValue); + +protected: + _TemplateParameterModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind), _M_defaultValue(false) {} + +private: + TypeInfo _M_type; + bool _M_defaultValue; + +private: + _TemplateParameterModelItem(const _TemplateParameterModelItem &other); + void operator = (const _TemplateParameterModelItem &other); +}; + +template +_Target model_safe_cast(_Source item) +{ + typedef typename _Target::Type * _Target_pointer; + typedef typename _Source::Type * _Source_pointer; + + _Source_pointer source = item.data(); + if (source && source->kind() == _Target_pointer(0)->__node_kind) { + _Target ptr(static_cast<_Target_pointer>(source)); + return ptr; + } + + return _Target(); +} + +template +_Target model_dynamic_cast(_Source item) +{ + typedef typename _Target::Type * _Target_pointer; + typedef typename _Source::Type * _Source_pointer; + + _Source_pointer source = item.data(); + if (source && (source->kind() == _Target_pointer(0)->__node_kind + || (int(_Target_pointer(0)->__node_kind) <= int(_CodeModelItem::KindMask) + && ((source->kind() & _Target_pointer(0)->__node_kind) + == _Target_pointer(0)->__node_kind)))) { + _Target ptr(static_cast<_Target_pointer>(source)); + return ptr; + } + + return _Target(); +} +#endif // CODEMODEL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/codemodel_finder.cpp b/parser/codemodel_finder.cpp new file mode 100644 index 000000000..866ea1cbd --- /dev/null +++ b/parser/codemodel_finder.cpp @@ -0,0 +1,98 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "codemodel_finder.h" +#include "codemodel.h" +#include "binder.h" + +CodeModelFinder::CodeModelFinder(CodeModel *model, Binder *binder) + : _M_model(model), + _M_binder(binder), + _M_token_stream(binder->tokenStream()), + name_cc(_M_binder), + _M_resolve_policy(ResolveItem) +{ +} + +CodeModelFinder::~CodeModelFinder() +{ +} + +ScopeModelItem CodeModelFinder::resolveScope(NameAST *name, ScopeModelItem scope) +{ + Q_ASSERT(scope); + + ResolvePolicy saved_resolve_policy = _M_resolve_policy; + _M_resolve_policy = ResolveScope; + + ScopeModelItem old = changeCurrentScope(scope); + + visit(name); + ScopeModelItem result = _M_current_scope; + + changeCurrentScope(old); // restore + + _M_resolve_policy = saved_resolve_policy; + + return result; +} + +ScopeModelItem CodeModelFinder::changeCurrentScope(ScopeModelItem scope) +{ + ScopeModelItem old = _M_current_scope; + _M_current_scope = scope; + return old; +} + +void CodeModelFinder::visitName(NameAST *node) +{ + visitNodes(this, node->qualified_names); + + if (_M_resolve_policy == ResolveItem) + visit(node->unqualified_name); +} + +void CodeModelFinder::visitUnqualifiedName(UnqualifiedNameAST *node) +{ + if (!_M_current_scope) { + // nothing to do + return; + } + + name_cc.run(node); + QString id = name_cc.name(); + + if (ClassModelItem klass = _M_current_scope->findClass(id)) { + _M_current_scope = klass; + } else if (NamespaceModelItem parentNamespace = model_safe_cast(_M_current_scope)) { + NamespaceModelItem ns = parentNamespace->findNamespace(id); + _M_current_scope = model_static_cast(ns); + } else if (FileModelItem file = model_safe_cast(_M_current_scope)) { + NamespaceModelItem ns = file->findNamespace(id); + _M_current_scope = model_static_cast(ns); + } +} + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/parser/codemodel_finder.h b/parser/codemodel_finder.h new file mode 100644 index 000000000..ac1b5b0eb --- /dev/null +++ b/parser/codemodel_finder.h @@ -0,0 +1,70 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef CODEMODEL_FINDER_H +#define CODEMODEL_FINDER_H + +#include +#include +#include + +class TokenStream; +class Binder; + +class CodeModelFinder: protected DefaultVisitor +{ + enum ResolvePolicy { + ResolveScope, + ResolveItem + }; + +public: + CodeModelFinder(CodeModel *model, Binder *binder); + virtual ~CodeModelFinder(); + + ScopeModelItem resolveScope(NameAST *name, ScopeModelItem scope); + + inline CodeModel *model() const + { + return _M_model; + } + +protected: + virtual void visitName(NameAST *node); + virtual void visitUnqualifiedName(UnqualifiedNameAST *node); + + ScopeModelItem changeCurrentScope(ScopeModelItem scope); + +private: + CodeModel *_M_model; + Binder *_M_binder; + TokenStream *_M_token_stream; + NameCompiler name_cc; + + ScopeModelItem _M_current_scope; + ResolvePolicy _M_resolve_policy; +}; + +#endif // CODEMODEL_FINDER_H diff --git a/parser/codemodel_fwd.h b/parser/codemodel_fwd.h new file mode 100644 index 000000000..96405909c --- /dev/null +++ b/parser/codemodel_fwd.h @@ -0,0 +1,80 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef CODEMODEL_FWD_H +#define CODEMODEL_FWD_H + +#include "codemodel_pointer.h" +#include + +// forward declarations +class CodeModel; +class _ArgumentModelItem; +class _ClassModelItem; +class _CodeModelItem; +class _EnumModelItem; +class _EnumeratorModelItem; +class _FileModelItem; +class _FunctionDefinitionModelItem; +class _FunctionModelItem; +class _NamespaceModelItem; +class _ScopeModelItem; +class _TemplateParameterModelItem; +class _TypeAliasModelItem; +class _VariableModelItem; +class _MemberModelItem; +class TypeInfo; + +typedef CodeModelPointer<_ArgumentModelItem> ArgumentModelItem; +typedef CodeModelPointer<_ClassModelItem> ClassModelItem; +typedef CodeModelPointer<_CodeModelItem> CodeModelItem; +typedef CodeModelPointer<_EnumModelItem> EnumModelItem; +typedef CodeModelPointer<_EnumeratorModelItem> EnumeratorModelItem; +typedef CodeModelPointer<_FileModelItem> FileModelItem; +typedef CodeModelPointer<_FunctionDefinitionModelItem> FunctionDefinitionModelItem; +typedef CodeModelPointer<_FunctionModelItem> FunctionModelItem; +typedef CodeModelPointer<_NamespaceModelItem> NamespaceModelItem; +typedef CodeModelPointer<_ScopeModelItem> ScopeModelItem; +typedef CodeModelPointer<_TemplateParameterModelItem> TemplateParameterModelItem; +typedef CodeModelPointer<_TypeAliasModelItem> TypeAliasModelItem; +typedef CodeModelPointer<_VariableModelItem> VariableModelItem; +typedef CodeModelPointer<_MemberModelItem> MemberModelItem; + +typedef QList ArgumentList; +typedef QList ClassList; +typedef QList ItemList; +typedef QList EnumList; +typedef QList EnumeratorList; +typedef QList FileList; +typedef QList FunctionDefinitionList; +typedef QList FunctionList; +typedef QList NamespaceList; +typedef QList ScopeList; +typedef QList TemplateParameterList; +typedef QList TypeAliasList; +typedef QList VariableList; +typedef QList MemberList; + +#endif // CODEMODEL_FWD_H diff --git a/parser/codemodel_pointer.h b/parser/codemodel_pointer.h new file mode 100644 index 000000000..2c728f3c5 --- /dev/null +++ b/parser/codemodel_pointer.h @@ -0,0 +1,60 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2006 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef CODEMODEL_POINTER_H +#define CODEMODEL_POINTER_H + +#include +#include + +template class CodeModelPointer : public QAtomicPointer +{ +public: + typedef T Type; + + inline CodeModelPointer(T *value = 0) : QAtomicPointer(value) {} + + inline CodeModelPointer &operator=(T *o) + { + QAtomicPointer::operator=(o); + return *this; + } + + inline T *data() + { + return (T *) *this; + } + + inline const T *data() const + { + return (const T *) *this; + } + + inline const T *constData() const + { + return (const T *) *this; + } +}; + +#endif // CODEMODEL_POINTER_H diff --git a/parser/compiler_utils.cpp b/parser/compiler_utils.cpp new file mode 100644 index 000000000..49624149a --- /dev/null +++ b/parser/compiler_utils.cpp @@ -0,0 +1,50 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "compiler_utils.h" +#include "type_compiler.h" +#include "name_compiler.h" +#include "declarator_compiler.h" +#include "ast.h" +#include "binder.h" + +TypeInfo CompilerUtils::typeDescription(TypeSpecifierAST *type_specifier, DeclaratorAST *declarator, Binder *binder) +{ + TypeCompiler type_cc(binder); + DeclaratorCompiler decl_cc(binder); + + type_cc.run(type_specifier); + decl_cc.run(declarator); + + TypeInfo typeInfo; + typeInfo.setQualifiedName(type_cc.qualifiedName()); + typeInfo.setConstant(type_cc.isConstant()); + typeInfo.setVolatile(type_cc.isVolatile()); + typeInfo.setReference(decl_cc.isReference()); + typeInfo.setIndirections(decl_cc.indirection()); + typeInfo.setArrayElements(decl_cc.arrayElements()); + + return typeInfo; +} diff --git a/parser/compiler_utils.h b/parser/compiler_utils.h new file mode 100644 index 000000000..fdd96f15b --- /dev/null +++ b/parser/compiler_utils.h @@ -0,0 +1,47 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef COMPILER_UTILS_H +#define COMPILER_UTILS_H + +#include + +#include "codemodel.h" + +class QString; +class QStringList; +struct TypeSpecifierAST; +struct DeclaratorAST; +class TokenStream; +class Binder; + +namespace CompilerUtils +{ + +TypeInfo typeDescription(TypeSpecifierAST *type_specifier, DeclaratorAST *declarator, Binder *binder); + +} // namespace CompilerUtils + +#endif // COMPILER_UTILS_H diff --git a/parser/control.cpp b/parser/control.cpp new file mode 100644 index 000000000..9615debba --- /dev/null +++ b/parser/control.cpp @@ -0,0 +1,130 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "control.h" +#include "lexer.h" + +Control::Control() + : current_context(0), + _M_skipFunctionBody(false), + _M_lexer(0), + _M_parser(0) +{ + pushContext(); + + declareTypedef(findOrInsertName("__builtin_va_list", + strlen("__builtin_va_list")), 0); +} + +Control::~Control() +{ + popContext(); + + Q_ASSERT(current_context == 0); +} + +Lexer *Control::changeLexer(Lexer *lexer) +{ + Lexer *old = _M_lexer; + _M_lexer = lexer; + return old; +} + +Parser *Control::changeParser(Parser *parser) +{ + Parser *old = _M_parser; + _M_parser = parser; + return old; +} + +Type *Control::lookupType(const NameSymbol *name) const +{ + Q_ASSERT(current_context != 0); + + return current_context->resolve(name); +} + +void Control::declare(const NameSymbol *name, Type *type) +{ + //printf("*** Declare:"); + //printSymbol(name); + //putchar('\n'); + Q_ASSERT(current_context != 0); + + current_context->bind(name, type); +} + +void Control::pushContext() +{ + // printf("+Context\n"); + Context *new_context = new Context; + new_context->parent = current_context; + current_context = new_context; +} + +void Control::popContext() +{ + // printf("-Context\n"); + Q_ASSERT(current_context != 0); + + Context *old_context = current_context; + current_context = current_context->parent; + + delete old_context; +} + +void Control::declareTypedef(const NameSymbol *name, Declarator *d) +{ + // printf("declared typedef:"); + // printSymbol(name); + // printf("\n"); + stl_typedef_table.insert(name, d); +} + +bool Control::isTypedef(const NameSymbol *name) const +{ + // printf("is typedef:"); + // printSymbol(name); + // printf("= %d\n", (stl_typedef_table.find(name) != stl_typedef_table.end())); + + return stl_typedef_table.contains(name); +} + +QList Control::errorMessages() const +{ + return _M_error_messages; +} + +void Control::clearErrorMessages() +{ + _M_error_messages.clear(); +} + +void Control::reportError(const ErrorMessage &errmsg) +{ + _M_error_messages.append(errmsg); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/control.h b/parser/control.h new file mode 100644 index 000000000..533db912c --- /dev/null +++ b/parser/control.h @@ -0,0 +1,160 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef CONTROL_H +#define CONTROL_H + +#include "symbol.h" +#include "smallobject.h" + +#include + +struct Declarator; +struct Type; +class Lexer; +class Parser; + +struct Context { + Context *parent; + + inline void bind(const NameSymbol *name, Type *type) { + symbol_table.insert(name, type); + } + + inline Type *resolve(const NameSymbol *name) const { + if (Type *type = symbol_table.value(name)) + return type; + else if (parent) + return parent->resolve(name); + + return 0; + } + + typedef QHash symbol_table_t; + + symbol_table_t symbol_table; +}; + +class Control +{ +public: + class ErrorMessage + { + public: + ErrorMessage(): + _M_line(0), + _M_column(0) {} + + inline int line() const { + return _M_line; + } + inline void setLine(int line) { + _M_line = line; + } + + inline int column() const { + return _M_column; + } + inline void setColumn(int column) { + _M_column = column; + } + + inline QString fileName() const { + return _M_fileName; + } + inline void setFileName(const QString &fileName) { + _M_fileName = fileName; + } + + inline QString message() const { + return _M_message; + } + inline void setMessage(const QString &message) { + _M_message = message; + } + + private: + int _M_line; + int _M_column; + QString _M_fileName; + QString _M_message; + }; + + Control(); + ~Control(); + + inline bool skipFunctionBody() const { + return _M_skipFunctionBody; + } + inline void setSkipFunctionBody(bool skip) { + _M_skipFunctionBody = skip; + } + + Lexer *changeLexer(Lexer *lexer); + Parser *changeParser(Parser *parser); + + Lexer *currentLexer() const { + return _M_lexer; + } + Parser *currentParser() const { + return _M_parser; + } + + Context *current_context; + + inline Context *currentContext() const { + return current_context; + } + + void pushContext(); + void popContext(); + + Type *lookupType(const NameSymbol *name) const; + void declare(const NameSymbol *name, Type *type); + + inline const NameSymbol *findOrInsertName(const char *data, size_t count) { + return name_table.findOrInsert(data, count); + } + + void declareTypedef(const NameSymbol *name, Declarator *d); + bool isTypedef(const NameSymbol *name) const; + + void reportError(const ErrorMessage &errmsg); + QList errorMessages() const; + void clearErrorMessages(); + +private: + NameTable name_table; + QHash stl_typedef_table; + bool _M_skipFunctionBody; + Lexer *_M_lexer; + Parser *_M_parser; + + QList _M_error_messages; +}; + +#endif // CONTROL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/declarator_compiler.cpp b/parser/declarator_compiler.cpp new file mode 100644 index 000000000..255bfcddb --- /dev/null +++ b/parser/declarator_compiler.cpp @@ -0,0 +1,147 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "declarator_compiler.h" +#include "name_compiler.h" +#include "type_compiler.h" +#include "compiler_utils.h" +#include "lexer.h" +#include "binder.h" +#include "tokens.h" + +#include + +DeclaratorCompiler::DeclaratorCompiler(Binder *binder) + : _M_binder(binder), _M_token_stream(binder->tokenStream()) +{ +} + +void DeclaratorCompiler::run(DeclaratorAST *node) +{ + _M_id.clear(); + _M_parameters.clear(); + _M_array.clear(); + _M_function = false; + _M_reference = false; + _M_variadics = false; + _M_indirection = 0; + + if (node) { + NameCompiler name_cc(_M_binder); + + DeclaratorAST *decl = node; + while (decl && decl->sub_declarator) + decl = decl->sub_declarator; + + Q_ASSERT(decl != 0); + + name_cc.run(decl->id); + _M_id = name_cc.name(); + _M_function = (node->parameter_declaration_clause != 0); + if (node->parameter_declaration_clause && node->parameter_declaration_clause->ellipsis) + _M_variadics = true; + + visitNodes(this, node->ptr_ops); + visit(node->parameter_declaration_clause); + + if (const ListNode *it = node->array_dimensions) { + it->toFront(); + const ListNode *end = it; + + do { + QString elt; + if (ExpressionAST *expr = it->element) { + const Token &start_token = _M_token_stream->token((int) expr->start_token); + const Token &end_token = _M_token_stream->token((int) expr->end_token); + + elt += QString::fromUtf8(&start_token.text[start_token.position], + (int)(end_token.position - start_token.position)).trimmed(); + } + + _M_array.append(elt); + + it = it->next; + } while (it != end); + } + } +} + +void DeclaratorCompiler::visitPtrOperator(PtrOperatorAST *node) +{ + std::size_t op = _M_token_stream->kind(node->op); + + switch (op) { + case '&': + _M_reference = true; + break; + case '*': + ++_M_indirection; + break; + + default: + break; + } + + if (node->mem_ptr) { +#if defined(__GNUC__) +#warning "ptr to mem -- not implemented" +#endif + } +} + +void DeclaratorCompiler::visitParameterDeclaration(ParameterDeclarationAST *node) +{ + Parameter p; + + TypeCompiler type_cc(_M_binder); + DeclaratorCompiler decl_cc(_M_binder); + + decl_cc.run(node->declarator); + + p.name = decl_cc.id(); + p.type = CompilerUtils::typeDescription(node->type_specifier, node->declarator, _M_binder); + if (node->expression != 0) { + const Token &start = _M_token_stream->token((int) node->expression->start_token); + const Token &end = _M_token_stream->token((int) node->expression->end_token); + int length = (int)(end.position - start.position); + + p.defaultValueExpression = QString(); + QString source = QString::fromUtf8(&start.text[start.position], length).trimmed(); + QStringList list = source.split("\n"); + + + for (int i = 0; i < list.size(); ++i) { + if (!list.at(i).startsWith("#")) + p.defaultValueExpression += list.at(i).trimmed(); + } + + p.defaultValue = p.defaultValueExpression.size() > 0; + + } + + _M_parameters.append(p); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/declarator_compiler.h b/parser/declarator_compiler.h new file mode 100644 index 000000000..70a65b058 --- /dev/null +++ b/parser/declarator_compiler.h @@ -0,0 +1,96 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef DECLARATOR_COMPILER_H +#define DECLARATOR_COMPILER_H + +#include "default_visitor.h" +#include "codemodel.h" + +#include +#include + +class TokenStream; +class Binder; + +class DeclaratorCompiler: protected DefaultVisitor +{ +public: + struct Parameter { + TypeInfo type; + QString name; + QString defaultValueExpression; + bool defaultValue; + + Parameter(): defaultValue(false) {} + }; + +public: + DeclaratorCompiler(Binder *binder); + + void run(DeclaratorAST *node); + + inline QString id() const { + return _M_id; + } + inline QStringList arrayElements() const { + return _M_array; + } + inline bool isFunction() const { + return _M_function; + } + inline bool isVariadics() const { + return _M_variadics; + } + inline bool isReference() const { + return _M_reference; + } + inline int indirection() const { + return _M_indirection; + } + inline QList parameters() const { + return _M_parameters; + } + +protected: + virtual void visitPtrOperator(PtrOperatorAST *node); + virtual void visitParameterDeclaration(ParameterDeclarationAST *node); + +private: + Binder *_M_binder; + TokenStream *_M_token_stream; + + bool _M_function; + bool _M_reference; + bool _M_variadics; + int _M_indirection; + QString _M_id; + QStringList _M_array; + QList _M_parameters; +}; + +#endif // DECLARATOR_COMPILER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/default_visitor.cpp b/parser/default_visitor.cpp new file mode 100644 index 000000000..07ab968cc --- /dev/null +++ b/parser/default_visitor.cpp @@ -0,0 +1,459 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "default_visitor.h" + +void DefaultVisitor::visitAccessSpecifier(AccessSpecifierAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitAsmDefinition(AsmDefinitionAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitBaseClause(BaseClauseAST *node) +{ + visitNodes(this, node->base_specifiers); +} + +void DefaultVisitor::visitBaseSpecifier(BaseSpecifierAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitBinaryExpression(BinaryExpressionAST *node) +{ + visit(node->left_expression); + visit(node->right_expression); +} + +void DefaultVisitor::visitCastExpression(CastExpressionAST *node) +{ + visit(node->type_id); + visit(node->expression); +} + +void DefaultVisitor::visitClassMemberAccess(ClassMemberAccessAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitClassSpecifier(ClassSpecifierAST *node) +{ + visit(node->win_decl_specifiers); + visit(node->name); + visit(node->base_clause); + visitNodes(this, node->member_specs); +} + +void DefaultVisitor::visitCompoundStatement(CompoundStatementAST *node) +{ + visitNodes(this, node->statements); +} + +void DefaultVisitor::visitCondition(ConditionAST *node) +{ + visit(node->type_specifier); + visit(node->declarator); + visit(node->expression); +} + +void DefaultVisitor::visitConditionalExpression(ConditionalExpressionAST *node) +{ + visit(node->condition); + visit(node->left_expression); + visit(node->right_expression); +} + +void DefaultVisitor::visitCppCastExpression(CppCastExpressionAST *node) +{ + visit(node->type_id); + visit(node->expression); + visitNodes(this, node->sub_expressions); +} + +void DefaultVisitor::visitCtorInitializer(CtorInitializerAST *node) +{ + visitNodes(this, node->member_initializers); +} + +void DefaultVisitor::visitDeclarationStatement(DeclarationStatementAST *node) +{ + visit(node->declaration); +} + +void DefaultVisitor::visitDeclarator(DeclaratorAST *node) +{ + visit(node->sub_declarator); + visitNodes(this, node->ptr_ops); + visit(node->id); + visit(node->bit_expression); + visitNodes(this, node->array_dimensions); + visit(node->parameter_declaration_clause); + visit(node->exception_spec); +} + +void DefaultVisitor::visitDeleteExpression(DeleteExpressionAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitDoStatement(DoStatementAST *node) +{ + visit(node->statement); + visit(node->expression); +} + +void DefaultVisitor::visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitEnumSpecifier(EnumSpecifierAST *node) +{ + visit(node->name); + visitNodes(this, node->enumerators); +} + +void DefaultVisitor::visitEnumerator(EnumeratorAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitExceptionSpecification(ExceptionSpecificationAST *node) +{ + visitNodes(this, node->type_ids); +} + +void DefaultVisitor::visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *node) +{ + visit(node->expression); + visit(node->declaration); +} + +void DefaultVisitor::visitExpressionStatement(ExpressionStatementAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitForStatement(ForStatementAST *node) +{ + visit(node->init_statement); + visit(node->condition); + visit(node->expression); + visit(node->statement); +} + +void DefaultVisitor::visitFunctionCall(FunctionCallAST *node) +{ + visit(node->arguments); +} + +void DefaultVisitor::visitFunctionDefinition(FunctionDefinitionAST *node) +{ + visit(node->type_specifier); + visit(node->init_declarator); + visit(node->function_body); + visit(node->win_decl_specifiers); +} + +void DefaultVisitor::visitIfStatement(IfStatementAST *node) +{ + visit(node->condition); + visit(node->statement); + visit(node->else_statement); +} + +void DefaultVisitor::visitIncrDecrExpression(IncrDecrExpressionAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitInitDeclarator(InitDeclaratorAST *node) +{ + visit(node->declarator); + visit(node->initializer); +} + +void DefaultVisitor::visitInitializer(InitializerAST *node) +{ + visit(node->initializer_clause); + visit(node->expression); +} + +void DefaultVisitor::visitInitializerClause(InitializerClauseAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitLabeledStatement(LabeledStatementAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitLinkageBody(LinkageBodyAST *node) +{ + visitNodes(this, node->declarations); +} + +void DefaultVisitor::visitLinkageSpecification(LinkageSpecificationAST *node) +{ + visit(node->linkage_body); + visit(node->declaration); +} + +void DefaultVisitor::visitMemInitializer(MemInitializerAST *node) +{ + visit(node->initializer_id); + visit(node->expression); +} + +void DefaultVisitor::visitName(NameAST *node) +{ + visitNodes(this, node->qualified_names); + visit(node->unqualified_name); +} + +void DefaultVisitor::visitNamespace(NamespaceAST *node) +{ + visit(node->linkage_body); +} + +void DefaultVisitor::visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *node) +{ + visit(node->alias_name); +} + +void DefaultVisitor::visitNewDeclarator(NewDeclaratorAST *node) +{ + visit(node->ptr_op); + visit(node->sub_declarator); + visitNodes(this, node->expressions); +} + +void DefaultVisitor::visitNewExpression(NewExpressionAST *node) +{ + visit(node->expression); + visit(node->type_id); + visit(node->new_type_id); + visit(node->new_initializer); +} + +void DefaultVisitor::visitNewInitializer(NewInitializerAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitNewTypeId(NewTypeIdAST *node) +{ + visit(node->type_specifier); + visit(node->new_initializer); + visit(node->new_declarator); +} + +void DefaultVisitor::visitOperator(OperatorAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitOperatorFunctionId(OperatorFunctionIdAST *node) +{ + visit(node->op); + visit(node->type_specifier); + visitNodes(this, node->ptr_ops); +} + +void DefaultVisitor::visitParameterDeclaration(ParameterDeclarationAST *node) +{ + visit(node->type_specifier); + visit(node->declarator); + visit(node->expression); +} + +void DefaultVisitor::visitParameterDeclarationClause(ParameterDeclarationClauseAST *node) +{ + visitNodes(this, node->parameter_declarations); +} + +void DefaultVisitor::visitPostfixExpression(PostfixExpressionAST *node) +{ + visit(node->type_specifier); + visit(node->expression); + visitNodes(this, node->sub_expressions); +} + +void DefaultVisitor::visitPrimaryExpression(PrimaryExpressionAST *node) +{ + visit(node->literal); + visit(node->expression_statement); + visit(node->sub_expression); + visit(node->name); +} + +void DefaultVisitor::visitPtrOperator(PtrOperatorAST *node) +{ + visit(node->mem_ptr); +} + +void DefaultVisitor::visitPtrToMember(PtrToMemberAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitReturnStatement(ReturnStatementAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitSimpleDeclaration(SimpleDeclarationAST *node) +{ + visit(node->type_specifier); + visitNodes(this, node->init_declarators); + visit(node->win_decl_specifiers); +} + +void DefaultVisitor::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node) +{ + visit(node->name); + visit(node->type_id); + visit(node->expression); +} + +void DefaultVisitor::visitSizeofExpression(SizeofExpressionAST *node) +{ + visit(node->type_id); + visit(node->expression); +} + +void DefaultVisitor::visitStringLiteral(StringLiteralAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitSubscriptExpression(SubscriptExpressionAST *node) +{ + visit(node->subscript); +} + +void DefaultVisitor::visitSwitchStatement(SwitchStatementAST *node) +{ + visit(node->condition); + visit(node->statement); +} + +void DefaultVisitor::visitTemplateArgument(TemplateArgumentAST *node) +{ + visit(node->type_id); + visit(node->expression); +} + +void DefaultVisitor::visitTemplateDeclaration(TemplateDeclarationAST *node) +{ + visitNodes(this, node->template_parameters); + visit(node->declaration); +} + +void DefaultVisitor::visitTemplateParameter(TemplateParameterAST *node) +{ + visit(node->type_parameter); + visit(node->parameter_declaration); +} + +void DefaultVisitor::visitThrowExpression(ThrowExpressionAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitTranslationUnit(TranslationUnitAST *node) +{ + visitNodes(this, node->declarations); +} + +void DefaultVisitor::visitTryBlockStatement(TryBlockStatementAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitTypeId(TypeIdAST *node) +{ + visit(node->type_specifier); + visit(node->declarator); +} + +void DefaultVisitor::visitTypeIdentification(TypeIdentificationAST *node) +{ + visit(node->name); + visit(node->expression); +} + +void DefaultVisitor::visitTypeParameter(TypeParameterAST *node) +{ + visit(node->name); + visit(node->type_id); + visitNodes(this, node->template_parameters); + visit(node->template_name); +} + +void DefaultVisitor::visitTypedef(TypedefAST *node) +{ + visit(node->type_specifier); + visitNodes(this, node->init_declarators); +} + +void DefaultVisitor::visitUnaryExpression(UnaryExpressionAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitUnqualifiedName(UnqualifiedNameAST *node) +{ + visit(node->operator_id); + visitNodes(this, node->template_arguments); +} + +void DefaultVisitor::visitUsing(UsingAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitUsingDirective(UsingDirectiveAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitWhileStatement(WhileStatementAST *node) +{ + visit(node->condition); + visit(node->statement); +} + +void DefaultVisitor::visitWinDeclSpec(WinDeclSpecAST *) +{ + // nothing to do +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/default_visitor.h b/parser/default_visitor.h new file mode 100644 index 000000000..ec1caf3bc --- /dev/null +++ b/parser/default_visitor.h @@ -0,0 +1,118 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef DEFAULT_VISITOR_H +#define DEFAULT_VISITOR_H + +#include "visitor.h" + +class DefaultVisitor: public Visitor +{ +public: + DefaultVisitor() {} + +protected: + virtual void visitAccessSpecifier(AccessSpecifierAST *); + virtual void visitAsmDefinition(AsmDefinitionAST *); + virtual void visitBaseClause(BaseClauseAST *); + virtual void visitBaseSpecifier(BaseSpecifierAST *); + virtual void visitBinaryExpression(BinaryExpressionAST *); + virtual void visitCastExpression(CastExpressionAST *); + virtual void visitClassMemberAccess(ClassMemberAccessAST *); + virtual void visitClassSpecifier(ClassSpecifierAST *); + virtual void visitCompoundStatement(CompoundStatementAST *); + virtual void visitCondition(ConditionAST *); + virtual void visitConditionalExpression(ConditionalExpressionAST *); + virtual void visitCppCastExpression(CppCastExpressionAST *); + virtual void visitCtorInitializer(CtorInitializerAST *); + virtual void visitDeclarationStatement(DeclarationStatementAST *); + virtual void visitDeclarator(DeclaratorAST *); + virtual void visitDeleteExpression(DeleteExpressionAST *); + virtual void visitDoStatement(DoStatementAST *); + virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *); + virtual void visitEnumSpecifier(EnumSpecifierAST *); + virtual void visitEnumerator(EnumeratorAST *); + virtual void visitExceptionSpecification(ExceptionSpecificationAST *); + virtual void visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *); + virtual void visitExpressionStatement(ExpressionStatementAST *); + virtual void visitForStatement(ForStatementAST *); + virtual void visitFunctionCall(FunctionCallAST *); + virtual void visitFunctionDefinition(FunctionDefinitionAST *); + virtual void visitIfStatement(IfStatementAST *); + virtual void visitIncrDecrExpression(IncrDecrExpressionAST *); + virtual void visitInitDeclarator(InitDeclaratorAST *); + virtual void visitInitializer(InitializerAST *); + virtual void visitInitializerClause(InitializerClauseAST *); + virtual void visitLabeledStatement(LabeledStatementAST *); + virtual void visitLinkageBody(LinkageBodyAST *); + virtual void visitLinkageSpecification(LinkageSpecificationAST *); + virtual void visitMemInitializer(MemInitializerAST *); + virtual void visitName(NameAST *); + virtual void visitNamespace(NamespaceAST *); + virtual void visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *); + virtual void visitNewDeclarator(NewDeclaratorAST *); + virtual void visitNewExpression(NewExpressionAST *); + virtual void visitNewInitializer(NewInitializerAST *); + virtual void visitNewTypeId(NewTypeIdAST *); + virtual void visitOperator(OperatorAST *); + virtual void visitOperatorFunctionId(OperatorFunctionIdAST *); + virtual void visitParameterDeclaration(ParameterDeclarationAST *); + virtual void visitParameterDeclarationClause(ParameterDeclarationClauseAST *); + virtual void visitPostfixExpression(PostfixExpressionAST *); + virtual void visitPrimaryExpression(PrimaryExpressionAST *); + virtual void visitPtrOperator(PtrOperatorAST *); + virtual void visitPtrToMember(PtrToMemberAST *); + virtual void visitReturnStatement(ReturnStatementAST *); + virtual void visitSimpleDeclaration(SimpleDeclarationAST *); + virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *); + virtual void visitSizeofExpression(SizeofExpressionAST *); + virtual void visitStringLiteral(StringLiteralAST *); + virtual void visitSubscriptExpression(SubscriptExpressionAST *); + virtual void visitSwitchStatement(SwitchStatementAST *); + virtual void visitTemplateArgument(TemplateArgumentAST *); + virtual void visitTemplateDeclaration(TemplateDeclarationAST *); + virtual void visitTemplateParameter(TemplateParameterAST *); + virtual void visitThrowExpression(ThrowExpressionAST *); + virtual void visitTranslationUnit(TranslationUnitAST *); + virtual void visitTryBlockStatement(TryBlockStatementAST *); + virtual void visitTypeId(TypeIdAST *); + virtual void visitTypeIdentification(TypeIdentificationAST *); + virtual void visitTypeParameter(TypeParameterAST *); + virtual void visitTypedef(TypedefAST *); + virtual void visitUnaryExpression(UnaryExpressionAST *); + virtual void visitUnqualifiedName(UnqualifiedNameAST *); + virtual void visitUsing(UsingAST *); + virtual void visitUsingDirective(UsingDirectiveAST *); + virtual void visitWhileStatement(WhileStatementAST *); + virtual void visitWinDeclSpec(WinDeclSpecAST *); + +private: + typedef void (Visitor::*visitor_fun_ptr)(AST *); + static visitor_fun_ptr _S_table[]; +}; + +#endif // VISITOR_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/dumptree.cpp b/parser/dumptree.cpp new file mode 100644 index 000000000..1514b0f64 --- /dev/null +++ b/parser/dumptree.cpp @@ -0,0 +1,125 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "dumptree.h" + +#include +#include + +static char const * const names[] = { + 0, + "AccessSpecifier", + "AsmDefinition", + "BaseClause", + "BaseSpecifier", + "BinaryExpression", + "CastExpression", + "ClassMemberAccess", + "ClassSpecifier", + "CompoundStatement", + "Condition", + "ConditionalExpression", + "CppCastExpression", + "CtorInitializer", + "DeclarationStatement", + "Declarator", + "DeleteExpression", + "DoStatement", + "ElaboratedTypeSpecifier", + "EnumSpecifier", + "Enumerator", + "ExceptionSpecification", + "ExpressionOrDeclarationStatement", + "ExpressionStatement", + "ForStatement", + "FunctionCall", + "FunctionDefinition", + "IfStatement", + "IncrDecrExpression", + "InitDeclarator", + "Initializer", + "InitializerClause", + "LabeledStatement", + "LinkageBody", + "LinkageSpecification", + "MemInitializer", + "Name", + "Namespace", + "NamespaceAliasDefinition", + "NewDeclarator", + "NewExpression", + "NewInitializer", + "NewTypeId", + "Operator", + "OperatorFunctionId", + "ParameterDeclaration", + "ParameterDeclarationClause", + "PostfixExpression", + "PrimaryExpression", + "PtrOperator", + "PtrToMember", + "ReturnStatement", + "SimpleDeclaration", + "SimpleTypeSpecifier", + "SizeofExpression", + "StringLiteral", + "SubscriptExpression", + "SwitchStatement", + "TemplateArgument", + "TemplateDeclaration", + "TemplateParameter", + "ThrowExpression", + "TranslationUnit", + "TryBlockStatement", + "TypeId", + "TypeIdentification", + "TypeParameter", + "Typedef", + "UnaryExpression", + "UnqualifiedName", + "Using", + "UsingDirective", + "WhileStatement", + "WinDeclSpec" +}; + +DumpTree::DumpTree() +{ +} + +void DumpTree::visit(AST *node) +{ + static int indent = 0; + + if (node) + qDebug() << QString(indent * 2, ' ').toLatin1().constData() << names[node->kind] + << '[' << node->start_token << ", " << node->end_token << ']'; + + ++indent; + DefaultVisitor::visit(node); + --indent; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/dumptree.h b/parser/dumptree.h new file mode 100644 index 000000000..cfc55e2e6 --- /dev/null +++ b/parser/dumptree.h @@ -0,0 +1,46 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef DUMPTREE_H +#define DUMPTREE_H + +#include "default_visitor.h" + +class DumpTree: protected DefaultVisitor +{ +public: + DumpTree(); + + void dump(AST *node) { + visit(node); + } + +protected: + virtual void visit(AST *node); +}; + +#endif // DUMPTREE_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/lexer.cpp b/parser/lexer.cpp new file mode 100644 index 000000000..2abb540d0 --- /dev/null +++ b/parser/lexer.cpp @@ -0,0 +1,1695 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "lexer.h" +#include "tokens.h" +#include "control.h" + +#include +#include + +scan_fun_ptr Lexer::s_scan_keyword_table[] = { + &Lexer::scanKeyword0, &Lexer::scanKeyword0, + &Lexer::scanKeyword2, &Lexer::scanKeyword3, + &Lexer::scanKeyword4, &Lexer::scanKeyword5, + &Lexer::scanKeyword6, &Lexer::scanKeyword7, + &Lexer::scanKeyword8, &Lexer::scanKeyword9, + &Lexer::scanKeyword10, &Lexer::scanKeyword11, + &Lexer::scanKeyword12, &Lexer::scanKeyword13, + &Lexer::scanKeyword14, &Lexer::scanKeyword0, + &Lexer::scanKeyword16 +}; + +void LocationManager::extract_line(int offset, int *line, QString *filename) const +{ + *line = 0; + if (token_stream.size() < 1) + return; + + const unsigned char *begin_buffer = reinterpret_cast(token_stream[0].text); + const unsigned char *cursor = begin_buffer + offset; + + ++cursor; // skip '#' + if (std::isspace(*cursor) && std::isdigit(*(cursor + 1))) { + ++cursor; + char buffer[1024], *cp = buffer; + do { + *cp++ = *cursor++; + } while (std::isdigit(*cursor)); + *cp = '\0'; + int l = strtol(buffer, 0, 0); + + Q_ASSERT(std::isspace(*cursor)); + ++cursor; + + Q_ASSERT(*cursor == '"'); + ++cursor; + + cp = buffer; + while (*cursor && *cursor != '"') { + *cp++ = *cursor++; + } + *cp = '\0'; + Q_ASSERT(*cursor == '"'); + ++cursor; + + *filename = buffer; + *line = l; + // printf("filename: %s line: %d\n", buffer, line); + } +} + +void LocationManager::positionAt(std::size_t offset, int *line, int *column, + QString *filename) const +{ + int ppline, ppcolumn; + line_table.positionAt(offset, &ppline, &ppcolumn); + + int base_line; + extract_line((int) line_table[ppline-1], &base_line, filename); + + int line2, column2; + location_table.positionAt((int) line_table[ppline-1], &line2, &column2); + + location_table.positionAt(offset, line, column); + *line = base_line + *line - line2 - 1; +} + +scan_fun_ptr Lexer::s_scan_table[256]; +bool Lexer::s_initialized = false; + +void Lexer::tokenize(const char *contents, std::size_t size) +{ + if (!s_initialized) + initialize_scan_table(); + + token_stream.resize(1024); + token_stream[0].kind = Token_EOF; + token_stream[0].text = contents; + + index = 1; + + cursor = (const unsigned char *) contents; + begin_buffer = (const unsigned char *) contents; + end_buffer = cursor + size; + + location_table.resize(1024); + location_table[0] = 0; + location_table.current_line = 1; + + line_table.resize(1024); + line_table[0] = 0; + line_table.current_line = 1; + + do { + if (index == token_stream.size()) + token_stream.resize(token_stream.size() * 2); + + Token *current_token = &token_stream[(int) index]; + current_token->text = reinterpret_cast(begin_buffer); + current_token->position = cursor - begin_buffer; + (this->*s_scan_table[*cursor])(); + current_token->size = cursor - begin_buffer - current_token->position; + } while (cursor < end_buffer); + + if (index == token_stream.size()) + token_stream.resize(token_stream.size() * 2); + + Q_ASSERT(index < token_stream.size()); + token_stream[(int) index].position = cursor - begin_buffer; + token_stream[(int) index].kind = Token_EOF; +} + +void Lexer::reportError(const QString& msg) +{ + int line, column; + QString fileName; + + std::size_t tok = token_stream.cursor(); + _M_location.positionAt(token_stream.position(tok), + &line, &column, &fileName); + + Control::ErrorMessage errmsg; + errmsg.setLine(line + 1); + errmsg.setColumn(column); + errmsg.setFileName(fileName); + errmsg.setMessage(QLatin1String("** LEXER ERROR ") + msg); + control->reportError(errmsg); +} + +void Lexer::initialize_scan_table() +{ + s_initialized = true; + + for (int i = 0; i < 256; ++i) { + if (isspace(i)) + s_scan_table[i] = &Lexer::scan_white_spaces; + else if (isalpha(i) || i == '_') + s_scan_table[i] = &Lexer::scan_identifier_or_keyword; + else if (isdigit(i)) + s_scan_table[i] = &Lexer::scan_int_constant; + else + s_scan_table[i] = &Lexer::scan_invalid_input; + } + + s_scan_table[int('L')] = &Lexer::scan_identifier_or_literal; + s_scan_table[int('\n')] = &Lexer::scan_newline; + s_scan_table[int('#')] = &Lexer::scan_preprocessor; + + s_scan_table[int('\'')] = &Lexer::scan_char_constant; + s_scan_table[int('"')] = &Lexer::scan_string_constant; + + s_scan_table[int('.')] = &Lexer::scan_int_constant; + + s_scan_table[int('!')] = &Lexer::scan_not; + s_scan_table[int('%')] = &Lexer::scan_remainder; + s_scan_table[int('&')] = &Lexer::scan_and; + s_scan_table[int('(')] = &Lexer::scan_left_paren; + s_scan_table[int(')')] = &Lexer::scan_right_paren; + s_scan_table[int('*')] = &Lexer::scan_star; + s_scan_table[int('+')] = &Lexer::scan_plus; + s_scan_table[int(',')] = &Lexer::scan_comma; + s_scan_table[int('-')] = &Lexer::scan_minus; + s_scan_table[int('/')] = &Lexer::scan_divide; + s_scan_table[int(':')] = &Lexer::scan_colon; + s_scan_table[int(';')] = &Lexer::scan_semicolon; + s_scan_table[int('<')] = &Lexer::scan_less; + s_scan_table[int('=')] = &Lexer::scan_equal; + s_scan_table[int('>')] = &Lexer::scan_greater; + s_scan_table[int('?')] = &Lexer::scan_question; + s_scan_table[int('[')] = &Lexer::scan_left_bracket; + s_scan_table[int(']')] = &Lexer::scan_right_bracket; + s_scan_table[int('^')] = &Lexer::scan_xor; + s_scan_table[int('{')] = &Lexer::scan_left_brace; + s_scan_table[int('|')] = &Lexer::scan_or; + s_scan_table[int('}')] = &Lexer::scan_right_brace; + s_scan_table[int('~')] = &Lexer::scan_tilde; + + s_scan_table[0] = &Lexer::scan_EOF; +} + +void Lexer::scan_preprocessor() +{ + if (line_table.current_line == line_table.size()) + line_table.resize(line_table.current_line * 2); + + line_table[(int) line_table.current_line++] = (cursor - begin_buffer); + + while (*cursor && *cursor != '\n') + ++cursor; + + if (*cursor != '\n') + reportError("expected newline"); +} + +void Lexer::scan_char_constant() +{ + const unsigned char *begin = cursor; + + ++cursor; + while (*cursor && *cursor != '\'') { + if (*cursor == '\n') + reportError("did not expect newline"); + + if (*cursor == '\\') + ++cursor; + ++cursor; + } + + if (*cursor != '\'') + reportError("expected \'"); + + ++cursor; + + token_stream[(int) index].extra.symbol = + control->findOrInsertName((const char*) begin, cursor - begin); + + token_stream[(int) index++].kind = Token_char_literal; +} + +void Lexer::scan_string_constant() +{ + const unsigned char *begin = cursor; + + ++cursor; + while (*cursor && *cursor != '"') { + if (*cursor == '\n') + reportError("did not expect newline"); + + if (*cursor == '\\') + ++cursor; + ++cursor; + } + + if (*cursor != '"') + reportError("expected \""); + + ++cursor; + + token_stream[(int) index].extra.symbol = + control->findOrInsertName((const char*) begin, cursor - begin); + + token_stream[(int) index++].kind = Token_string_literal; +} + +void Lexer::scan_newline() +{ + if (location_table.current_line == location_table.size()) + location_table.resize(location_table.current_line * 2); + + location_table[(int) location_table.current_line++] = (cursor - begin_buffer); + ++cursor; +} + +void Lexer::scan_white_spaces() +{ + while (isspace(*cursor)) { + if (*cursor == '\n') + scan_newline(); + else + ++cursor; + } +} + +void Lexer::scan_identifier_or_literal() +{ + switch (*(cursor + 1)) { + case '\'': + ++cursor; + scan_char_constant(); + break; + + case '\"': + ++cursor; + scan_string_constant(); + break; + + default: + scan_identifier_or_keyword(); + break; + } +} + +void Lexer::scan_identifier_or_keyword() +{ + const unsigned char *skip = cursor; + while (isalnum(*skip) || *skip == '_') + ++skip; + + int n = skip - cursor; + Token *current_token = &token_stream[(int) index]; + (this->*s_scan_keyword_table[n < 17 ? n : 0])(); + + if (current_token->kind == Token_identifier) { + current_token->extra.symbol = + control->findOrInsertName((const char*) cursor, n); + } + + cursor = skip; +} + +void Lexer::scan_int_constant() +{ + if (*cursor == '.' && !std::isdigit(*(cursor + 1))) { + scan_dot(); + return; + } + + const unsigned char *begin = cursor; + + while (isalnum(*cursor) || *cursor == '.') + ++cursor; + + token_stream[(int) index].extra.symbol = + control->findOrInsertName((const char*) begin, cursor - begin); + + token_stream[(int) index++].kind = Token_number_literal; +} + +void Lexer::scan_not() +{ + /* + '!' ::= not + '!=' ::= not_equal + */ + + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_not_eq; + } else { + token_stream[(int) index++].kind = '!'; + } +} + +void Lexer::scan_remainder() +{ + /* + '%' ::= remainder + '%=' ::= remainder_equal + */ + + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = '%'; + } +} + +void Lexer::scan_and() +{ + /* + '&&' ::= and_and + '&' ::= and + '&=' ::= and_equal + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else if (*cursor == '&') { + ++cursor; + token_stream[(int) index++].kind = Token_and; + } else { + token_stream[(int) index++].kind = '&'; + } +} + +void Lexer::scan_left_paren() +{ + ++cursor; + token_stream[(int) index++].kind = '('; +} + +void Lexer::scan_right_paren() +{ + ++cursor; + token_stream[(int) index++].kind = ')'; +} + +void Lexer::scan_star() +{ + /* + '*' ::= star + '*=' ::= star_equal + */ + + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = '*'; + } +} + +void Lexer::scan_plus() +{ + /* + '+' ::= plus + '++' ::= incr + '+=' ::= plus_equal + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else if (*cursor == '+') { + ++cursor; + token_stream[(int) index++].kind = Token_incr; + } else { + token_stream[(int) index++].kind = '+'; + } +} + +void Lexer::scan_comma() +{ + ++cursor; + token_stream[(int) index++].kind = ','; +} + +void Lexer::scan_minus() +{ + /* + '-' ::= minus + '--' ::= decr + '-=' ::= minus_equal + '->' ::= left_arrow + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else if (*cursor == '-') { + ++cursor; + token_stream[(int) index++].kind = Token_decr; + } else if (*cursor == '>') { + ++cursor; + token_stream[(int) index++].kind = Token_arrow; + if (*cursor == '*') { + ++cursor; + token_stream[(int) index++].kind = Token_ptrmem; + } + } else { + token_stream[(int) index++].kind = '-'; + } +} + +void Lexer::scan_dot() +{ + /* + '.' ::= dot + '...' ::= ellipsis + */ + + ++cursor; + if (*cursor == '.' && *(cursor + 1) == '.') { + cursor += 2; + token_stream[(int) index++].kind = Token_ellipsis; + } else if (*cursor == '.' && *(cursor + 1) == '*') { + cursor += 2; + token_stream[(int) index++].kind = Token_ptrmem; + } else + token_stream[(int) index++].kind = '.'; +} + +void Lexer::scan_divide() +{ + /* + '/' ::= divide + '/=' ::= divide_equal + */ + + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = '/'; + } +} + +void Lexer::scan_colon() +{ + ++cursor; + if (*cursor == ':') { + ++cursor; + token_stream[(int) index++].kind = Token_scope; + } else { + token_stream[(int) index++].kind = ':'; + } +} + +void Lexer::scan_semicolon() +{ + ++cursor; + token_stream[(int) index++].kind = ';'; +} + +void Lexer::scan_less() +{ + /* + '<' ::= less + '<<' ::= left_shift + '<<=' ::= left_shift_equal + '<=' ::= less_equal + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_leq; + } else if (*cursor == '<') { + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = Token_shift; + } + } else { + token_stream[(int) index++].kind = '<'; + } +} + +void Lexer::scan_equal() +{ + /* + '=' ::= equal + '==' ::= equal_equal + */ + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_eq; + } else { + token_stream[(int) index++].kind = '='; + } +} + +void Lexer::scan_greater() +{ + /* + '>' ::= greater + '>=' ::= greater_equal + '>>' ::= right_shift + '>>=' ::= right_shift_equal + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_geq; + } else if (*cursor == '>') { + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = Token_shift; + } + } else { + token_stream[(int) index++].kind = '>'; + } +} + +void Lexer::scan_question() +{ + ++cursor; + token_stream[(int) index++].kind = '?'; +} + +void Lexer::scan_left_bracket() +{ + ++cursor; + token_stream[(int) index++].kind = '['; +} + +void Lexer::scan_right_bracket() +{ + ++cursor; + token_stream[(int) index++].kind = ']'; +} + +void Lexer::scan_xor() +{ + /* + '^' ::= xor + '^=' ::= xor_equal + */ + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = '^'; + } +} + +void Lexer::scan_left_brace() +{ + ++cursor; + token_stream[(int) index++].kind = '{'; +} + +void Lexer::scan_or() +{ + /* + '|' ::= or + '|=' ::= or_equal + '||' ::= or_or + */ + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else if (*cursor == '|') { + ++cursor; + token_stream[(int) index++].kind = Token_or; + } else { + token_stream[(int) index++].kind = '|'; + } +} + +void Lexer::scan_right_brace() +{ + ++cursor; + token_stream[(int) index++].kind = '}'; +} + +void Lexer::scan_tilde() +{ + ++cursor; + token_stream[(int) index++].kind = '~'; +} + +void Lexer::scan_EOF() +{ + ++cursor; + token_stream[(int) index++].kind = Token_EOF; +} + +void Lexer::scan_invalid_input() +{ + QString errmsg("invalid input: %1"); + errmsg.arg(int(*cursor)); + reportError(errmsg); + ++cursor; +} + +void LocationTable::positionAt(std::size_t offset, int max_line, + int *line, int *column) const +{ + if (!(line && column && max_line != 0)) + return; + + int first = 0; + int len = max_line; + int half; + int middle; + + while (len > 0) { + half = len >> 1; + middle = first; + + middle += half; + + if (lines[middle] < offset) { + first = middle; + ++first; + len = len - half - 1; + } else + len = half; + } + + *line = std::max(first, 1); + *column = (int)(offset - lines[*line - 1] - 1); + + if (*column < 0) { + *column = 0; + } +} + +void Lexer::scanKeyword0() +{ + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword2() +{ + switch (*cursor) { + case 'i': + if (*(cursor + 1) == 'f') { + token_stream[(int) index++].kind = Token_if; + return; + } + break; + + case 'd': + if (*(cursor + 1) == 'o') { + token_stream[(int) index++].kind = Token_do; + return; + } + break; + + case 'o': + if (*(cursor + 1) == 'r') { + token_stream[(int) index++].kind = Token_or; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword3() +{ + switch (*cursor) { + case 'a': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'd') { + token_stream[(int) index++].kind = Token_and; + return; + } + if (*(cursor + 1) == 's' && + *(cursor + 2) == 'm') { + token_stream[(int) index++].kind = Token_asm; + return; + } + break; + + case 'f': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'r') { + token_stream[(int) index++].kind = Token_for; + return; + } + break; + + case 'i': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 't') { + token_stream[(int) index++].kind = Token_int; + return; + } + break; + + case 'n': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'w') { + token_stream[(int) index++].kind = Token_new; + return; + } + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 't') { + token_stream[(int) index++].kind = Token_not; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'y') { + token_stream[(int) index++].kind = Token_try; + return; + } + break; + + case 'x': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'r') { + token_stream[(int) index++].kind = Token_xor; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword4() +{ + switch (*cursor) { + case 'a': + if (*(cursor + 1) == 'u' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'o') { + token_stream[(int) index++].kind = Token_auto; + return; + } + break; + + case 'c': + if (*(cursor + 1) == 'a' && + *(cursor + 2) == 's' && + *(cursor + 3) == 'e') { + token_stream[(int) index++].kind = Token_case; + return; + } + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 'r') { + token_stream[(int) index++].kind = Token_char; + return; + } + break; + + case 'b': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 'l') { + token_stream[(int) index++].kind = Token_bool; + return; + } + break; + + case 'e': + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 's' && + *(cursor + 3) == 'e') { + token_stream[(int) index++].kind = Token_else; + return; + } + if (*(cursor + 1) == 'm' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 't') { + token_stream[(int) index++].kind = Token_emit; + return; + } + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'u' && + *(cursor + 3) == 'm') { + token_stream[(int) index++].kind = Token_enum; + return; + } + break; + + case 'g': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'o') { + token_stream[(int) index++].kind = Token_goto; + return; + } + break; + + case 'l': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 'g') { + token_stream[(int) index++].kind = Token_long; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 's') { + token_stream[(int) index++].kind = Token_this; + return; + } + break; + + case 'v': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'd') { + token_stream[(int) index++].kind = Token_void; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword5() +{ + switch (*cursor) { + case 'c': + if (*(cursor + 1) == 'a' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'h') { + token_stream[(int) index++].kind = Token_catch; + return; + } + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 's' && + *(cursor + 4) == 's') { + token_stream[(int) index++].kind = Token_class; + return; + } + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'm' && + *(cursor + 3) == 'p' && + *(cursor + 4) == 'l') { + token_stream[(int) index++].kind = Token_compl; + return; + } + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 's' && + *(cursor + 4) == 't') { + token_stream[(int) index++].kind = Token_const; + return; + } + break; + + case 'b': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'r') { + token_stream[(int) index++].kind = Token_bitor; + return; + } + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'e' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'k') { + token_stream[(int) index++].kind = Token_break; + return; + } + break; + + case 'f': + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 't') { + token_stream[(int) index++].kind = Token_float; + return; + } + break; + + case 'o': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == '_' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'q') { + token_stream[(int) index++].kind = Token_or_eq; + return; + } + break; + + case 's': + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 'r' && + *(cursor + 4) == 't') { + token_stream[(int) index++].kind = Token_short; + return; + } + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 't' && + *(cursor + 4) == 's') { + token_stream[(int) index++].kind = Token_slots; + return; + } + break; + + case 'u': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'n') { + token_stream[(int) index++].kind = Token_union; + return; + } + if (*(cursor + 1) == 's' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'g') { + token_stream[(int) index++].kind = Token_using; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'r' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'w') { + token_stream[(int) index++].kind = Token_throw; + return; + } + break; + + case 'w': + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'e') { + token_stream[(int) index++].kind = Token_while; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword6() +{ + switch (*cursor) { + case 'a': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'd' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') { + token_stream[(int) index++].kind = Token_and_eq; + return; + } + break; + + case 'b': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'd') { + token_stream[(int) index++].kind = Token_bitand; + return; + } + break; + + case 'e': + if (*(cursor + 1) == 'x' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 't') { + token_stream[(int) index++].kind = Token_export; + return; + } + if (*(cursor + 1) == 'x' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 'n') { + token_stream[(int) index++].kind = Token_extern; + return; + } + break; + + case 'd': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'l' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'e') { + token_stream[(int) index++].kind = Token_delete; + return; + } + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'u' && + *(cursor + 3) == 'b' && + *(cursor + 4) == 'l' && + *(cursor + 5) == 'e') { + token_stream[(int) index++].kind = Token_double; + return; + } + break; + + case 'f': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'd') { + token_stream[(int) index++].kind = Token_friend; + return; + } + break; + + case 'i': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'l' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'e') { + token_stream[(int) index++].kind = Token_inline; + return; + } + break; + + case 'K': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'D' && + *(cursor + 3) == 'C' && + *(cursor + 4) == 'O' && + *(cursor + 5) == 'P') { + token_stream[(int) index++].kind = Token_K_DCOP; + return; + } + break; + + case 'n': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 't' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') { + token_stream[(int) index++].kind = Token_not_eq; + return; + } + break; + + case 'p': + if (*(cursor + 1) == 'u' && + *(cursor + 2) == 'b' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c') { + token_stream[(int) index++].kind = Token_public; + return; + } + break; + + case 's': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 'g' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'd') { + token_stream[(int) index++].kind = Token_signed; + return; + } + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 'z' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'f') { + token_stream[(int) index++].kind = Token_sizeof; + return; + } + if (*(cursor + 1) == 't' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c') { + token_stream[(int) index++].kind = Token_static; + return; + } + if (*(cursor + 1) == 't' && + *(cursor + 2) == 'r' && + *(cursor + 3) == 'u' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 't') { + token_stream[(int) index++].kind = Token_struct; + return; + } + if (*(cursor + 1) == 'w' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 'h') { + token_stream[(int) index++].kind = Token_switch; + return; + } + break; + + case 'r': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'u' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 'n') { + token_stream[(int) index++].kind = Token_return; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'y' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'd') { + token_stream[(int) index++].kind = Token_typeid; + return; + } + break; + + case 'x': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'r' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') { + token_stream[(int) index++].kind = Token_xor_eq; + return; + } + break; + + case 'k': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'd' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'p') { + token_stream[(int) index++].kind = Token_k_dcop; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword7() +{ + switch (*cursor) { + case 'd': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'f' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'u' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 't') { + token_stream[(int) index++].kind = Token_default; + return; + } + break; + + case 'm': + if (*(cursor + 1) == 'u' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'b' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 'e') { + token_stream[(int) index++].kind = Token_mutable; + return; + } + break; + + case 'p': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'v' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'e') { + token_stream[(int) index++].kind = Token_private; + return; + } + break; + case 's': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 'g' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 's') { + token_stream[(int) index++].kind = Token_signals; + return; + } + break; + case 't': + if (*(cursor + 1) == 'y' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'd' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'f') { + token_stream[(int) index++].kind = Token_typedef; + return; + } + break; + + case 'v': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 'r' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'u' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 'l') { + token_stream[(int) index++].kind = Token_virtual; + return; + } + break; + + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'E' && + *(cursor + 3) == 'N' && + *(cursor + 4) == 'U' && + *(cursor + 5) == 'M' && + *(cursor + 6) == 'S') { + token_stream[(int) index++].kind = Token_Q_ENUMS; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword8() +{ + switch (*cursor) { + case '_': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'y' && + *(cursor + 4) == 'p' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'o' && + *(cursor + 7) == 'f') { + token_stream[(int) index++].kind = Token___typeof; + return; + } + break; + + case 'c': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'n' && + *(cursor + 6) == 'u' && + *(cursor + 7) == 'e') { + token_stream[(int) index++].kind = Token_continue; + return; + } + break; + + case 'e': + if (*(cursor + 1) == 'x' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c' && + *(cursor + 6) == 'i' && + *(cursor + 7) == 't') { + token_stream[(int) index++].kind = Token_explicit; + return; + } + break; + + case 'o': + if (*(cursor + 1) == 'p' && + *(cursor + 2) == 'e' && + *(cursor + 3) == 'r' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'o' && + *(cursor + 7) == 'r') { + token_stream[(int) index++].kind = Token_operator; + return; + } + break; + + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'O' && + *(cursor + 3) == 'B' && + *(cursor + 4) == 'J' && + *(cursor + 5) == 'E' && + *(cursor + 6) == 'C' && + *(cursor + 7) == 'T') { + token_stream[(int) index++].kind = Token_Q_OBJECT; + return; + } + break; + + case 'r': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'g' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 's' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'e' && + *(cursor + 7) == 'r') { + token_stream[(int) index++].kind = Token_register; + return; + } + break; + + case 'u': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 's' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 'g' && + *(cursor + 5) == 'n' && + *(cursor + 6) == 'e' && + *(cursor + 7) == 'd') { + token_stream[(int) index++].kind = Token_unsigned; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'm' && + *(cursor + 3) == 'p' && + *(cursor + 4) == 'l' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 't' && + *(cursor + 7) == 'e') { + token_stream[(int) index++].kind = Token_template; + return; + } + if (*(cursor + 1) == 'y' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 'm' && + *(cursor + 7) == 'e') { + token_stream[(int) index++].kind = Token_typename; + return; + } + break; + + case 'v': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'l' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'i' && + *(cursor + 6) == 'l' && + *(cursor + 7) == 'e') { + token_stream[(int) index++].kind = Token_volatile; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword9() +{ + switch (*cursor) { + case 'p': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'c' && + *(cursor + 6) == 't' && + *(cursor + 7) == 'e' && + *(cursor + 8) == 'd') { + token_stream[(int) index++].kind = Token_protected; + return; + } + break; + + case 'n': + if (*(cursor + 1) == 'a' && + *(cursor + 2) == 'm' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 's' && + *(cursor + 5) == 'p' && + *(cursor + 6) == 'a' && + *(cursor + 7) == 'c' && + *(cursor + 8) == 'e') { + token_stream[(int) index++].kind = Token_namespace; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword10() +{ + switch (*cursor) { + case 'c': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 's' && + *(cursor + 4) == 't' && + *(cursor + 5) == '_' && + *(cursor + 6) == 'c' && + *(cursor + 7) == 'a' && + *(cursor + 8) == 's' && + *(cursor + 9) == 't') { + token_stream[(int) index++].kind = Token_const_cast; + return; + } + break; + + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'P' && + *(cursor + 3) == 'R' && + *(cursor + 4) == 'O' && + *(cursor + 5) == 'P' && + *(cursor + 6) == 'E' && + *(cursor + 7) == 'R' && + *(cursor + 8) == 'T' && + *(cursor + 9) == 'Y') { + token_stream[(int) index++].kind = Token_Q_PROPERTY; + return; + } + + break; + } + + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword11() +{ + switch (*cursor) { + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'I' && + *(cursor + 3) == 'N' && + *(cursor + 4) == 'V' && + *(cursor + 5) == 'O' && + *(cursor + 6) == 'K' && + *(cursor + 7) == 'A' && + *(cursor + 8) == 'B' && + *(cursor + 9) == 'L' && + *(cursor + 10) == 'E') { + token_stream[(int) index++].kind = Token_Q_INVOKABLE; + return; + } + break; + + case 's': + if (*(cursor + 1) == 't' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c' && + *(cursor + 6) == '_' && + *(cursor + 7) == 'c' && + *(cursor + 8) == 'a' && + *(cursor + 9) == 's' && + *(cursor + 10) == 't') { + token_stream[(int) index++].kind = Token_static_cast; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword12() +{ + switch (*cursor) { + case 'd': + if (*(cursor + 1) == 'y' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'm' && + *(cursor + 5) == 'i' && + *(cursor + 6) == 'c' && + *(cursor + 7) == '_' && + *(cursor + 8) == 'c' && + *(cursor + 9) == 'a' && + *(cursor + 10) == 's' && + *(cursor + 11) == 't') { + token_stream[(int) index++].kind = Token_dynamic_cast; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword13() +{ + switch (*cursor) { + case '_': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'r' && + *(cursor + 6) == 'i' && + *(cursor + 7) == 'b' && + *(cursor + 8) == 'u' && + *(cursor + 9) == 't' && + *(cursor + 10) == 'e' && + *(cursor + 11) == '_' && + *(cursor + 12) == '_') { + token_stream[(int) index++].kind = Token___attribute__; + return; + } + break; + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword14() +{ + switch (*cursor) { + case 'k': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'd' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'p' && + *(cursor + 6) == '_' && + *(cursor + 7) == 's' && + *(cursor + 8) == 'i' && + *(cursor + 9) == 'g' && + *(cursor + 10) == 'n' && + *(cursor + 11) == 'a' && + *(cursor + 12) == 'l' && + *(cursor + 13) == 's') { + token_stream[(int) index++].kind = Token_k_dcop_signals; + return; + } + break; + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword16() +{ + switch (*cursor) { + case 'r': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'r' && + *(cursor + 7) == 'p' && + *(cursor + 8) == 'r' && + *(cursor + 9) == 'e' && + *(cursor + 10) == 't' && + *(cursor + 11) == '_' && + *(cursor + 12) == 'c' && + *(cursor + 13) == 'a' && + *(cursor + 14) == 's' && + *(cursor + 15) == 't') { + token_stream[(int) index++].kind = Token_reinterpret_cast; + return; + } + break; + } + + token_stream[(int) index++].kind = Token_identifier; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/lexer.h b/parser/lexer.h new file mode 100644 index 000000000..874805325 --- /dev/null +++ b/parser/lexer.h @@ -0,0 +1,290 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef LEXER_H +#define LEXER_H + +#include "symbol.h" + +#include +#include +#include + +struct NameSymbol; +class Lexer; +class Control; + +typedef void (Lexer::*scan_fun_ptr)(); + +class Token +{ +public: + int kind; + std::size_t position; + std::size_t size; + char const *text; + + union { + const NameSymbol *symbol; + std::size_t right_brace; + } extra; +}; + +class LocationTable +{ +private: + LocationTable(const LocationTable &source); + void operator = (const LocationTable &source); + +public: + inline LocationTable(std::size_t size = 1024) + : lines(0), + line_count(0), + current_line(0) { + resize(size); + } + + inline ~LocationTable() { + free(lines); + } + + inline std::size_t size() const { + return line_count; + } + + void resize(std::size_t size) { + Q_ASSERT(size > 0); + lines = (std::size_t*) ::realloc(lines, sizeof(std::size_t) * size); + line_count = size; + } + + void positionAt(std::size_t offset, int *line, int *column) const { + positionAt(offset, (int) current_line, line, column); + } + + void positionAt(std::size_t offset, int max_line, int *line, int *column) const; + + inline std::size_t &operator[](int index) { + return lines[index]; + } + +private: + std::size_t *lines; + std::size_t line_count; + std::size_t current_line; + + friend class Lexer; +}; + +class TokenStream +{ +private: + TokenStream(const TokenStream &); + void operator = (const TokenStream &); + +public: + inline TokenStream(std::size_t size = 1024) + : tokens(0), + index(0), + token_count(0) { + resize(size); + } + + inline ~TokenStream() { + ::free(tokens); + } + + inline std::size_t size() const { + return token_count; + } + + inline std::size_t cursor() const { + return index; + } + + inline void rewind(int i) { + index = i; + } + + void resize(std::size_t size) { + Q_ASSERT(size > 0); + tokens = (Token*) ::realloc(tokens, sizeof(Token) * size); + token_count = size; + } + + inline std::size_t nextToken() { + return index++; + } + + inline int lookAhead(std::size_t i = 0) const { + return tokens[index + i].kind; + } + + inline int kind(std::size_t i) const { + return tokens[i].kind; + } + + inline std::size_t position(std::size_t i) const { + return tokens[i].position; + } + + inline const NameSymbol *symbol(std::size_t i) const { + return tokens[i].extra.symbol; + } + + inline std::size_t matchingBrace(std::size_t i) const { + return tokens[i].extra.right_brace; + } + + inline Token &operator[](int index) { + return tokens[index]; + } + + inline const Token &token(int index) const { + return tokens[index]; + } + +private: + Token *tokens; + std::size_t index; + std::size_t token_count; + +private: + friend class Lexer; +}; + +class LocationManager +{ + LocationManager(LocationManager const &__other); + void operator = (LocationManager const &__other); + +public: + LocationManager(TokenStream &__token_stream, + LocationTable &__location_table, + LocationTable &__line_table): + token_stream(__token_stream), + location_table(__location_table), + line_table(__line_table) {} + + void positionAt(std::size_t offset, int *line, int *column, + QString *filename) const; + + void extract_line(int offset, int *line, QString *filename) const; + + TokenStream &token_stream; + LocationTable &location_table; + LocationTable &line_table; +}; + +class Lexer +{ +public: + Lexer(LocationManager &__location, Control *__control): + _M_location(__location), + token_stream(_M_location.token_stream), + location_table(_M_location.location_table), + line_table(_M_location.line_table), + control(__control) {} + + void tokenize(const char *contents, std::size_t size); + + LocationManager &_M_location; + TokenStream &token_stream; + LocationTable &location_table; + LocationTable &line_table; + +private: + void reportError(const QString& msg); + + void initialize_scan_table(); + void scan_newline(); + void scan_white_spaces(); + void scan_identifier_or_keyword(); + void scan_identifier_or_literal(); + void scan_int_constant(); + void scan_char_constant(); + void scan_string_constant(); + void scan_invalid_input(); + void scan_preprocessor(); + + // keywords + void scanKeyword0(); + void scanKeyword2(); + void scanKeyword3(); + void scanKeyword4(); + void scanKeyword5(); + void scanKeyword6(); + void scanKeyword7(); + void scanKeyword8(); + void scanKeyword9(); + void scanKeyword10(); + void scanKeyword11(); + void scanKeyword12(); + void scanKeyword13(); + void scanKeyword14(); + void scanKeyword16(); + + // operators + void scan_not(); + void scan_remainder(); + void scan_and(); + void scan_left_paren(); + void scan_right_paren(); + void scan_star(); + void scan_plus(); + void scan_comma(); + void scan_minus(); + void scan_dot(); + void scan_divide(); + void scan_colon(); + void scan_semicolon(); + void scan_less(); + void scan_equal(); + void scan_greater(); + void scan_question(); + void scan_left_bracket(); + void scan_right_bracket(); + void scan_xor(); + void scan_left_brace(); + void scan_or(); + void scan_right_brace(); + void scan_tilde(); + void scan_EOF(); + +private: + Control *control; + const unsigned char *cursor; + const unsigned char *begin_buffer; + const unsigned char *end_buffer; + std::size_t index; + + static scan_fun_ptr s_scan_table[]; + static scan_fun_ptr s_scan_keyword_table[]; + static bool s_initialized; +}; + +#endif // LEXER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/list.cpp b/parser/list.cpp new file mode 100644 index 000000000..7482b7392 --- /dev/null +++ b/parser/list.cpp @@ -0,0 +1,28 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "list.h" + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/list.h b/parser/list.h new file mode 100644 index 000000000..64aef452f --- /dev/null +++ b/parser/list.h @@ -0,0 +1,100 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef FASTLIST_H +#define FASTLIST_H + +#include "smallobject.h" + +template +struct ListNode { + Tp element; + int index; + mutable const ListNode *next; + + static ListNode *create(const Tp &element, pool *p) { + ListNode *node = new(p->allocate(sizeof(ListNode))) ListNode(); + node->element = element; + node->index = 0; + node->next = node; + + return node; + } + + static ListNode *create(const ListNode *n1, const Tp &element, pool *p) { + ListNode *n2 = ListNode::create(element, p); + + n2->index = n1->index + 1; + n2->next = n1->next; + n1->next = n2; + + return n2; + } + + inline ListNode() { } + + inline const ListNode *at(int index) const { + const ListNode *node = this; + while (index != node->index) + node = node->next; + + return node; + } + + inline bool hasNext() const { + return index < next->index; + } + + inline int count() const { + return 1 + toBack()->index; + } + + inline const ListNode *toFront() const { + return toBack()->next; + } + + inline const ListNode *toBack() const { + const ListNode *node = this; + while (node->hasNext()) + node = node->next; + + return node; + } +}; + +template +inline const ListNode *snoc(const ListNode *list, + const Tp &element, pool *p) +{ + if (!list) + return ListNode::create(element, p); + + return ListNode::create(list->toBack(), element, p); +} + +#endif // FASTLIST_H + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/parser/name_compiler.cpp b/parser/name_compiler.cpp new file mode 100644 index 000000000..4dbd516d6 --- /dev/null +++ b/parser/name_compiler.cpp @@ -0,0 +1,134 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "name_compiler.h" +#include "type_compiler.h" +#include "declarator_compiler.h" +#include "lexer.h" +#include "symbol.h" +#include "binder.h" + +#include + +NameCompiler::NameCompiler(Binder *binder) + : _M_binder(binder), _M_token_stream(binder->tokenStream()) +{ +} + +QString NameCompiler::decode_operator(std::size_t index) const +{ + const Token &tk = _M_token_stream->token((int) index); + return QString::fromUtf8(&tk.text[tk.position], (int) tk.size); +} + +QString NameCompiler::internal_run(AST *node) +{ + _M_name.clear(); + visit(node); + return name(); +} + +void NameCompiler::visitUnqualifiedName(UnqualifiedNameAST *node) +{ + QString tmp_name; + + if (node->tilde) + tmp_name += QLatin1String("~"); + + if (node->id) + tmp_name += _M_token_stream->symbol(node->id)->as_string(); + + if (OperatorFunctionIdAST *op_id = node->operator_id) { +#if defined(__GNUC__) +#warning "NameCompiler::visitUnqualifiedName() -- implement me" +#endif + + if (op_id->op && op_id->op->op) { + tmp_name += QLatin1String("operator"); + tmp_name += decode_operator(op_id->op->op); + if (op_id->op->close) + tmp_name += decode_operator(op_id->op->close); + } else if (op_id->type_specifier) { +#if defined(__GNUC__) +#warning "don't use an hardcoded string as cast' name" +#endif + Token const &tk = _M_token_stream->token((int) op_id->start_token); + Token const &end_tk = _M_token_stream->token((int) op_id->end_token); + tmp_name += QString::fromLatin1(&tk.text[tk.position], + (int)(end_tk.position - tk.position)).trimmed(); + } + } + + _M_name += tmp_name; + if (node->template_arguments) { + // ### cleanup + _M_name.last() += QLatin1String("<"); + visitNodes(this, node->template_arguments); + _M_name.last().truncate(_M_name.last().count() - 1); // remove the last ',' + _M_name.last() += QLatin1String(">"); + } + +} + +void NameCompiler::visitTemplateArgument(TemplateArgumentAST *node) +{ + if (node->type_id && node->type_id->type_specifier) { + TypeCompiler type_cc(_M_binder); + type_cc.run(node->type_id->type_specifier); + + DeclaratorCompiler decl_cc(_M_binder); + decl_cc.run(node->type_id->declarator); + + if (type_cc.isConstant()) + _M_name.last() += "const "; + + QStringList q = type_cc.qualifiedName(); + + if (q.count() == 1) { +#if defined (RXX_RESOLVE_TYPEDEF) // ### it'll break :( + TypeInfo tp; + tp.setQualifiedName(q); + tp = TypeInfo::resolveType(tp, _M_binder->currentScope()->toItem()); + q = tp.qualifiedName(); +#endif + + if (CodeModelItem item = _M_binder->model()->findItem(q, _M_binder->currentScope()->toItem())) { + if (item->name() == q.last()) + q = item->qualifiedName(); + } + } + + _M_name.last() += q.join("::"); + + if (decl_cc.isReference()) + _M_name.last() += "&"; + if (decl_cc.indirection()) + _M_name.last() += QString(decl_cc.indirection(), '*'); + + _M_name.last() += QLatin1String(","); + } +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/name_compiler.h b/parser/name_compiler.h new file mode 100644 index 000000000..66cabaccf --- /dev/null +++ b/parser/name_compiler.h @@ -0,0 +1,69 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef NAME_COMPILER_H +#define NAME_COMPILER_H + +#include "default_visitor.h" +#include + +class TokenStream; +class Binder; + +class NameCompiler: protected DefaultVisitor +{ +public: + NameCompiler(Binder *binder); + + void run(NameAST *node) { + internal_run(node); + } + void run(UnqualifiedNameAST *node) { + internal_run(node); + } + + QString name() const { + return _M_name.join("::"); + } + QStringList qualifiedName() const { + return _M_name; + } + +protected: + virtual void visitUnqualifiedName(UnqualifiedNameAST *node); + virtual void visitTemplateArgument(TemplateArgumentAST *node); + + QString internal_run(AST *node); + QString decode_operator(std::size_t index) const; + +private: + Binder *_M_binder; + TokenStream *_M_token_stream; + QStringList _M_name; +}; + +#endif // NAME_COMPILER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/parser.cpp b/parser/parser.cpp new file mode 100644 index 000000000..d65d5f3e4 --- /dev/null +++ b/parser/parser.cpp @@ -0,0 +1,4056 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + + +// c++ support +#include "parser.h" +#include "tokens.h" +#include "lexer.h" +#include "control.h" + +#include + +#define ADVANCE(tk, descr) \ + { \ + if (token_stream.lookAhead() != tk) { \ + tokenRequiredError(tk); \ + return false; \ + } \ + token_stream.nextToken(); \ + } + +#define ADVANCE_NR(tk, descr) \ + do { \ + if (token_stream.lookAhead() != tk) { \ + tokenRequiredError(tk); \ + } \ + else \ + token_stream.nextToken(); \ + } while (0) + +#define CHECK(tk) \ + do { \ + if (token_stream.lookAhead() != tk) { \ + return false; \ + } \ + token_stream.nextToken(); \ + } while (0) + +#define UPDATE_POS(_node, start, end) \ + do { \ + (_node)->start_token = start; \ + (_node)->end_token = end; \ + } while (0) + +Parser::Parser(Control *c) + : _M_location(token_stream, location_table, line_table), + control(c), + lexer(_M_location, control) +{ + _M_block_errors = false; +} + +Parser::~Parser() +{ +} + +void Parser::advance() +{ + token_stream.nextToken(); +} + +TranslationUnitAST *Parser::parse(const char *contents, + std::size_t size, pool *p) +{ + _M_block_errors = false; + _M_pool = p; + lexer.tokenize(contents, size); + token_stream.nextToken(); // skip the first token + + Lexer *oldLexer = control->changeLexer(&lexer); + Parser *oldParser = control->changeParser(this); + + TranslationUnitAST *ast = 0; + parseTranslationUnit(ast); + + control->changeLexer(oldLexer); + control->changeParser(oldParser); + + return ast; +} + +bool Parser::parseWinDeclSpec(WinDeclSpecAST *&node) +{ + if (token_stream.lookAhead() != Token_identifier) + return false; + + std::size_t start = token_stream.cursor(); + + const NameSymbol *name_symbol = token_stream.symbol(token_stream.cursor()); + QString name = name_symbol->as_string(); + if (name != QLatin1String("__declspec")) + return false; + std::size_t specifier = token_stream.cursor(); + + token_stream.nextToken(); + if (token_stream.lookAhead() != '(') + return false; + + token_stream.nextToken(); + if (token_stream.lookAhead() != Token_identifier) + return false; + std::size_t modifier = token_stream.cursor(); + + token_stream.nextToken(); + if (token_stream.lookAhead() != ')') + return false; + + token_stream.nextToken(); + + node = CreateNode(_M_pool); + node->specifier = specifier; + node->modifier = modifier; + + UPDATE_POS(node, start, token_stream.cursor()); + + return true; +} + +void Parser::tokenRequiredError(int token) +{ + QString err; + + err += "expected token "; + err += "``"; + err += token_name(token); + err += "'' found ``"; + err += token_name(token_stream.lookAhead()); + err += "''"; + + reportError(err); +} + +void Parser::syntaxError() +{ + QString err; + + err += "unexpected token "; + err += "``"; + err += token_name(token_stream.lookAhead()); + err += "''"; + + reportError(err); +} + +void Parser::reportError(const QString& msg) +{ + if (!_M_block_errors) { + int line, column; + QString fileName; + + std::size_t tok = token_stream.cursor(); + location().positionAt(token_stream.position(tok), + &line, &column, &fileName); + + Control::ErrorMessage errmsg; + errmsg.setLine(line + 1); + errmsg.setColumn(column); + errmsg.setFileName(fileName); + errmsg.setMessage(QLatin1String("** PARSER ERROR ") + msg); + control->reportError(errmsg); + } +} + +bool Parser::skipUntil(int token) +{ + while (token_stream.lookAhead()) { + if (token_stream.lookAhead() == token) + return true; + + token_stream.nextToken(); + } + + return false; +} + +bool Parser::skipUntilDeclaration() +{ + while (token_stream.lookAhead()) { + + switch (token_stream.lookAhead()) { + case ';': + case '~': + case Token_scope: + case Token_identifier: + case Token_operator: + case Token_char: + case Token_wchar_t: + case Token_bool: + case Token_short: + case Token_int: + case Token_long: + case Token_signed: + case Token_unsigned: + case Token_float: + case Token_double: + case Token_void: + case Token_extern: + case Token_namespace: + case Token_using: + case Token_typedef: + case Token_asm: + case Token_template: + case Token_export: + + case Token_const: // cv + case Token_volatile: // cv + + case Token_public: + case Token_protected: + case Token_private: + case Token_signals: // Qt + case Token_slots: // Qt + return true; + + default: + token_stream.nextToken(); + } + } + + return false; +} + +bool Parser::skipUntilStatement() +{ + while (token_stream.lookAhead()) { + switch (token_stream.lookAhead()) { + case ';': + case '{': + case '}': + case Token_const: + case Token_volatile: + case Token_identifier: + case Token_case: + case Token_default: + case Token_if: + case Token_switch: + case Token_while: + case Token_do: + case Token_for: + case Token_break: + case Token_continue: + case Token_return: + case Token_goto: + case Token_try: + case Token_catch: + case Token_throw: + case Token_char: + case Token_wchar_t: + case Token_bool: + case Token_short: + case Token_int: + case Token_long: + case Token_signed: + case Token_unsigned: + case Token_float: + case Token_double: + case Token_void: + case Token_class: + case Token_struct: + case Token_union: + case Token_enum: + case Token_scope: + case Token_template: + case Token_using: + return true; + + default: + token_stream.nextToken(); + } + } + + return false; +} + +bool Parser::skip(int l, int r) +{ + int count = 0; + while (token_stream.lookAhead()) { + int tk = token_stream.lookAhead(); + + if (tk == l) + ++count; + else if (tk == r) + --count; + else if (l != '{' && (tk == '{' || tk == '}' || tk == ';')) + return false; + + if (!count) + return true; + + token_stream.nextToken(); + } + + return false; +} + +bool Parser::parseName(NameAST *&node, bool acceptTemplateId) +{ + std::size_t start = token_stream.cursor(); + + WinDeclSpecAST *winDeclSpec = 0; + parseWinDeclSpec(winDeclSpec); + + NameAST *ast = CreateNode(_M_pool); + + if (token_stream.lookAhead() == Token_scope) { + ast->global = true; + token_stream.nextToken(); + } + + std::size_t idx = token_stream.cursor(); + + while (true) { + UnqualifiedNameAST *n = 0; + if (!parseUnqualifiedName(n)) + return false; + + if (token_stream.lookAhead() == Token_scope) { + token_stream.nextToken(); + + ast->qualified_names + = snoc(ast->qualified_names, n, _M_pool); + + if (token_stream.lookAhead() == Token_template) { + /// skip optional template #### @todo CHECK + token_stream.nextToken(); + } + } else { + Q_ASSERT(n); + if (!acceptTemplateId) { + token_stream.rewind((int) n->start_token); + parseUnqualifiedName(n, false); + } + + ast->unqualified_name = n; + break; + } + } + + if (idx == token_stream.cursor()) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTranslationUnit(TranslationUnitAST *&node) +{ + std::size_t start = token_stream.cursor(); + TranslationUnitAST *ast = CreateNode(_M_pool); + + while (token_stream.lookAhead()) { + std::size_t startDecl = token_stream.cursor(); + + DeclarationAST *declaration = 0; + if (parseDeclaration(declaration)) { + ast->declarations = + snoc(ast->declarations, declaration, _M_pool); + } else { + // error recovery + if (startDecl == token_stream.cursor()) { + // skip at least one token + token_stream.nextToken(); + } + + skipUntilDeclaration(); + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDeclaration(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case ';': + token_stream.nextToken(); + return true; + + case Token_extern: + return parseLinkageSpecification(node); + + case Token_namespace: + return parseNamespace(node); + + case Token_using: + return parseUsing(node); + + case Token_typedef: + return parseTypedef(node); + + case Token_asm: + return parseAsmDefinition(node); + + case Token_Q_ENUMS: + return parseQ_ENUMS(node); + + case Token_template: + case Token_export: + return parseTemplateDeclaration(node); + + default: { + const ListNode *cv = 0; + parseCvQualify(cv); + + const ListNode *storageSpec = 0; + parseStorageClassSpecifier(storageSpec); + + parseCvQualify(cv); + + TypeSpecifierAST *spec = 0; + if (parseEnumSpecifier(spec) + || parseClassSpecifier(spec) + || parseForwardDeclarationSpecifier(spec)) { + parseCvQualify(cv); + + spec->cv = cv; + + const ListNode *declarators = 0; + parseInitDeclaratorList(declarators); + ADVANCE(';', ";"); + + SimpleDeclarationAST *ast = + CreateNode(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->type_specifier = spec; + ast->init_declarators = declarators; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + } // end switch + + token_stream.rewind((int) start); + return parseDeclarationInternal(node); +} + +bool Parser::parseLinkageSpecification(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_extern); + + LinkageSpecificationAST *ast = CreateNode(_M_pool); + + if (token_stream.lookAhead() == Token_string_literal) { + ast->extern_type = token_stream.cursor(); + token_stream.nextToken(); + } + + if (token_stream.lookAhead() == '{') + parseLinkageBody(ast->linkage_body); + else if (!parseDeclaration(ast->declaration)) + reportError(("Declaration syntax error")); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseLinkageBody(LinkageBodyAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK('{'); + + LinkageBodyAST *ast = CreateNode(_M_pool); + + while (token_stream.lookAhead()) { + int tk = token_stream.lookAhead(); + + if (tk == '}') + break; + + std::size_t startDecl = token_stream.cursor(); + + DeclarationAST *declaration = 0; + if (parseDeclaration(declaration)) { + ast->declarations = snoc(ast->declarations, declaration, _M_pool); + } else { + // error recovery + if (startDecl == token_stream.cursor()) { + // skip at least one token + token_stream.nextToken(); + } + + skipUntilDeclaration(); + } + } + + if (token_stream.lookAhead() != '}') + reportError(("} expected")); + else + token_stream.nextToken(); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNamespace(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_namespace); + + std::size_t namespace_name = 0; + if (token_stream.lookAhead() == Token_identifier) { + namespace_name = token_stream.cursor(); + token_stream.nextToken(); + } + + if (token_stream.lookAhead() == '=') { + // namespace alias + token_stream.nextToken(); + + NameAST *name = 0; + if (parseName(name)) { + ADVANCE(';', ";"); + + NamespaceAliasDefinitionAST *ast + = CreateNode(_M_pool); + ast->namespace_name = namespace_name; + ast->alias_name = name; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; + } else { + reportError(("namespace expected")); + return false; + } + } else if (token_stream.lookAhead() != '{') { + reportError(("{ expected")); + return false; + } + + NamespaceAST *ast = CreateNode(_M_pool); + ast->namespace_name = namespace_name; + parseLinkageBody(ast->linkage_body); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseUsing(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_using); + + if (token_stream.lookAhead() == Token_namespace) + return parseUsingDirective(node); + + UsingAST *ast = CreateNode(_M_pool); + + if (token_stream.lookAhead() == Token_typename) { + ast->type_name = token_stream.cursor(); + token_stream.nextToken(); + } + + if (!parseName(ast->name)) + return false; + + ADVANCE(';', ";"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseUsingDirective(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_namespace); + + NameAST *name = 0; + if (!parseName(name)) { + reportError(("Namespace name expected")); + return false; + } + + ADVANCE(';', ";"); + + UsingDirectiveAST *ast = CreateNode(_M_pool); + ast->name = name; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + + +bool Parser::parseOperatorFunctionId(OperatorFunctionIdAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_operator); + + OperatorFunctionIdAST *ast = CreateNode(_M_pool); + + if (!parseOperator(ast->op)) { + ast->op = 0; + + // parse cast operator + const ListNode *cv = 0; + parseCvQualify(cv); + + if (!parseSimpleTypeSpecifier(ast->type_specifier)) { + syntaxError(); + return false; + } + + parseCvQualify(cv); + ast->type_specifier->cv = cv; + + PtrOperatorAST *ptr_op = 0; + while (parsePtrOperator(ptr_op)) + ast->ptr_ops = snoc(ast->ptr_ops, ptr_op, _M_pool); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; +} + +bool Parser::parseTemplateArgumentList(const ListNode *&node, + bool reportError) +{ + TemplateArgumentAST *templArg = 0; + if (!parseTemplateArgument(templArg)) + return false; + + node = snoc(node, templArg, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseTemplateArgument(templArg)) { + if (reportError) { + syntaxError(); + break; + } + + node = 0; + return false; + } + + node = snoc(node, templArg, _M_pool); + } + + return true; +} + +bool Parser::parseTypedef(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_typedef); + + TypeSpecifierAST *spec = 0; + if (!parseTypeSpecifierOrClassSpec(spec)) { + reportError(("Need a type specifier to declare")); + return false; + } + + const ListNode *declarators = 0; + if (!parseInitDeclaratorList(declarators)) { + //reportError(("Need an identifier to declare")); + //return false; + } + + ADVANCE(';', ";"); + + TypedefAST *ast = CreateNode(_M_pool); + ast->type_specifier = spec; + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseAsmDefinition(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_asm, "asm"); + + const ListNode *cv = 0; + parseCvQualify(cv); + +#if defined(__GNUC__) +#warning "implement me" +#endif + skip('(', ')'); + token_stream.nextToken(); + ADVANCE(';', ";"); + + AsmDefinitionAST *ast = CreateNode(_M_pool); + ast->cv = cv; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTemplateDeclaration(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + std::size_t exported = 0; + if (token_stream.lookAhead() == Token_export) { + exported = token_stream.cursor(); + token_stream.nextToken(); + } + + CHECK(Token_template); + + const ListNode *params = 0; + if (token_stream.lookAhead() == '<') { + token_stream.nextToken(); + parseTemplateParameterList(params); + + ADVANCE('>', ">"); + } + + DeclarationAST *declaration = 0; + if (!parseDeclaration(declaration)) + reportError(("expected a declaration")); + + TemplateDeclarationAST *ast = CreateNode(_M_pool); + ast->exported = exported; + ast->template_parameters = params; + ast->declaration = declaration; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseOperator(OperatorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + OperatorAST *ast = CreateNode(_M_pool); + + switch (token_stream.lookAhead()) { + case Token_new: + case Token_delete: { + ast->op = token_stream.cursor(); + token_stream.nextToken(); + + if (token_stream.lookAhead() == '[' + && token_stream.lookAhead(1) == ']') { + ast->open = token_stream.cursor(); + token_stream.nextToken(); + + ast->close = token_stream.cursor(); + token_stream.nextToken(); + } + } + break; + + case '+': + case '-': + case '*': + case '/': + case '%': + case '^': + case '&': + case '|': + case '~': + case '!': + case '=': + case '<': + case '>': + case ',': + case Token_assign: + case Token_shift: + case Token_eq: + case Token_not_eq: + case Token_leq: + case Token_geq: + case Token_and: + case Token_or: + case Token_incr: + case Token_decr: + case Token_ptrmem: + case Token_arrow: + ast->op = token_stream.cursor(); + token_stream.nextToken(); + break; + + default: + if (token_stream.lookAhead() == '(' + && token_stream.lookAhead(1) == ')') { + ast->op = ast->open = token_stream.cursor(); + token_stream.nextToken(); + ast->close = token_stream.cursor(); + token_stream.nextToken(); + } else if (token_stream.lookAhead() == '[' + && token_stream.lookAhead(1) == ']') { + ast->op = ast->open = token_stream.cursor(); + token_stream.nextToken(); + ast->close = token_stream.cursor(); + token_stream.nextToken(); + } else { + return false; + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseCvQualify(const ListNode *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk; + while (0 != (tk = token_stream.lookAhead()) + && (tk == Token_const || tk == Token_volatile)) { + node = snoc(node, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + } + + return start != token_stream.cursor(); +} + +bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST *&node, + bool onlyIntegral) +{ + std::size_t start = token_stream.cursor(); + bool isIntegral = false; + bool done = false; + + const ListNode *integrals = 0; + + while (!done) { + switch (token_stream.lookAhead()) { + case Token_char: + case Token_wchar_t: + case Token_bool: + case Token_short: + case Token_int: + case Token_long: + case Token_signed: + case Token_unsigned: + case Token_float: + case Token_double: + case Token_void: + integrals = snoc(integrals, token_stream.cursor(), _M_pool); + isIntegral = true; + token_stream.nextToken(); + break; + + default: + done = true; + } + } + + SimpleTypeSpecifierAST *ast = CreateNode(_M_pool); + if (isIntegral) { + ast->integrals = integrals; + } else if (token_stream.lookAhead() == Token___typeof) { + ast->type_of = token_stream.cursor(); + token_stream.nextToken(); + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + std::size_t saved = token_stream.cursor(); + parseTypeId(ast->type_id); + if (token_stream.lookAhead() != ')') { + ast->type_id = 0; + token_stream.rewind((int) saved); + parseUnaryExpression(ast->expression); + } + ADVANCE(')', ")"); + } else { + parseUnaryExpression(ast->expression); + } + } else if (onlyIntegral) { + token_stream.rewind((int) start); + return false; + } else { + if (!parseName(ast->name, true)) { + ast->name = 0; + token_stream.rewind((int) start); + return false; + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parsePtrOperator(PtrOperatorAST *&node) +{ + int tk = token_stream.lookAhead(); + + if (tk != '&' && tk != '*' + && tk != Token_scope && tk != Token_identifier) { + return false; + } + + std::size_t start = token_stream.cursor(); + + PtrOperatorAST *ast = CreateNode(_M_pool); + + switch (token_stream.lookAhead()) { + case '&': + case '*': + ast->op = token_stream.cursor(); + token_stream.nextToken(); + break; + + case Token_scope: + case Token_identifier: { + if (!parsePtrToMember(ast->mem_ptr)) { + token_stream.rewind((int) start); + return false; + } + } + break; + + default: + Q_ASSERT(0); + break; + } + + parseCvQualify(ast->cv); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTemplateArgument(TemplateArgumentAST *&node) +{ + std::size_t start = token_stream.cursor(); + + TypeIdAST *typeId = 0; + ExpressionAST *expr = 0; + + if (!parseTypeId(typeId) || (token_stream.lookAhead() != ',' + && token_stream.lookAhead() != '>')) { + token_stream.rewind((int) start); + + if (!parseLogicalOrExpression(expr, true)) + return false; + } + + TemplateArgumentAST *ast = CreateNode(_M_pool); + ast->type_id = typeId; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTypeSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + const ListNode *cv = 0; + parseCvQualify(cv); + + TypeSpecifierAST *ast = 0; + if (!parseElaboratedTypeSpecifier(ast) && !parseSimpleTypeSpecifier(ast)) { + token_stream.rewind((int) start); + return false; + } + + parseCvQualify(cv); + ast->cv = cv; + + node = ast; + + return true; +} + +bool Parser::parseDeclarator(DeclaratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeclaratorAST *ast = CreateNode(_M_pool); + + //fprintf(stderr, "[%s-%s] ast->ptr_ops: %p\n", __FILE__, __FUNCTION__, ast->ptr_ops); + + DeclaratorAST *decl = 0; + NameAST *declId = 0; + + PtrOperatorAST *ptrOp = 0; + while (parsePtrOperator(ptrOp)) + ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, _M_pool); + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + if (!parseDeclarator(decl)) + return false; + + ast->sub_declarator = decl; + + CHECK(')'); + } else { + if (token_stream.lookAhead() == ':') { + // unnamed bitfield + } else if (parseName(declId, true)) { + ast->id = declId; + } else { + token_stream.rewind((int) start); + return false; + } + + if (token_stream.lookAhead() == ':') { + token_stream.nextToken(); + + if (!parseConstantExpression(ast->bit_expression)) + reportError(("Constant expression expected")); + + goto update_pos; + } + } + + { + bool isVector = true; + + while (token_stream.lookAhead() == '[') { + token_stream.nextToken(); + + ExpressionAST *expr = 0; + parseCommaExpression(expr); + + ADVANCE(']', "]"); + + ast->array_dimensions = snoc(ast->array_dimensions, expr, _M_pool); + isVector = true; + } + + bool skipParen = false; + if (token_stream.lookAhead() == Token_identifier + && token_stream.lookAhead(1) == '(' + && token_stream.lookAhead(2) == '(') { + token_stream.nextToken(); + token_stream.nextToken(); + skipParen = true; + } + + int tok = token_stream.lookAhead(); + if (ast->sub_declarator + && !(isVector || tok == '(' || tok == ',' + || tok == ';' || tok == '=')) { + token_stream.rewind((int) start); + return false; + } + + std::size_t index = token_stream.cursor(); + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + ParameterDeclarationClauseAST *params = 0; + if (!parseParameterDeclarationClause(params)) { + token_stream.rewind((int) index); + goto update_pos; + } + + ast->parameter_declaration_clause = params; + + if (token_stream.lookAhead() != ')') { + token_stream.rewind((int) index); + goto update_pos; + } + + token_stream.nextToken(); // skip ')' + + parseCvQualify(ast->fun_cv); + parseExceptionSpecification(ast->exception_spec); + + if (token_stream.lookAhead() == Token___attribute__) + parse_Attribute__(); + } + + if (skipParen) { + if (token_stream.lookAhead() != ')') + reportError(("')' expected")); + else + token_stream.nextToken(); + } + } + +update_pos: + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeclaratorAST *ast = CreateNode(_M_pool); + DeclaratorAST *decl = 0; + + PtrOperatorAST *ptrOp = 0; + while (parsePtrOperator(ptrOp)) + ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, _M_pool); + + int index = (int) token_stream.cursor(); + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + if (!parseAbstractDeclarator(decl)) { + token_stream.rewind((int) index); + goto label1; + } + + ast->sub_declarator = decl; + + if (token_stream.lookAhead() != ')') { + token_stream.rewind((int) start); + return false; + } + token_stream.nextToken(); + } else if (token_stream.lookAhead() == ':') { + token_stream.nextToken(); + if (!parseConstantExpression(ast->bit_expression)) { + ast->bit_expression = 0; + reportError(("Constant expression expected")); + } + goto update_pos; + } + +label1: { + bool isVector = true; + + while (token_stream.lookAhead() == '[') { + token_stream.nextToken(); + + ExpressionAST *expr = 0; + parseCommaExpression(expr); + + ADVANCE(']', "]"); + + ast->array_dimensions = snoc(ast->array_dimensions, expr, _M_pool); + isVector = true; + } + + int tok = token_stream.lookAhead(); + if (ast->sub_declarator + && !(isVector || tok == '(' || tok == ',' + || tok == ';' || tok == '=')) { + token_stream.rewind((int) start); + return false; + } + + int index = (int) token_stream.cursor(); + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + ParameterDeclarationClauseAST *params = 0; + if (!parseParameterDeclarationClause(params)) { + token_stream.rewind((int) index); + goto update_pos; + } + + ast->parameter_declaration_clause = params; + + if (token_stream.lookAhead() != ')') { + token_stream.rewind((int) index); + goto update_pos; + } + + token_stream.nextToken(); // skip ')' + + parseCvQualify(ast->fun_cv); + parseExceptionSpecification(ast->exception_spec); + } + } + +update_pos: + if (token_stream.cursor() == start) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseEnumSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_enum); + + NameAST *name = 0; + parseName(name); + + if (token_stream.lookAhead() != '{') { + token_stream.rewind((int) start); + return false; + } + token_stream.nextToken(); + + EnumSpecifierAST *ast = CreateNode(_M_pool); + ast->name = name; + + EnumeratorAST *enumerator = 0; + if (parseEnumerator(enumerator)) { + ast->enumerators = snoc(ast->enumerators, enumerator, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseEnumerator(enumerator)) { + //reportError(("Enumerator expected")); + break; + } + + ast->enumerators = snoc(ast->enumerators, enumerator, _M_pool); + } + } + + ADVANCE_NR('}', "}"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTemplateParameterList(const ListNode *&node) +{ + TemplateParameterAST *param = 0; + if (!parseTemplateParameter(param)) + return false; + + node = snoc(node, param, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseTemplateParameter(param)) { + syntaxError(); + break; + } else { + node = snoc(node, param, _M_pool); + } + } + + return true; +} + +bool Parser::parseTemplateParameter(TemplateParameterAST *&node) +{ + std::size_t start = token_stream.cursor(); + TemplateParameterAST *ast = CreateNode(_M_pool); + + int tk = token_stream.lookAhead(); + + if ((tk == Token_class || tk == Token_typename || tk == Token_template) + && parseTypeParameter(ast->type_parameter)) { + // nothing to do + } else if (!parseParameterDeclaration(ast->parameter_declaration)) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTypeParameter(TypeParameterAST *&node) +{ + std::size_t start = token_stream.cursor(); + + TypeParameterAST *ast = CreateNode(_M_pool); + ast->type = start; + + switch (token_stream.lookAhead()) { + case Token_class: + case Token_typename: { + token_stream.nextToken(); // skip class + + // parse optional name + if (parseName(ast->name, true)) { + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + if (!parseTypeId(ast->type_id)) { + //syntaxError(); + token_stream.rewind((int) start); + return false; + } + } else if (token_stream.lookAhead() != ',' + && token_stream.lookAhead() != '>') { + token_stream.rewind((int) start); + return false; + } + } + } + break; + + case Token_template: { + token_stream.nextToken(); // skip template + ADVANCE('<', "<"); + + if (!parseTemplateParameterList(ast->template_parameters)) + return false; + + ADVANCE('>', ">"); + + if (token_stream.lookAhead() == Token_class) + token_stream.nextToken(); + + // parse optional name + if (parseName(ast->name, true)) { + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + if (!parseTypeId(ast->type_id)) { + syntaxError(); + return false; + } + } + } + + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + parseName(ast->template_name, true); + } + } + break; + + default: + return false; + + } // end switch + + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; +} + +bool Parser::parseStorageClassSpecifier(const ListNode *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk; + while (0 != (tk = token_stream.lookAhead()) + && (tk == Token_friend || tk == Token_auto + || tk == Token_register || tk == Token_static + || tk == Token_extern || tk == Token_mutable)) { + node = snoc(node, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + } + + return start != token_stream.cursor(); +} + +bool Parser::parseFunctionSpecifier(const ListNode *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk; + while (0 != (tk = token_stream.lookAhead()) + && (tk == Token_inline || tk == Token_virtual + || tk == Token_explicit || tk == Token_Q_INVOKABLE)) { + node = snoc(node, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + } + + return start != token_stream.cursor(); +} + +bool Parser::parseTypeId(TypeIdAST *&node) +{ + /// @todo implement the AST for typeId + std::size_t start = token_stream.cursor(); + + TypeSpecifierAST *spec = 0; + if (!parseTypeSpecifier(spec)) { + token_stream.rewind((int) start); + return false; + } + + DeclaratorAST *decl = 0; + parseAbstractDeclarator(decl); + + TypeIdAST *ast = CreateNode(_M_pool); + ast->type_specifier = spec; + ast->declarator = decl; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseInitDeclaratorList(const ListNode *&node) +{ + InitDeclaratorAST *decl = 0; + if (!parseInitDeclarator(decl)) + return false; + + node = snoc(node, decl, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseInitDeclarator(decl)) { + syntaxError(); + break; + } + node = snoc(node, decl, _M_pool); + } + + return true; +} + +bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ParameterDeclarationClauseAST *ast + = CreateNode(_M_pool); + + if (!parseParameterDeclarationList(ast->parameter_declarations)) { + if (token_stream.lookAhead() == ')') + goto good; + + if (token_stream.lookAhead() == Token_ellipsis + && token_stream.lookAhead(1) == ')') { + ast->ellipsis = token_stream.cursor(); + goto good; + } + + return false; + } + +good: + + if (token_stream.lookAhead() == Token_ellipsis) { + ast->ellipsis = token_stream.cursor(); + token_stream.nextToken(); + } + + /// @todo add ellipsis + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseParameterDeclarationList(const ListNode *&node) +{ + std::size_t start = token_stream.cursor(); + + ParameterDeclarationAST *param = 0; + if (!parseParameterDeclaration(param)) { + token_stream.rewind((int) start); + return false; + } + + node = snoc(node, param, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (token_stream.lookAhead() == Token_ellipsis) + break; + + if (!parseParameterDeclaration(param)) { + token_stream.rewind((int) start); + return false; + } + node = snoc(node, param, _M_pool); + } + + return true; +} + +bool Parser::parseParameterDeclaration(ParameterDeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + const ListNode *storage = 0; + parseStorageClassSpecifier(storage); + + // parse decl spec + TypeSpecifierAST *spec = 0; + if (!parseTypeSpecifier(spec)) { + token_stream.rewind((int) start); + return false; + } + + int index = (int) token_stream.cursor(); + + DeclaratorAST *decl = 0; + if (!parseDeclarator(decl)) { + token_stream.rewind((int) index); + + // try with abstract declarator + parseAbstractDeclarator(decl); + } + + ExpressionAST *expr = 0; + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + if (!parseLogicalOrExpression(expr, true)) + reportError(("Expression expected")); + } + + ParameterDeclarationAST *ast = CreateNode(_M_pool); + ast->type_specifier = spec; + ast->declarator = decl; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parse_Attribute__() +{ + token_stream.nextToken(); + + ADVANCE('(', "("); + + ExpressionAST *expr = 0; + parseExpression(expr); + + if (token_stream.lookAhead() != ')') { + reportError(("')' expected")); + return false; + } else { + token_stream.nextToken(); + } + return true; +} + +QString Parser::tokenText(AST *ast) const +{ + if (!ast) + return QString(); + + int start_token = ast->start_token; + int end_token = ast->end_token; + + Token const &tk = token_stream.token(start_token); + Token const &end_tk = token_stream.token(end_token); + + return QString::fromLatin1(&tk.text[tk.position], + (int)(end_tk.position - tk.position)).trimmed(); +} + +bool Parser::parseForwardDeclarationSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + int kind = token_stream.lookAhead(); + if (kind != Token_class && kind != Token_struct && kind != Token_union) + return false; + + std::size_t class_key = token_stream.cursor(); + token_stream.nextToken(); + + NameAST *name = 0; + if (!parseName(name, false)) { + token_stream.rewind((int) start); + return false; + } + + BaseClauseAST *bases = 0; + if (token_stream.lookAhead() == ':') { + if (!parseBaseClause(bases)) { + token_stream.rewind((int) start); + return false; + } + } + + if (token_stream.lookAhead() != ';') { + token_stream.rewind((int) start); + return false; + } + + ForwardDeclarationSpecifierAST *ast = CreateNode(_M_pool); + ast->class_key = class_key; + ast->name = name; + ast->base_clause = bases; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseClassSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + int kind = token_stream.lookAhead(); + if (kind != Token_class && kind != Token_struct && kind != Token_union) + return false; + + std::size_t class_key = token_stream.cursor(); + token_stream.nextToken(); + + WinDeclSpecAST *winDeclSpec = 0; + parseWinDeclSpec(winDeclSpec); + + if (token_stream.lookAhead() == Token___attribute__) + parse_Attribute__(); + + while (token_stream.lookAhead() == Token_identifier + && token_stream.lookAhead(1) == Token_identifier) + token_stream.nextToken(); + + NameAST *name = 0; + parseName(name, true); + + BaseClauseAST *bases = 0; + + if (token_stream.lookAhead() == ':') { + if (!parseBaseClause(bases)) + skipUntil('{'); + } + + if (token_stream.lookAhead() != '{') { + + token_stream.rewind((int) start); + return false; + } + + ADVANCE('{', "{"); + + ClassSpecifierAST *ast = CreateNode(_M_pool); + ast->win_decl_specifiers = winDeclSpec; + ast->class_key = class_key; + ast->name = name; + ast->base_clause = bases; + + while (token_stream.lookAhead()) { + if (token_stream.lookAhead() == '}') + break; + + std::size_t startDecl = token_stream.cursor(); + + DeclarationAST *memSpec = 0; + if (!parseMemberSpecification(memSpec)) { + if (startDecl == token_stream.cursor()) + token_stream.nextToken(); // skip at least one token + skipUntilDeclaration(); + } else + ast->member_specs = snoc(ast->member_specs, memSpec, _M_pool); + } + + ADVANCE_NR('}', "}"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseAccessSpecifier(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + const ListNode *specs = 0; + + bool done = false; + while (!done) { + switch (token_stream.lookAhead()) { + case Token_signals: + case Token_slots: + case Token_k_dcop: + case Token_k_dcop_signals: + case Token_public: + case Token_protected: + case Token_private: + specs = snoc(specs, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + break; + + default: + done = true; + break; + } + } + + if (!specs) + return false; + + ADVANCE(':', ":"); + + AccessSpecifierAST *ast = CreateNode(_M_pool); + ast->specs = specs; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseMemberSpecification(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() == ';') { + token_stream.nextToken(); + return true; + } else if (token_stream.lookAhead() == Token_Q_OBJECT + || token_stream.lookAhead() == Token_K_DCOP) { + token_stream.nextToken(); + return true; + } else if (parseTypedef(node)) { + return true; + } else if (parseUsing(node)) { + return true; + } else if (parseTemplateDeclaration(node)) { + return true; + } else if (parseAccessSpecifier(node)) { + return true; + } else if (parseQ_PROPERTY(node)) { + return true; + } else if (parseQ_ENUMS(node)) { + return true; + } + + token_stream.rewind((int) start); + + const ListNode *cv = 0; + parseCvQualify(cv); + + const ListNode *storageSpec = 0; + parseStorageClassSpecifier(storageSpec); + + parseCvQualify(cv); + + TypeSpecifierAST *spec = 0; + if (parseEnumSpecifier(spec) || parseClassSpecifier(spec)) { + parseCvQualify(cv); + spec->cv = cv; + + const ListNode *declarators = 0; + parseInitDeclaratorList(declarators); + ADVANCE(';', ";"); + + SimpleDeclarationAST *ast = CreateNode(_M_pool); + ast->type_specifier = spec; + ast->init_declarators = declarators; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + + token_stream.rewind((int) start); + return parseDeclarationInternal(node); +} + +bool Parser::parseCtorInitializer(CtorInitializerAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(':'); + + CtorInitializerAST *ast = CreateNode(_M_pool); + ast->colon = start; + + if (!parseMemInitializerList(ast->member_initializers)) + reportError(("Member initializers expected")); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk = token_stream.lookAhead(); + if (tk == Token_class + || tk == Token_struct + || tk == Token_union + || tk == Token_enum + || tk == Token_typename) { + std::size_t type = token_stream.cursor(); + token_stream.nextToken(); + + NameAST *name = 0; + if (parseName(name, true)) { + ElaboratedTypeSpecifierAST *ast + = CreateNode(_M_pool); + + ast->type = type; + ast->name = name; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + + token_stream.rewind((int) start); + return false; +} + +bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_throw); + ADVANCE('(', "("); + + ExceptionSpecificationAST *ast = CreateNode(_M_pool); + + if (token_stream.lookAhead() == Token_ellipsis) { + ast->ellipsis = token_stream.cursor(); + token_stream.nextToken(); + } else { + parseTypeIdList(ast->type_ids); + } + + ADVANCE(')', ")"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseEnumerator(EnumeratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_identifier); + std::size_t id = token_stream.cursor() - 1; + + EnumeratorAST *ast = CreateNode(_M_pool); + ast->id = id; + + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + if (!parseConstantExpression(ast->expression)) + reportError(("Constant expression expected")); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseInitDeclarator(InitDeclaratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeclaratorAST *decl = 0; + if (!parseDeclarator(decl)) + return false; + + if (token_stream.lookAhead(0) == Token_asm) { + token_stream.nextToken(); + skip('(', ')'); + token_stream.nextToken(); + } + + InitializerAST *init = 0; + parseInitializer(init); + + InitDeclaratorAST *ast = CreateNode(_M_pool); + ast->declarator = decl; + ast->initializer = init; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseBaseClause(BaseClauseAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(':'); + + BaseSpecifierAST *baseSpec = 0; + if (!parseBaseSpecifier(baseSpec)) + return false; + + BaseClauseAST *ast = CreateNode(_M_pool); + ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseBaseSpecifier(baseSpec)) { + reportError(("Base class specifier expected")); + break; + } + ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, _M_pool); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseInitializer(InitializerAST *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk = token_stream.lookAhead(); + if (tk != '=' && tk != '(') + return false; + + InitializerAST *ast = CreateNode(_M_pool); + + if (tk == '=') { + token_stream.nextToken(); + + if (!parseInitializerClause(ast->initializer_clause)) + reportError(("Initializer clause expected")); + + } else if (tk == '(') { + token_stream.nextToken(); + parseCommaExpression(ast->expression); + CHECK(')'); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseMemInitializerList(const ListNode *&node) +{ + MemInitializerAST *init = 0; + + if (!parseMemInitializer(init)) + return false; + + node = snoc(node, init, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseMemInitializer(init)) + break; + + node = snoc(node, init, _M_pool); + } + + return true; +} + +bool Parser::parseMemInitializer(MemInitializerAST *&node) +{ + std::size_t start = token_stream.cursor(); + + NameAST *initId = 0; + if (!parseName(initId, true)) { + reportError(("Identifier expected")); + return false; + } + + ADVANCE('(', "("); + ExpressionAST *expr = 0; + parseCommaExpression(expr); + ADVANCE(')', ")"); + + MemInitializerAST *ast = CreateNode(_M_pool); + ast->initializer_id = initId; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTypeIdList(const ListNode *&node) +{ + TypeIdAST *typeId = 0; + if (!parseTypeId(typeId)) + return false; + + node = snoc(node, typeId, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + if (parseTypeId(typeId)) { + node = snoc(node, typeId, _M_pool); + } else { + reportError(("Type id expected")); + break; + } + } + + return true; +} + +bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + BaseSpecifierAST *ast = CreateNode(_M_pool); + + if (token_stream.lookAhead() == Token_virtual) { + ast->virt = token_stream.cursor(); + token_stream.nextToken(); + + int tk = token_stream.lookAhead(); + if (tk == Token_public || tk == Token_protected + || tk == Token_private) { + ast->access_specifier = token_stream.cursor(); + token_stream.nextToken(); + } + } else { + int tk = token_stream.lookAhead(); + if (tk == Token_public || tk == Token_protected + || tk == Token_private) { + ast->access_specifier = token_stream.cursor(); + token_stream.nextToken(); + } + + if (token_stream.lookAhead() == Token_virtual) { + ast->virt = token_stream.cursor(); + token_stream.nextToken(); + } + } + + if (!parseName(ast->name, true)) + reportError(("Class name expected")); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseInitializerClause(InitializerClauseAST *&node) +{ + std::size_t start = token_stream.cursor(); + + InitializerClauseAST *ast = CreateNode(_M_pool); + + if (token_stream.lookAhead() == '{') { +#if defined(__GNUC__) +#warning "implement me" +#endif + if (skip('{', '}')) + token_stream.nextToken(); + else + reportError(("} missing")); + } else { + if (!parseAssignmentExpression(ast->expression)) + reportError(("Expression expected")); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parsePtrToMember(PtrToMemberAST *&node) +{ +#if defined(__GNUC__) +#warning "implemente me (AST)" +#endif + + std::size_t start = token_stream.cursor(); + + std::size_t global_scope = 0; + if (token_stream.lookAhead() == Token_scope) { + global_scope = token_stream.cursor(); + token_stream.nextToken(); + } + + UnqualifiedNameAST *name = 0; + while (token_stream.lookAhead() == Token_identifier) { + if (!parseUnqualifiedName(name)) + break; + + if (token_stream.lookAhead() == Token_scope + && token_stream.lookAhead(1) == '*') { + token_stream.nextToken(); + token_stream.nextToken(); + + PtrToMemberAST *ast = CreateNode(_M_pool); + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + + if (token_stream.lookAhead() == Token_scope) + token_stream.nextToken(); + } + + token_stream.rewind((int) start); + return false; +} + +bool Parser::parseUnqualifiedName(UnqualifiedNameAST *&node, + bool parseTemplateId) +{ + std::size_t start = token_stream.cursor(); + + std::size_t tilde = 0; + std::size_t id = 0; + OperatorFunctionIdAST *operator_id = 0; + + if (token_stream.lookAhead() == Token_identifier) { + id = token_stream.cursor(); + token_stream.nextToken(); + } else if (token_stream.lookAhead() == '~' + && token_stream.lookAhead(1) == Token_identifier) { + tilde = token_stream.cursor(); + token_stream.nextToken(); // skip ~ + + id = token_stream.cursor(); + token_stream.nextToken(); // skip classname + } else if (token_stream.lookAhead() == Token_operator) { + if (!parseOperatorFunctionId(operator_id)) + return false; + } else { + return false; + } + + UnqualifiedNameAST *ast = CreateNode(_M_pool); + ast->tilde = tilde; + ast->id = id; + ast->operator_id = operator_id; + + if (parseTemplateId && !tilde) { + std::size_t index = token_stream.cursor(); + + if (token_stream.lookAhead() == '<') { + token_stream.nextToken(); + + // optional template arguments + parseTemplateArgumentList(ast->template_arguments); + + if (token_stream.lookAhead() == '>') { + token_stream.nextToken(); + } else { + ast->template_arguments = 0; + token_stream.rewind((int) index); + } + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseStringLiteral(StringLiteralAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() != Token_string_literal) + return false; + + StringLiteralAST *ast = CreateNode(_M_pool); + + while (token_stream.lookAhead() == Token_string_literal) { + ast->literals = snoc(ast->literals, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseExpressionStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ExpressionAST *expr = 0; + parseCommaExpression(expr); + + ADVANCE(';', ";"); + + ExpressionStatementAST *ast = CreateNode(_M_pool); + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case Token_while: + return parseWhileStatement(node); + + case Token_do: + return parseDoStatement(node); + + case Token_for: + return parseForStatement(node); + + case Token_if: + return parseIfStatement(node); + + case Token_switch: + return parseSwitchStatement(node); + + case Token_try: + return parseTryBlockStatement(node); + + case Token_case: + case Token_default: + return parseLabeledStatement(node); + + case Token_break: + case Token_continue: +#if defined(__GNUC__) +#warning "implement me" +#endif + token_stream.nextToken(); + ADVANCE(';', ";"); + return true; + + case Token_goto: +#if defined(__GNUC__) +#warning "implement me" +#endif + token_stream.nextToken(); + ADVANCE(Token_identifier, "identifier"); + ADVANCE(';', ";"); + return true; + + case Token_return: { + token_stream.nextToken(); + ExpressionAST *expr = 0; + parseCommaExpression(expr); + + ADVANCE(';', ";"); + + ReturnStatementAST *ast = CreateNode(_M_pool); + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case '{': + return parseCompoundStatement(node); + + case Token_identifier: + if (parseLabeledStatement(node)) + return true; + break; + } + + return parseExpressionOrDeclarationStatement(node); +} + +bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node) +{ + bool blocked = block_errors(true); + + std::size_t start = token_stream.cursor(); + + StatementAST *decl_ast = 0; + bool maybe_amb = parseDeclarationStatement(decl_ast); + maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';'; + + std::size_t end = token_stream.cursor(); + + token_stream.rewind((int) start); + StatementAST *expr_ast = 0; + maybe_amb &= parseExpressionStatement(expr_ast); + maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';'; + + if (maybe_amb) { + Q_ASSERT(decl_ast && expr_ast); + ExpressionOrDeclarationStatementAST *ast = + CreateNode(_M_pool); + ast->declaration = decl_ast; + ast->expression = expr_ast; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } else { + token_stream.rewind((int) std::max(end, token_stream.cursor())); + + node = decl_ast; + if (!node) + node = expr_ast; + } + + block_errors(blocked); + + if (!node) + syntaxError(); + + return node != 0; +} + +bool Parser::parseCondition(ConditionAST *&node, bool initRequired) +{ + std::size_t start = token_stream.cursor(); + + ConditionAST *ast = CreateNode(_M_pool); + TypeSpecifierAST *spec = 0; + + if (parseTypeSpecifier(spec)) { + ast->type_specifier = spec; + + std::size_t declarator_start = token_stream.cursor(); + + DeclaratorAST *decl = 0; + if (!parseDeclarator(decl)) { + token_stream.rewind((int) declarator_start); + if (!initRequired && !parseAbstractDeclarator(decl)) + decl = 0; + } + + if (decl && (!initRequired || token_stream.lookAhead() == '=')) { + ast->declarator = decl; + + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + parseExpression(ast->expression); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + + token_stream.rewind((int) start); + + if (!parseCommaExpression(ast->expression)) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + + +bool Parser::parseWhileStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_while, "while"); + ADVANCE('(' , "("); + + ConditionAST *cond = 0; + if (!parseCondition(cond)) { + reportError(("condition expected")); + return false; + } + ADVANCE(')', ")"); + + StatementAST *body = 0; + if (!parseStatement(body)) { + reportError(("statement expected")); + return false; + } + + WhileStatementAST *ast = CreateNode(_M_pool); + ast->condition = cond; + ast->statement = body; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDoStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_do, "do"); + + StatementAST *body = 0; + if (!parseStatement(body)) { + reportError(("statement expected")); + //return false; + } + + ADVANCE_NR(Token_while, "while"); + ADVANCE_NR('(' , "("); + + ExpressionAST *expr = 0; + if (!parseCommaExpression(expr)) { + reportError(("expression expected")); + //return false; + } + + ADVANCE_NR(')', ")"); + ADVANCE_NR(';', ";"); + + DoStatementAST *ast = CreateNode(_M_pool); + ast->statement = body; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseForStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_for, "for"); + ADVANCE('(', "("); + + StatementAST *init = 0; + if (!parseForInitStatement(init)) { + reportError(("for initialization expected")); + return false; + } + + ConditionAST *cond = 0; + parseCondition(cond); + ADVANCE(';', ";"); + + ExpressionAST *expr = 0; + parseCommaExpression(expr); + ADVANCE(')', ")"); + + StatementAST *body = 0; + if (!parseStatement(body)) + return false; + + ForStatementAST *ast = CreateNode(_M_pool); + ast->init_statement = init; + ast->condition = cond; + ast->expression = expr; + ast->statement = body; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseForInitStatement(StatementAST *&node) +{ + if (parseDeclarationStatement(node)) + return true; + + return parseExpressionStatement(node); +} + +bool Parser::parseCompoundStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK('{'); + + CompoundStatementAST *ast = CreateNode(_M_pool); + + while (token_stream.lookAhead()) { + if (token_stream.lookAhead() == '}') + break; + + std::size_t startStmt = token_stream.cursor(); + + StatementAST *stmt = 0; + if (!parseStatement(stmt)) { + if (startStmt == token_stream.cursor()) + token_stream.nextToken(); + + skipUntilStatement(); + } else { + ast->statements = snoc(ast->statements, stmt, _M_pool); + } + } + + ADVANCE_NR('}', "}"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseIfStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_if, "if"); + + ADVANCE('(' , "("); + + IfStatementAST *ast = CreateNode(_M_pool); + + ConditionAST *cond = 0; + if (!parseCondition(cond)) { + reportError(("condition expected")); + return false; + } + ADVANCE(')', ")"); + + StatementAST *stmt = 0; + if (!parseStatement(stmt)) { + reportError(("statement expected")); + return false; + } + + ast->condition = cond; + ast->statement = stmt; + + if (token_stream.lookAhead() == Token_else) { + token_stream.nextToken(); + + if (!parseStatement(ast->else_statement)) { + reportError(("statement expected")); + return false; + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseSwitchStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + ADVANCE(Token_switch, "switch"); + + ADVANCE('(' , "("); + + ConditionAST *cond = 0; + if (!parseCondition(cond)) { + reportError(("condition expected")); + return false; + } + ADVANCE(')', ")"); + + StatementAST *stmt = 0; + if (!parseCompoundStatement(stmt)) { + syntaxError(); + return false; + } + + SwitchStatementAST *ast = CreateNode(_M_pool); + ast->condition = cond; + ast->statement = stmt; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseLabeledStatement(StatementAST *&node) +{ + switch (token_stream.lookAhead()) { + case Token_identifier: + case Token_default: + if (token_stream.lookAhead(1) == ':') { + token_stream.nextToken(); + token_stream.nextToken(); + + StatementAST *stmt = 0; + if (parseStatement(stmt)) { + node = stmt; + return true; + } + } + break; + + case Token_case: { + token_stream.nextToken(); + ExpressionAST *expr = 0; + if (!parseConstantExpression(expr)) { + reportError(("expression expected")); + } else if (token_stream.lookAhead() == Token_ellipsis) { + token_stream.nextToken(); + + ExpressionAST *expr2 = 0; + if (!parseConstantExpression(expr2)) + reportError(("expression expected")); + } + ADVANCE(':', ":"); + + StatementAST *stmt = 0; + if (parseStatement(stmt)) { + node = stmt; + return true; + } + } + break; + + } + + return false; +} + +bool Parser::parseBlockDeclaration(DeclarationAST *&node) +{ + switch (token_stream.lookAhead()) { + case Token_typedef: + return parseTypedef(node); + case Token_using: + return parseUsing(node); + case Token_asm: + return parseAsmDefinition(node); + case Token_namespace: + return parseNamespaceAliasDefinition(node); + } + + std::size_t start = token_stream.cursor(); + + const ListNode *cv = 0; + parseCvQualify(cv); + + const ListNode *storageSpec = 0; + parseStorageClassSpecifier(storageSpec); + + parseCvQualify(cv); + + TypeSpecifierAST *spec = 0; + if (!parseTypeSpecifierOrClassSpec(spec)) { // replace with simpleTypeSpecifier?!?! + token_stream.rewind((int) start); + return false; + } + + parseCvQualify(cv); + spec->cv = cv; + + const ListNode *declarators = 0; + parseInitDeclaratorList(declarators); + + if (token_stream.lookAhead() != ';') { + token_stream.rewind((int) start); + return false; + } + token_stream.nextToken(); + + SimpleDeclarationAST *ast = CreateNode(_M_pool); + ast->type_specifier = spec; + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_namespace); + + NamespaceAliasDefinitionAST *ast + = CreateNode(_M_pool); + + ADVANCE(Token_identifier, "identifier"); + ast->namespace_name = token_stream.cursor() - 1; + + ADVANCE('=', "="); + + if (!parseName(ast->alias_name)) + reportError(("Namespace name expected")); + + ADVANCE(';', ";"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDeclarationStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeclarationAST *decl = 0; + if (!parseBlockDeclaration(decl)) + return false; + + DeclarationStatementAST *ast = CreateNode(_M_pool); + ast->declaration = decl; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDeclarationInternal(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + // that is for the case '__declspec(dllexport) int ...' or + // '__declspec(dllexport) inline int ...', etc. + WinDeclSpecAST *winDeclSpec = 0; + parseWinDeclSpec(winDeclSpec); + + const ListNode *funSpec = 0; + bool hasFunSpec = parseFunctionSpecifier(funSpec); + + const ListNode *cv = 0; + parseCvQualify(cv); + + const ListNode *storageSpec = 0; + bool hasStorageSpec = parseStorageClassSpecifier(storageSpec); + + if (hasStorageSpec && !hasFunSpec) + hasFunSpec = parseFunctionSpecifier(funSpec); + + // that is for the case 'friend __declspec(dllexport) ....' + parseWinDeclSpec(winDeclSpec); + + if (!cv) + parseCvQualify(cv); + + int index = (int) token_stream.cursor(); + NameAST *name = 0; + if (parseName(name, true) && token_stream.lookAhead() == '(') { + // no type specifier, maybe a constructor or a cast operator?? + + token_stream.rewind((int) index); + + InitDeclaratorAST *declarator = 0; + if (parseInitDeclarator(declarator)) { + switch (token_stream.lookAhead()) { + case ';': { + token_stream.nextToken(); + + SimpleDeclarationAST *ast + = CreateNode(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->init_declarators = snoc(ast->init_declarators, + declarator, _M_pool); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case ':': { + CtorInitializerAST *ctorInit = 0; + StatementAST *funBody = 0; + + if (parseCtorInitializer(ctorInit) + && parseFunctionBody(funBody)) { + FunctionDefinitionAST *ast + = CreateNode(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->init_declarator = declarator; + ast->function_body = funBody; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + break; + + case '{': { + StatementAST *funBody = 0; + if (parseFunctionBody(funBody)) { + FunctionDefinitionAST *ast + = CreateNode(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->init_declarator = declarator; + ast->function_body = funBody; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + break; + + case '(': + case '[': + // ops!! it seems a declarator + goto start_decl; + break; + } + + } + } + +start_decl: + token_stream.rewind((int) index); + + if (token_stream.lookAhead() == Token_const + && token_stream.lookAhead(1) == Token_identifier + && token_stream.lookAhead(2) == '=') { + // constant definition + token_stream.nextToken(); // skip const + + const ListNode *declarators = 0; + if (!parseInitDeclaratorList(declarators)) { + syntaxError(); + return false; + } + + ADVANCE(';', ";"); + +#if defined(__GNUC__) +#warning "mark the ast as constant" +#endif + SimpleDeclarationAST *ast = CreateNode(_M_pool); + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + + TypeSpecifierAST *spec = 0; + if (parseTypeSpecifier(spec)) { + Q_ASSERT(spec); + + if (!hasFunSpec) + parseFunctionSpecifier(funSpec); // e.g. "void inline" + + spec->cv = cv; + + const ListNode *declarators = 0; + InitDeclaratorAST *decl = 0; + int startDeclarator = (int) token_stream.cursor(); + bool maybeFunctionDefinition = false; + + if (token_stream.lookAhead() != ';') { + if (parseInitDeclarator(decl) && token_stream.lookAhead() == '{') { + // function definition + maybeFunctionDefinition = true; + } else { + token_stream.rewind((int) startDeclarator); + if (!parseInitDeclaratorList(declarators)) { + syntaxError(); + return false; + } + } + } + + switch (token_stream.lookAhead()) { + case ';': { + token_stream.nextToken(); + SimpleDeclarationAST *ast + = CreateNode(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->type_specifier = spec; + ast->win_decl_specifiers = winDeclSpec; + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case '{': { + if (!maybeFunctionDefinition) { + syntaxError(); + return false; + } + + StatementAST *funBody = 0; + if (parseFunctionBody(funBody)) { + FunctionDefinitionAST *ast + = CreateNode(_M_pool); + + ast->win_decl_specifiers = winDeclSpec; + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->type_specifier = spec; + ast->init_declarator = decl; + ast->function_body = funBody; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + break; + } // end switch + } + + syntaxError(); + return false; +} + +bool Parser::skipFunctionBody(StatementAST *&) +{ +#if defined(__GNUC__) +#warning "Parser::skipFunctionBody() -- implement me" +#endif + Q_ASSERT(0); // ### not implemented + return 0; +} + +bool Parser::parseFunctionBody(StatementAST *&node) +{ + if (control->skipFunctionBody()) + return skipFunctionBody(node); + + return parseCompoundStatement(node); +} + +bool Parser::parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node) +{ + if (parseClassSpecifier(node)) + return true; + else if (parseEnumSpecifier(node)) + return true; + else if (parseTypeSpecifier(node)) + return true; + + return false; +} + +bool Parser::parseTryBlockStatement(StatementAST *&node) +{ +#if defined(__GNUC__) +#warning "implement me" +#endif + CHECK(Token_try); + + StatementAST *stmt = 0; + if (!parseCompoundStatement(stmt)) { + syntaxError(); + return false; + } + + if (token_stream.lookAhead() != Token_catch) { + reportError(("catch expected")); + return false; + } + + while (token_stream.lookAhead() == Token_catch) { + token_stream.nextToken(); + ADVANCE('(', "("); + ConditionAST *cond = 0; + if (token_stream.lookAhead() == Token_ellipsis) { + token_stream.nextToken(); + } else if (!parseCondition(cond, false)) { + reportError(("condition expected")); + return false; + } + ADVANCE(')', ")"); + + StatementAST *body = 0; + if (!parseCompoundStatement(body)) { + syntaxError(); + return false; + } + } + + node = stmt; + return true; +} + +bool Parser::parsePrimaryExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + PrimaryExpressionAST *ast = CreateNode(_M_pool); + + switch (token_stream.lookAhead()) { + case Token_string_literal: + parseStringLiteral(ast->literal); + break; + + case Token_number_literal: + case Token_char_literal: + case Token_true: + case Token_false: + case Token_this: + ast->token = token_stream.cursor(); + token_stream.nextToken(); + break; + + case '(': + token_stream.nextToken(); + + if (token_stream.lookAhead() == '{') { + if (!parseCompoundStatement(ast->expression_statement)) + return false; + } else { + if (!parseExpression(ast->sub_expression)) + return false; + } + + CHECK(')'); + break; + + default: + if (!parseName(ast->name)) + return false; + + break; + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + + +/* + postfix-expression-internal: + [ expression ] + ( expression-list [opt] ) + (.|->) template [opt] id-expression + (.|->) pseudo-destructor-name + ++ + -- +*/ +bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case '[': { + token_stream.nextToken(); + ExpressionAST *expr = 0; + parseExpression(expr); + CHECK(']'); + + SubscriptExpressionAST *ast + = CreateNode(_M_pool); + + ast->subscript = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case '(': { + token_stream.nextToken(); + ExpressionAST *expr = 0; + parseExpression(expr); + CHECK(')'); + + FunctionCallAST *ast = CreateNode(_M_pool); + ast->arguments = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case '.': + case Token_arrow: { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + std::size_t templ = 0; + if (token_stream.lookAhead() == Token_template) { + templ = token_stream.cursor(); + token_stream.nextToken(); + } + + int saved = int(token_stream.cursor()); + NameAST *name = 0; + + if (parseName(name, true) && name->unqualified_name + && name->unqualified_name->template_arguments + && token_stream.lookAhead() == '(') { + // a template method call + // ### reverse the logic + } else { + token_stream.rewind(saved); + name = 0; + + if (!parseName(name, templ != 0)) + return false; + } + + ClassMemberAccessAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->name = name; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case Token_incr: + case Token_decr: { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + IncrDecrExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + default: + return false; + } +} + +/* + postfix-expression: + simple-type-specifier ( expression-list [opt] ) + primary-expression postfix-expression-internal* +*/ +bool Parser::parsePostfixExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case Token_dynamic_cast: + case Token_static_cast: + case Token_reinterpret_cast: + case Token_const_cast: { + std::size_t castOp = token_stream.cursor(); + token_stream.nextToken(); + + CHECK('<'); + TypeIdAST *typeId = 0; + parseTypeId(typeId); + CHECK('>'); + + CHECK('('); + ExpressionAST *expr = 0; + parseCommaExpression(expr); + CHECK(')'); + + CppCastExpressionAST *ast = CreateNode(_M_pool); + ast->op = castOp; + ast->type_id = typeId; + ast->expression = expr; + + ExpressionAST *e = 0; + while (parsePostfixExpressionInternal(e)) + ast->sub_expressions = snoc(ast->sub_expressions, e, _M_pool); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case Token_typename: { + std::size_t token = token_stream.cursor(); + token_stream.nextToken(); + + NameAST* name = 0; + if (!parseName(name, true)) + return false; + + CHECK('('); + ExpressionAST *expr = 0; + parseCommaExpression(expr); + CHECK(')'); + + TypeIdentificationAST *ast = CreateNode(_M_pool); + ast->typename_token = token; + ast->name = name; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case Token_typeid: { + token_stream.nextToken(); + + CHECK('('); + TypeIdAST *typeId = 0; + parseTypeId(typeId); + CHECK(')'); + + TypeIdentificationAST *ast = CreateNode(_M_pool); + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + default: + break; + } + + std::size_t saved_pos = token_stream.cursor(); + + TypeSpecifierAST *typeSpec = 0; + ExpressionAST *expr = 0; + + // let's try to parse a type + NameAST *name = 0; + if (parseName(name, true)) { + Q_ASSERT(name->unqualified_name); + + bool has_template_args = name->unqualified_name->template_arguments != 0; + + if (has_template_args && token_stream.lookAhead() == '(') { + ExpressionAST *cast_expr = 0; + if (parseCastExpression(cast_expr) + && cast_expr->kind == AST::Kind_CastExpression) { + token_stream.rewind((int) saved_pos); + parsePrimaryExpression(expr); + goto L_no_rewind; + } + } + } + + token_stream.rewind((int) saved_pos); + +L_no_rewind: + if (!expr && parseSimpleTypeSpecifier(typeSpec) + && token_stream.lookAhead() == '(') { + token_stream.nextToken(); // skip '(' + parseCommaExpression(expr); + CHECK(')'); + } else if (expr) { + typeSpec = 0; + } else { + typeSpec = 0; + token_stream.rewind((int) start); + + if (!parsePrimaryExpression(expr)) + return false; + } + + const ListNode *sub_expressions = 0; + ExpressionAST *sub_expression = 0; + + while (parsePostfixExpressionInternal(sub_expression)) + sub_expressions = snoc(sub_expressions, sub_expression, _M_pool); + + if (sub_expressions || !expr || (typeSpec && expr)) { + PostfixExpressionAST *ast = CreateNode(_M_pool); + ast->type_specifier = typeSpec; + ast->expression = expr; + ast->sub_expressions = sub_expressions; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } else + node = expr; + + return true; +} + +bool Parser::parseUnaryExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case Token_incr: + case Token_decr: + case '*': + case '&': + case '+': + case '-': + case '!': + case '~': { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *expr = 0; + if (!parseCastExpression(expr)) + return false; + + UnaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case Token_sizeof: { + std::size_t sizeof_token = token_stream.cursor(); + token_stream.nextToken(); + + SizeofExpressionAST *ast = CreateNode(_M_pool); + ast->sizeof_token = sizeof_token; + + std::size_t index = token_stream.cursor(); + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + if (parseTypeId(ast->type_id) && token_stream.lookAhead() == ')') { + token_stream.nextToken(); // skip ) + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; + } + + ast->type_id = 0; + token_stream.rewind((int) index); + } + + if (!parseUnaryExpression(ast->expression)) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; + } + + default: + break; + } + + int token = token_stream.lookAhead(); + + if (token == Token_new + || (token == Token_scope && token_stream.lookAhead(1) == Token_new)) + return parseNewExpression(node); + + if (token == Token_delete + || (token == Token_scope && token_stream.lookAhead(1) == Token_delete)) + return parseDeleteExpression(node); + + return parsePostfixExpression(node); +} + +bool Parser::parseNewExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + NewExpressionAST *ast = CreateNode(_M_pool); + + if (token_stream.lookAhead() == Token_scope + && token_stream.lookAhead(1) == Token_new) { + ast->scope_token = token_stream.cursor(); + token_stream.nextToken(); + } + + CHECK(Token_new); + ast->new_token = token_stream.cursor() - 1; + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + parseCommaExpression(ast->expression); + CHECK(')'); + } + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + parseTypeId(ast->type_id); + CHECK(')'); + } else { + parseNewTypeId(ast->new_type_id); + } + + parseNewInitializer(ast->new_initializer); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNewTypeId(NewTypeIdAST *&node) +{ + std::size_t start = token_stream.cursor(); + + TypeSpecifierAST *typeSpec = 0; + if (!parseTypeSpecifier(typeSpec)) + return false; + + NewTypeIdAST *ast = CreateNode(_M_pool); + ast->type_specifier = typeSpec; + + parseNewDeclarator(ast->new_declarator); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNewDeclarator(NewDeclaratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + NewDeclaratorAST *ast = CreateNode(_M_pool); + + PtrOperatorAST *ptrOp = 0; + if (parsePtrOperator(ptrOp)) { + ast->ptr_op = ptrOp; + parseNewDeclarator(ast->sub_declarator); + } + + while (token_stream.lookAhead() == '[') { + token_stream.nextToken(); + ExpressionAST *expr = 0; + parseExpression(expr); + ast->expressions = snoc(ast->expressions, expr, _M_pool); + ADVANCE(']', "]"); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNewInitializer(NewInitializerAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK('('); + + NewInitializerAST *ast = CreateNode(_M_pool); + + parseCommaExpression(ast->expression); + + CHECK(')'); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDeleteExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeleteExpressionAST *ast = CreateNode(_M_pool); + + if (token_stream.lookAhead() == Token_scope + && token_stream.lookAhead(1) == Token_delete) { + ast->scope_token = token_stream.cursor(); + token_stream.nextToken(); + } + + CHECK(Token_delete); + ast->delete_token = token_stream.cursor() - 1; + + if (token_stream.lookAhead() == '[') { + ast->lbracket_token = token_stream.cursor(); + token_stream.nextToken(); + CHECK(']'); + ast->rbracket_token = token_stream.cursor() - 1; + } + + if (!parseCastExpression(ast->expression)) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseCastExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + CastExpressionAST *ast = CreateNode(_M_pool); + + if (parseTypeId(ast->type_id)) { + if (token_stream.lookAhead() == ')') { + token_stream.nextToken(); + + if (parseCastExpression(ast->expression)) { + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + } + } + + token_stream.rewind((int) start); + return parseUnaryExpression(node); +} + +bool Parser::parsePmExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseCastExpression(node) || !node) // ### fixme + return false; + + while (token_stream.lookAhead() == Token_ptrmem) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseCastExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseMultiplicativeExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parsePmExpression(node)) + return false; + + while (token_stream.lookAhead() == '*' + || token_stream.lookAhead() == '/' + || token_stream.lookAhead() == '%') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parsePmExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + + +bool Parser::parseAdditiveExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseMultiplicativeExpression(node)) + return false; + + while (token_stream.lookAhead() == '+' || token_stream.lookAhead() == '-') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseMultiplicativeExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseShiftExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseAdditiveExpression(node)) + return false; + + while (token_stream.lookAhead() == Token_shift) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseAdditiveExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseRelationalExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseShiftExpression(node)) + return false; + + while (token_stream.lookAhead() == '<' + || (token_stream.lookAhead() == '>' && !templArgs) + || token_stream.lookAhead() == Token_leq + || token_stream.lookAhead() == Token_geq) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseShiftExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseEqualityExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseRelationalExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == Token_eq + || token_stream.lookAhead() == Token_not_eq) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseRelationalExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseAndExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseEqualityExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == '&') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseEqualityExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseExclusiveOrExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseAndExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == '^') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseAndExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseInclusiveOrExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseExclusiveOrExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == '|') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseExclusiveOrExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseLogicalAndExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseInclusiveOrExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == Token_and) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseInclusiveOrExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseLogicalOrExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseLogicalAndExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == Token_or) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseLogicalAndExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseConditionalExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseLogicalOrExpression(node)) + return false; + + if (token_stream.lookAhead() == '?') { + token_stream.nextToken(); + + ExpressionAST *leftExpr = 0; + if (!parseExpression(leftExpr)) + return false; + + CHECK(':'); + + ExpressionAST *rightExpr = 0; + if (!parseAssignmentExpression(rightExpr)) + return false; + + ConditionalExpressionAST *ast + = CreateNode(_M_pool); + + ast->condition = node; + ast->left_expression = leftExpr; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseAssignmentExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() == Token_throw && !parseThrowExpression(node)) + return false; + else if (!parseConditionalExpression(node)) + return false; + + while (token_stream.lookAhead() == Token_assign + || token_stream.lookAhead() == '=') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseConditionalExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseConstantExpression(ExpressionAST *&node) +{ + return parseConditionalExpression(node); +} + +bool Parser::parseExpression(ExpressionAST *&node) +{ + return parseCommaExpression(node); +} + +bool Parser::parseCommaExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseAssignmentExpression(node)) + return false; + + while (token_stream.lookAhead() == ',') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseAssignmentExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseThrowExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_throw); + + ThrowExpressionAST *ast = CreateNode(_M_pool); + ast->throw_token = token_stream.cursor() - 1; + + parseAssignmentExpression(ast->expression); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseQ_ENUMS(DeclarationAST *&node) +{ + if (token_stream.lookAhead() != Token_Q_ENUMS) + return false; + + if (token_stream.lookAhead(1) != '(') + return false; + + token_stream.nextToken(); + token_stream.nextToken(); + + int firstToken = token_stream.cursor(); + while (token_stream.lookAhead() != ')') + token_stream.nextToken(); + + QEnumsAST *ast = CreateNode(_M_pool); + UPDATE_POS(ast, firstToken, token_stream.cursor()); + node = ast; + + token_stream.nextToken(); + + return true; +} + +bool Parser::parseQ_PROPERTY(DeclarationAST *&node) +{ + if (token_stream.lookAhead() != Token_Q_PROPERTY) + return false; + + if (token_stream.lookAhead(1) != '(') + return false; + + token_stream.nextToken(); + token_stream.nextToken(); + + int firstToken = token_stream.cursor(); + while (token_stream.lookAhead() != ')') + token_stream.nextToken(); + + QPropertyAST *ast = CreateNode(_M_pool); + UPDATE_POS(ast, firstToken, token_stream.cursor()); + node = ast; + +// const Token &t1 = token_stream[firstToken]; +// const Token &t2 = token_stream[token_stream.cursor()]; +// printf("property: %s\n", +// qPrintable(QString::fromLatin1(t1.text + t1.position, t2.position - t1.position))); + + token_stream.nextToken(); + + return true; +} + +bool Parser::block_errors(bool block) +{ + bool current = _M_block_errors; + _M_block_errors = block; + return current; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/parser/parser.h b/parser/parser.h new file mode 100644 index 000000000..4b0c76c85 --- /dev/null +++ b/parser/parser.h @@ -0,0 +1,198 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef PARSER_H +#define PARSER_H + +#include "ast.h" +#include "lexer.h" + +#include + +class FileSymbol; +class Control; + +class Parser +{ +public: + Parser(Control *control); + ~Parser(); + + LocationManager &location() { return _M_location; } + + TranslationUnitAST *parse(const char *contents, std::size_t size, pool *p); + +private: + void reportError(const QString& msg); + void syntaxError(); + void tokenRequiredError(int expected); + +public: + bool skipFunctionBody(StatementAST *&node); + +public: + bool parse_Attribute__(); + bool parseAbstractDeclarator(DeclaratorAST *&node); + bool parseAccessSpecifier(DeclarationAST *&node); + bool parseAdditiveExpression(ExpressionAST *&node); + bool parseAndExpression(ExpressionAST *&node, bool templArgs = false); + bool parseAsmDefinition(DeclarationAST *&node); + bool parseAssignmentExpression(ExpressionAST *&node); + bool parseBaseClause(BaseClauseAST *&node); + bool parseBaseSpecifier(BaseSpecifierAST *&node); + bool parseBlockDeclaration(DeclarationAST *&node); + bool parseCastExpression(ExpressionAST *&node); + bool parseClassSpecifier(TypeSpecifierAST *&node); + bool parseForwardDeclarationSpecifier(TypeSpecifierAST *&node); + bool parseCommaExpression(ExpressionAST *&node); + bool parseCompoundStatement(StatementAST *&node); + bool parseCondition(ConditionAST *&node, bool initRequired = true); + bool parseConditionalExpression(ExpressionAST *&node); + bool parseConstantExpression(ExpressionAST *&node); + bool parseCtorInitializer(CtorInitializerAST *&node); + bool parseCvQualify(const ListNode *&node); + bool parseDeclaration(DeclarationAST *&node); + bool parseDeclarationInternal(DeclarationAST *&node); + bool parseDeclarationStatement(StatementAST *&node); + bool parseDeclarator(DeclaratorAST *&node); + bool parseDeleteExpression(ExpressionAST *&node); + bool parseDoStatement(StatementAST *&node); + bool parseElaboratedTypeSpecifier(TypeSpecifierAST *&node); + bool parseEnumSpecifier(TypeSpecifierAST *&node); + bool parseEnumerator(EnumeratorAST *&node); + bool parseEqualityExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseExceptionSpecification(ExceptionSpecificationAST *&node); + bool parseExclusiveOrExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseExpression(ExpressionAST *&node); + bool parseExpressionOrDeclarationStatement(StatementAST *&node); + bool parseExpressionStatement(StatementAST *&node); + bool parseForInitStatement(StatementAST *&node); + bool parseForStatement(StatementAST *&node); + bool parseFunctionBody(StatementAST *&node); + bool parseFunctionSpecifier(const ListNode *&node); + bool parseIfStatement(StatementAST *&node); + bool parseInclusiveOrExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseInitDeclarator(InitDeclaratorAST *&node); + bool parseInitDeclaratorList(const ListNode *&node); + bool parseInitializer(InitializerAST *&node); + bool parseInitializerClause(InitializerClauseAST *&node); + bool parseLabeledStatement(StatementAST *&node); + bool parseLinkageBody(LinkageBodyAST *&node); + bool parseLinkageSpecification(DeclarationAST *&node); + bool parseLogicalAndExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseLogicalOrExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseMemInitializer(MemInitializerAST *&node); + bool parseMemInitializerList(const ListNode *&node); + bool parseMemberSpecification(DeclarationAST *&node); + bool parseMultiplicativeExpression(ExpressionAST *&node); + bool parseName(NameAST *&node, bool acceptTemplateId = false); + bool parseNamespace(DeclarationAST *&node); + bool parseNamespaceAliasDefinition(DeclarationAST *&node); + bool parseNewDeclarator(NewDeclaratorAST *&node); + bool parseNewExpression(ExpressionAST *&node); + bool parseNewInitializer(NewInitializerAST *&node); + bool parseNewTypeId(NewTypeIdAST *&node); + bool parseOperator(OperatorAST *&node); + bool parseOperatorFunctionId(OperatorFunctionIdAST *&node); + bool parseParameterDeclaration(ParameterDeclarationAST *&node); + bool parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node); + bool parseParameterDeclarationList(const ListNode *&node); + bool parsePmExpression(ExpressionAST *&node); + bool parsePostfixExpression(ExpressionAST *&node); + bool parsePostfixExpressionInternal(ExpressionAST *&node); + bool parsePrimaryExpression(ExpressionAST *&node); + bool parsePtrOperator(PtrOperatorAST *&node); + bool parsePtrToMember(PtrToMemberAST *&node); + bool parseRelationalExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseShiftExpression(ExpressionAST *&node); + bool parseSimpleTypeSpecifier(TypeSpecifierAST *&node, + bool onlyIntegral = false); + bool parseStatement(StatementAST *&node); + bool parseStorageClassSpecifier(const ListNode *&node); + bool parseStringLiteral(StringLiteralAST *&node); + bool parseSwitchStatement(StatementAST *&node); + bool parseTemplateArgument(TemplateArgumentAST *&node); + bool parseTemplateArgumentList(const ListNode *&node, + bool reportError = true); + bool parseTemplateDeclaration(DeclarationAST *&node); + bool parseTemplateParameter(TemplateParameterAST *&node); + bool parseTemplateParameterList(const ListNode *&node); + bool parseThrowExpression(ExpressionAST *&node); + bool parseTranslationUnit(TranslationUnitAST *&node); + bool parseTryBlockStatement(StatementAST *&node); + bool parseTypeId(TypeIdAST *&node); + bool parseTypeIdList(const ListNode *&node); + bool parseTypeParameter(TypeParameterAST *&node); + bool parseTypeSpecifier(TypeSpecifierAST *&node); + bool parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node); + bool parseTypedef(DeclarationAST *&node); + bool parseUnaryExpression(ExpressionAST *&node); + bool parseUnqualifiedName(UnqualifiedNameAST *&node, + bool parseTemplateId = true); + bool parseUsing(DeclarationAST *&node); + bool parseUsingDirective(DeclarationAST *&node); + bool parseWhileStatement(StatementAST *&node); + bool parseWinDeclSpec(WinDeclSpecAST *&node); + + bool parseQ_PROPERTY(DeclarationAST *&node); + bool parseQ_ENUMS(DeclarationAST *&node); + + bool skipUntil(int token); + bool skipUntilDeclaration(); + bool skipUntilStatement(); + bool skip(int l, int r); + + void advance(); + + // private: + TokenStream token_stream; + LocationTable location_table; + LocationTable line_table; + + bool block_errors(bool block); + +private: + QString tokenText(AST *) const; + + LocationManager _M_location; + Control *control; + Lexer lexer; + pool *_M_pool; + bool _M_block_errors; + +private: + Parser(const Parser& source); + void operator = (const Parser& source); +}; + +#endif + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/r++.macros b/parser/r++.macros new file mode 100644 index 000000000..455276c84 --- /dev/null +++ b/parser/r++.macros @@ -0,0 +1,28 @@ + +#define __attribute__(a...) +#define __typeof__ __typeof + +#define __extension +#define __extension__ + +#define __restrict +#define __restrict__ + +#define __volatile volatile +#define __volatile__ volatile + +#define __inline inline +#define __inline__ inline + +#define __const const +#define __const__ const + +#define __asm asm +#define __asm__ asm + +#define __GNUC__ 3 +//#define __GNUC_MINOR__ 4 + +#define __ROBC__ 0 +#define __ROBC_MINOR__ 1 + diff --git a/parser/rpp-allocator.h b/parser/rpp-allocator.h new file mode 100644 index 000000000..313895f00 --- /dev/null +++ b/parser/rpp-allocator.h @@ -0,0 +1,24 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "parser/rxx_allocator.h" diff --git a/parser/rpp/builtin-macros.cpp b/parser/rpp/builtin-macros.cpp new file mode 100644 index 000000000..1b0fc06af --- /dev/null +++ b/parser/rpp/builtin-macros.cpp @@ -0,0 +1,23 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + diff --git a/parser/rpp/pp-cctype.h b/parser/rpp/pp-cctype.h new file mode 100644 index 000000000..5b0bf477c --- /dev/null +++ b/parser/rpp/pp-cctype.h @@ -0,0 +1,57 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_CCTYPE_H +#define PP_CCTYPE_H + +#include + +namespace rpp +{ + +inline bool pp_isalpha(int __ch) +{ + return std::isalpha((unsigned char) __ch) != 0; +} + +inline bool pp_isalnum(int __ch) +{ + return std::isalnum((unsigned char) __ch) != 0; +} + +inline bool pp_isdigit(int __ch) +{ + return std::isdigit((unsigned char) __ch) != 0; +} + +inline bool pp_isspace(int __ch) +{ + return std::isspace((unsigned char) __ch) != 0; +} + +} // namespace rpp + +#endif // PP_CCTYPE_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-configuration b/parser/rpp/pp-configuration new file mode 100644 index 000000000..15586dd88 --- /dev/null +++ b/parser/rpp/pp-configuration @@ -0,0 +1,86 @@ +#define __DBL_MIN_EXP__ (-1021) +#define __FLT_MIN__ 1.17549435e-38F +#define __CHAR_BIT__ 8 +#define __WCHAR_MAX__ 2147483647 +#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +#define __FLT_EVAL_METHOD__ 2 +#define __DBL_MIN_10_EXP__ (-307) +#define __FINITE_MATH_ONLY__ 0 +#define __GNUC_PATCHLEVEL__ 2 +#define __SHRT_MAX__ 32767 +#define __LDBL_MAX__ 1.18973149535723176502e+4932L +#define __UINTMAX_TYPE__ long long unsigned int +#define __linux 1 +#define __unix 1 +#define __LDBL_MAX_EXP__ 16384 +#define __linux__ 1 +#define __SCHAR_MAX__ 127 +#define __USER_LABEL_PREFIX__ +#define __STDC_HOSTED__ 1 +#define __LDBL_HAS_INFINITY__ 1 +#define __DBL_DIG__ 15 +#define __FLT_EPSILON__ 1.19209290e-7F +#define __GXX_WEAK__ 1 +#define __LDBL_MIN__ 3.36210314311209350626e-4932L +#define __unix__ 1 +#define __DECIMAL_DIG__ 21 +#define __gnu_linux__ 1 +#define __LDBL_HAS_QUIET_NAN__ 1 +#define __GNUC__ 4 +#define __DBL_MAX__ 1.7976931348623157e+308 +#define __DBL_HAS_INFINITY__ 1 +#define __cplusplus 1 +#define __DEPRECATED 1 +#define __DBL_MAX_EXP__ 1024 +#define __GNUG__ 4 +#define __LONG_LONG_MAX__ 9223372036854775807LL +#define __GXX_ABI_VERSION 1002 +#define __FLT_MIN_EXP__ (-125) +#define __DBL_MIN__ 2.2250738585072014e-308 +#define __FLT_MIN_10_EXP__ (-37) +#define __DBL_HAS_QUIET_NAN__ 1 +#define __REGISTER_PREFIX__ +#define __NO_INLINE__ 1 +#define __i386 1 +#define __FLT_MANT_DIG__ 24 +#define __VERSION__ "4.0.2 20050808 (prerelease) (Ubuntu 4.0.1-4ubuntu9)" +#define i386 1 +#define __i486__ 1 +#define unix 1 +#define __i386__ 1 +#define __SIZE_TYPE__ unsigned int +#define __ELF__ 1 +#define __FLT_RADIX__ 2 +#define __LDBL_EPSILON__ 1.08420217248550443401e-19L +#define __FLT_HAS_QUIET_NAN__ 1 +#define __FLT_MAX_10_EXP__ 38 +#define __LONG_MAX__ 2147483647L +#define __FLT_HAS_INFINITY__ 1 +#define linux 1 +#define __EXCEPTIONS 1 +#define __LDBL_MANT_DIG__ 64 +#define __WCHAR_TYPE__ int +#define __FLT_DIG__ 6 +#define __INT_MAX__ 2147483647 +#define __i486 1 +#define __FLT_MAX_EXP__ 128 +#define __DBL_MANT_DIG__ 53 +#define __WINT_TYPE__ unsigned int +#define __LDBL_MIN_EXP__ (-16381) +#define __LDBL_MAX_10_EXP__ 4932 +#define __DBL_EPSILON__ 2.2204460492503131e-16 +#define __tune_i486__ 1 +#define __INTMAX_MAX__ 9223372036854775807LL +#define __FLT_DENORM_MIN__ 1.40129846e-45F +#define __FLT_MAX__ 3.40282347e+38F +#define __INTMAX_TYPE__ long long int +#define __GNUC_MINOR__ 0 +#define __DBL_MAX_10_EXP__ 308 +#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L +#define __PTRDIFF_TYPE__ int +#define __LDBL_MIN_10_EXP__ (-4931) +#define __LDBL_DIG__ 18 +#define _GNU_SOURCE 1 + + +#define __STDC__ diff --git a/parser/rpp/pp-engine-bits.h b/parser/rpp/pp-engine-bits.h new file mode 100644 index 000000000..7594ab796 --- /dev/null +++ b/parser/rpp/pp-engine-bits.h @@ -0,0 +1,1252 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_ENGINE_BITS_H +#define PP_ENGINE_BITS_H + +#include "pp.h" +#include +#include +#include + +namespace rpp +{ + +inline std::string pp::fix_file_path(std::string const &filename) const +{ +#if defined (PP_OS_WIN) + std::string s = filename; + for (std::string::iterator it = s.begin(); it != s.end(); ++it) { + if (*it == '/') + *it = '\\'; + } + return s; +#else + return filename; +#endif +} + +inline bool pp::is_absolute(std::string const &filename) const +{ +#if defined(PP_OS_WIN) + return filename.length() >= 3 + && filename.at(1) == ':' + && (filename.at(2) == '\\' || filename.at(2) == '/'); +#else + return filename.length() >= 1 + && filename.at(0) == '/'; +#endif +} + +template +void pp::file(std::string const &filename, _OutputIterator __result) +{ + FILE *fp = std::fopen(filename.c_str(), "rb"); + if (fp != 0) { + std::string was = env.current_file; + env.current_file = filename; + file(fp, __result); + env.current_file = was; + } + //else + //std::cerr << "** WARNING file ``" << filename << " not found!" << std::endl; +} + +template +void pp::file(FILE *fp, _OutputIterator __result) +{ + assert(fp != 0); + +#if defined (HAVE_MMAP) + struct stat st; + fstat(FILENO(fp), &st); + std::size_t size = st.st_size; + char *buffer = 0; + buffer = (char *) ::mmap(0, size, PROT_READ, MAP_SHARED, FILENO(fp), 0); + fclose(fp); + if (!buffer || buffer == (char*) - 1) + return; + this->operator()(buffer, buffer + size, __result); + ::munmap(buffer, size); +#else + std::string buffer; + while (!feof(fp)) { + char tmp[1024]; + int read = (int) fread(tmp, sizeof(char), 1023, fp); + tmp[read] = '\0'; + buffer += tmp; + } + fclose(fp); + this->operator()(buffer.c_str(), buffer.c_str() + buffer.size(), __result); +#endif +} + +template +bool pp::find_header_protection(_InputIterator __first, _InputIterator __last, std::string *__prot) +{ + int was = env.current_line; + + while (__first != __last) { + if (pp_isspace(*__first)) { + if (*__first == '\n') + ++env.current_line; + + ++__first; + } else if (_PP_internal::comment_p(__first, __last)) { + __first = skip_comment_or_divop(__first, __last); + env.current_line += skip_comment_or_divop.lines; + } else if (*__first == '#') { + __first = skip_blanks(++__first, __last); + env.current_line += skip_blanks.lines; + + if (__first != __last && *__first == 'i') { + _InputIterator __begin = __first; + __first = skip_identifier(__begin, __last); + env.current_line += skip_identifier.lines; + + std::string __directive(__begin, __first); + + if (__directive == "ifndef") { + __first = skip_blanks(__first, __last); + env.current_line += skip_blanks.lines; + + __begin = __first; + __first = skip_identifier(__first, __last); + env.current_line += skip_identifier.lines; + + if (__begin != __first && __first != __last) { + __prot->assign(__begin, __first); + return true; + } + } + } + break; + } else + break; + } + + env.current_line = was; + return false; +} + +inline pp::PP_DIRECTIVE_TYPE pp::find_directive(char const *__directive, std::size_t __size) const +{ + switch (__size) { + case 2: + if (__directive[0] == 'i' + && __directive[1] == 'f') + return PP_IF; + break; + + case 4: + if (__directive[0] == 'e' && !strcmp(__directive, "elif")) + return PP_ELIF; + else if (__directive[0] == 'e' && !strcmp(__directive, "else")) + return PP_ELSE; + break; + + case 5: + if (__directive[0] == 'i' && !strcmp(__directive, "ifdef")) + return PP_IFDEF; + else if (__directive[0] == 'u' && !strcmp(__directive, "undef")) + return PP_UNDEF; + else if (__directive[0] == 'e') { + if (!strcmp(__directive, "endif")) + return PP_ENDIF; + else if (!strcmp(__directive, "error")) + return PP_ERROR; + } + break; + + case 6: + if (__directive[0] == 'i' && !strcmp(__directive, "ifndef")) + return PP_IFNDEF; + else if (__directive[0] == 'd' && !strcmp(__directive, "define")) + return PP_DEFINE; + else if (__directive[0] == 'p' && !strcmp(__directive, "pragma")) + return PP_PRAGMA; + break; + + case 7: + if (__directive[0] == 'i' && !strcmp(__directive, "include")) + return PP_INCLUDE; + else if (!strcmp(__directive, "warning")) + return PP_WARNING; + break; + + case 12: + if (__directive[0] == 'i' && !strcmp(__directive, "include_next")) + return PP_INCLUDE_NEXT; + break; + + default: + break; + } + std::cerr << "** WARNING unknown directive '#" << __directive << "' at " << env.current_file << ":" << env.current_line << std::endl; + return PP_UNKNOWN_DIRECTIVE; +} + +inline bool pp::file_isdir(std::string const &__filename) const +{ + struct stat __st; +#if defined(PP_OS_WIN) + if (stat(__filename.c_str(), &__st) == 0) + return (__st.st_mode & _S_IFDIR) == _S_IFDIR; + else + return false; +#else + if (lstat(__filename.c_str(), &__st) == 0) + return (__st.st_mode & S_IFDIR) == S_IFDIR; + else + return false; +#endif +} + +inline bool pp::file_exists(std::string const &__filename) const +{ + struct stat __st; +#if defined(PP_OS_WIN) + return stat(__filename.c_str(), &__st) == 0; +#else + return lstat(__filename.c_str(), &__st) == 0; +#endif +} + +inline FILE *pp::find_include_file(std::string const &__input_filename, std::string *__filepath, + INCLUDE_POLICY __include_policy, bool __skip_current_path) const +{ + assert(__filepath != 0); + assert(! __input_filename.empty()); + + __filepath->assign(__input_filename); + + if (is_absolute(*__filepath)) + return std::fopen(__filepath->c_str(), "r"); + + if (! env.current_file.empty()) + _PP_internal::extract_file_path(env.current_file, __filepath); + + if (__include_policy == INCLUDE_LOCAL && ! __skip_current_path) { + std::string __tmp(*__filepath); + __tmp += __input_filename; + + if (file_exists(__tmp) && !file_isdir(__tmp)) { + __filepath->append(__input_filename); + return std::fopen(__filepath->c_str(), "r"); + } + } + + std::vector::const_iterator it = include_paths.begin(); + + if (__skip_current_path) { + it = std::find(include_paths.begin(), include_paths.end(), *__filepath); + + if (it != include_paths.end()) + ++it; + + else + it = include_paths.begin(); + } + + for (; it != include_paths.end(); ++it) { + if (__skip_current_path && it == include_paths.begin()) + continue; + + __filepath->assign(*it); + __filepath->append(__input_filename); + + if (file_exists(*__filepath) && !file_isdir(*__filepath)) + return std::fopen(__filepath->c_str(), "r"); + +#ifdef Q_OS_MAC + // try in Framework path on Mac, if there is a path in front + // ### what about escaped slashes? + size_t slashPos = __input_filename.find('/'); + if (slashPos != std::string::npos) { + __filepath->assign(*it); + __filepath->append(__input_filename.substr(0, slashPos)); + __filepath->append(".framework/Headers/"); + __filepath->append(__input_filename.substr(slashPos + 1, std::string::npos)); + std::cerr << *__filepath << "\n"; + + if (file_exists(*__filepath) && !file_isdir(*__filepath)) + return fopen(__filepath->c_str(), "r"); + } +#endif // Q_OS_MAC + } + + return 0; +} + +template +_InputIterator pp::handle_directive(char const *__directive, std::size_t __size, + _InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ + __first = skip_blanks(__first, __last); + + PP_DIRECTIVE_TYPE d = find_directive(__directive, __size); + switch (d) { + case PP_DEFINE: + if (! skipping()) + return handle_define(__first, __last); + break; + + case PP_INCLUDE: + case PP_INCLUDE_NEXT: + if (! skipping()) + return handle_include(d == PP_INCLUDE_NEXT, __first, __last, __result); + break; + + case PP_UNDEF: + if (! skipping()) + return handle_undef(__first, __last); + break; + + case PP_ELIF: + return handle_elif(__first, __last); + + case PP_ELSE: + return handle_else(__first, __last); + + case PP_ENDIF: + return handle_endif(__first, __last); + + case PP_IF: + return handle_if(__first, __last); + + case PP_IFDEF: + return handle_ifdef(false, __first, __last); + + case PP_IFNDEF: + return handle_ifdef(true, __first, __last); + + default: + break; + } + + return __first; +} + +template +_InputIterator pp::handle_include(bool __skip_current_path, _InputIterator __first, _InputIterator __last, + _OutputIterator __result) +{ + if (pp_isalpha(*__first) || *__first == '_') { + pp_macro_expander expand_include(env); + std::string name; + name.reserve(255); + expand_include(__first, __last, std::back_inserter(name)); + std::string::iterator it = skip_blanks(name.begin(), name.end()); + assert(it != name.end() && (*it == '<' || *it == '"')); + handle_include(__skip_current_path, it, name.end(), __result); + return __first; + } + + assert(*__first == '<' || *__first == '"'); + int quote = (*__first == '"') ? '"' : '>'; + ++__first; + + _InputIterator end_name = __first; + for (; end_name != __last; ++end_name) { + assert(*end_name != '\n'); + + if (*end_name == quote) + break; + } + + std::string filename(__first, end_name); + +#ifdef PP_OS_WIN + std::replace(filename.begin(), filename.end(), '/', '\\'); +#endif + + std::string filepath; + FILE *fp = find_include_file(filename, &filepath, quote == '>' ? INCLUDE_GLOBAL : INCLUDE_LOCAL, __skip_current_path); + +#if defined (PP_HOOK_ON_FILE_INCLUDED) + PP_HOOK_ON_FILE_INCLUDED(env.current_file, fp ? filepath : filename, fp); +#endif + + if (fp != 0) { + std::string old_file = env.current_file; + env.current_file = filepath; + int __saved_lines = env.current_line; + + env.current_line = 1; + //output_line (env.current_file, 1, __result); + + file(fp, __result); + + // restore the file name and the line position + env.current_file = old_file; + env.current_line = __saved_lines; + + // sync the buffer + _PP_internal::output_line(env.current_file, env.current_line, __result); + } +#ifndef RPP_JAMBI +// else +// std::cerr << "*** WARNING " << filename << ": No such file or directory" << std::endl; +#endif + + return __first; +} + +template +void pp::operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ +#ifndef PP_NO_SMART_HEADER_PROTECTION + std::string __prot; + __prot.reserve(255); + pp_fast_string __tmp(__prot.c_str(), __prot.size()); + + if (find_header_protection(__first, __last, &__prot) + && env.resolve(&__tmp) != 0) { + // std::cerr << "** DEBUG found header protection:" << __prot << std::endl; + return; + } +#endif + + env.current_line = 1; + char __buffer[512]; + + while (true) { + __first = skip_blanks(__first, __last); + env.current_line += skip_blanks.lines; + + if (__first == __last) + break; + else if (*__first == '#') { + assert(*__first == '#'); + __first = skip_blanks(++__first, __last); + env.current_line += skip_blanks.lines; + + _InputIterator end_id = skip_identifier(__first, __last); + env.current_line += skip_identifier.lines; + std::size_t __size = end_id - __first; + + assert(__size < 512); + char *__cp = __buffer; + std::copy(__first, end_id, __cp); + __cp[__size] = '\0'; + + end_id = skip_blanks(end_id, __last); + __first = skip(end_id, __last); + + int was = env.current_line; + (void) handle_directive(__buffer, __size, end_id, __first, __result); + + if (env.current_line != was) { + env.current_line = was; + _PP_internal::output_line(env.current_file, env.current_line, __result); + } + } else if (*__first == '\n') { + // ### compress the line + *__result++ = *__first++; + ++env.current_line; + } else if (skipping()) + __first = skip(__first, __last); + else { + _PP_internal::output_line(env.current_file, env.current_line, __result); + __first = expand(__first, __last, __result); + env.current_line += expand.lines; + + if (expand.generated_lines) + _PP_internal::output_line(env.current_file, env.current_line, __result); + } + } +} + +inline pp::pp(pp_environment &__env): + env(__env), expand(env) +{ + iflevel = 0; + _M_skipping[iflevel] = 0; + _M_true_test[iflevel] = 0; +} + +inline std::back_insert_iterator > pp::include_paths_inserter() +{ + return std::back_inserter(include_paths); +} + +inline std::vector::iterator pp::include_paths_begin() +{ + return include_paths.begin(); +} + +inline std::vector::iterator pp::include_paths_end() +{ + return include_paths.end(); +} + +inline std::vector::const_iterator pp::include_paths_begin() const +{ + return include_paths.begin(); +} + +inline std::vector::const_iterator pp::include_paths_end() const +{ + return include_paths.end(); +} + +inline void pp::push_include_path(std::string const &__path) +{ + if (__path.empty() || __path [__path.size() - 1] != PATH_SEPARATOR) { + std::string __tmp(__path); + __tmp += PATH_SEPARATOR; + include_paths.push_back(__tmp); + } + + else + include_paths.push_back(__path); +} + +template +_InputIterator pp::handle_define(_InputIterator __first, _InputIterator __last) +{ + pp_macro macro; +#if defined (PP_WITH_MACRO_POSITION) + macro.file = pp_symbol::get(env.current_file); +#endif + std::string definition; + + __first = skip_blanks(__first, __last); + _InputIterator end_macro_name = skip_identifier(__first, __last); + pp_fast_string const *macro_name = pp_symbol::get(__first, end_macro_name); + __first = end_macro_name; + + if (__first != __last && *__first == '(') { + macro.function_like = true; + macro.formals.reserve(5); + + __first = skip_blanks(++__first, __last); // skip '(' + _InputIterator arg_end = skip_identifier(__first, __last); + if (__first != arg_end) + macro.formals.push_back(pp_symbol::get(__first, arg_end)); + + __first = skip_blanks(arg_end, __last); + + if (*__first == '.') { + macro.variadics = true; + while (*__first == '.') + ++__first; + } + + while (__first != __last && *__first == ',') { + __first = skip_blanks(++__first, __last); + + arg_end = skip_identifier(__first, __last); + if (__first != arg_end) + macro.formals.push_back(pp_symbol::get(__first, arg_end)); + + __first = skip_blanks(arg_end, __last); + + if (*__first == '.') { + macro.variadics = true; + while (*__first == '.') + ++__first; + } + } + + assert(*__first == ')'); + ++__first; + } + + __first = skip_blanks(__first, __last); + + while (__first != __last && *__first != '\n') { + if (*__first == '/') { + __first = skip_comment_or_divop(__first, __last); + env.current_line += skip_comment_or_divop.lines; + } + + if (*__first == '\\') { + _InputIterator __begin = __first; + __begin = skip_blanks(++__begin, __last); + + if (__begin != __last && *__begin == '\n') { + ++macro.lines; + __first = skip_blanks(++__begin, __last); + definition += ' '; + continue; + } + } + + definition += *__first++; + } + + macro.definition = pp_symbol::get(definition); + env.bind(macro_name, macro); + + return __first; +} + +template +_InputIterator pp::skip(_InputIterator __first, _InputIterator __last) +{ + pp_skip_string_literal skip_string_literal; + pp_skip_char_literal skip_char_literal; + + while (__first != __last && *__first != '\n') { + if (*__first == '/') { + __first = skip_comment_or_divop(__first, __last); + env.current_line += skip_comment_or_divop.lines; + } else if (*__first == '"') { + __first = skip_string_literal(__first, __last); + env.current_line += skip_string_literal.lines; + } else if (*__first == '\'') { + __first = skip_char_literal(__first, __last); + env.current_line += skip_char_literal.lines; + } else if (*__first == '\\') { + __first = skip_blanks(++__first, __last); + env.current_line += skip_blanks.lines; + + if (__first != __last && *__first == '\n') { + ++__first; + ++env.current_line; + } + } else + ++__first; + } + + return __first; +} + +inline bool pp::test_if_level() +{ + bool result = !_M_skipping[iflevel++]; + _M_skipping[iflevel] = _M_skipping[iflevel - 1]; + _M_true_test[iflevel] = false; + return result; +} + +inline int pp::skipping() const +{ + return _M_skipping[iflevel]; +} + +template +_InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, Value *result) +{ + bool expect_paren = false; + int token; + __first = next_token(__first, __last, &token); + + switch (token) { + case TOKEN_NUMBER: + result->set_long(token_value); + break; + + case TOKEN_UNUMBER: + result->set_ulong(token_uvalue); + break; + + case TOKEN_DEFINED: + __first = next_token(__first, __last, &token); + + if (token == '(') { + expect_paren = true; + __first = next_token(__first, __last, &token); + } + + if (token != TOKEN_IDENTIFIER) { + std::cerr << "** WARNING expected ``identifier'' found:" << char(token) << std::endl; + result->set_long(0); + break; + } + + result->set_long(env.resolve(token_text->c_str(), token_text->size()) != 0); + + next_token(__first, __last, &token); // skip '(' + + if (expect_paren) { + _InputIterator next = next_token(__first, __last, &token); + if (token != ')') + std::cerr << "** WARNING expected ``)''" << std::endl; + else + __first = next; + } + break; + + case TOKEN_IDENTIFIER: + result->set_long(0); + break; + + case '-': + __first = eval_primary(__first, __last, result); + result->set_long(- result->l); + return __first; + + case '+': + __first = eval_primary(__first, __last, result); + return __first; + + case '!': + __first = eval_primary(__first, __last, result); + result->set_long(result->is_zero()); + return __first; + + case '(': + __first = eval_constant_expression(__first, __last, result); + next_token(__first, __last, &token); + + if (token != ')') + std::cerr << "** WARNING expected ``)'' = " << token << std::endl; + else + __first = next_token(__first, __last, &token); + break; + + default: + result->set_long(0); + } + + return __first; +} + +template +_InputIterator pp::eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_primary(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '*' || token == '/' || token == '%') { + Value value; + __first = eval_primary(next, __last, &value); + + if (token == '*') + result->op_mult(value); + else if (token == '/') { + if (value.is_zero()) { + std::cerr << "** WARNING division by zero" << std::endl; + result->set_long(0); + } else + result->op_div(value); + } else { + if (value.is_zero()) { + std::cerr << "** WARNING division by zero" << std::endl; + result->set_long(0); + } else + result->op_mod(value); + } + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_additive(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_multiplicative(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '+' || token == '-') { + Value value; + __first = eval_multiplicative(next, __last, &value); + + if (token == '+') + result->op_add(value); + else + result->op_sub(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_shift(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_additive(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == TOKEN_LT_LT || token == TOKEN_GT_GT) { + Value value; + __first = eval_additive(next, __last, &value); + + if (token == TOKEN_LT_LT) + result->op_lhs(value); + else + result->op_rhs(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_relational(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_shift(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '<' + || token == '>' + || token == TOKEN_LT_EQ + || token == TOKEN_GT_EQ) { + Value value; + __first = eval_shift(next, __last, &value); + + switch (token) { + default: + assert(0); + break; + + case '<': + result->op_lt(value); + break; + + case '>': + result->op_gt(value); + break; + + case TOKEN_LT_EQ: + result->op_le(value); + break; + + case TOKEN_GT_EQ: + result->op_ge(value); + break; + } + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_equality(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_relational(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == TOKEN_EQ_EQ || token == TOKEN_NOT_EQ) { + Value value; + __first = eval_relational(next, __last, &value); + + if (token == TOKEN_EQ_EQ) + result->op_eq(value); + else + result->op_ne(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_and(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_equality(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '&') { + Value value; + __first = eval_equality(next, __last, &value); + result->op_bit_and(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_xor(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_and(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '^') { + Value value; + __first = eval_and(next, __last, &value); + result->op_bit_xor(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_or(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_xor(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '|') { + Value value; + __first = eval_xor(next, __last, &value); + result->op_bit_or(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_or(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == TOKEN_AND_AND) { + Value value; + __first = eval_or(next, __last, &value); + result->op_and(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_logical_and(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == TOKEN_OR_OR) { + Value value; + __first = eval_logical_and(next, __last, &value); + result->op_or(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template +_InputIterator pp::eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_logical_or(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + if (token == '?') { + Value left_value; + __first = eval_constant_expression(next, __last, &left_value); + __first = skip_blanks(__first, __last); + + __first = next_token(__first, __last, &token); + if (token == ':') { + Value right_value; + __first = eval_constant_expression(__first, __last, &right_value); + + *result = !result->is_zero() ? left_value : right_value; + } else { + std::cerr << "** WARNING expected ``:'' = " << int (token) << std::endl; + *result = left_value; + } + } + + return __first; +} + +template +_InputIterator pp::eval_expression(_InputIterator __first, _InputIterator __last, Value *result) +{ + return __first = eval_constant_expression(skip_blanks(__first, __last), __last, result); +} + +template +_InputIterator pp::handle_if(_InputIterator __first, _InputIterator __last) +{ + if (test_if_level()) { + pp_macro_expander expand_condition(env); + std::string condition; + condition.reserve(255); + expand_condition(skip_blanks(__first, __last), __last, std::back_inserter(condition)); + + Value result; + result.set_long(0); + eval_expression(condition.c_str(), condition.c_str() + condition.size(), &result); + + _M_true_test[iflevel] = !result.is_zero(); + _M_skipping[iflevel] = result.is_zero(); + } + + return __first; +} + +template +_InputIterator pp::handle_else(_InputIterator __first, _InputIterator /*__last*/) +{ + if (iflevel == 0 && !skipping()) { + std::cerr << "** WARNING #else without #if" << std::endl; + } else if (iflevel > 0 && _M_skipping[iflevel - 1]) { + _M_skipping[iflevel] = true; + } else { + _M_skipping[iflevel] = _M_true_test[iflevel]; + } + + return __first; +} + +template +_InputIterator pp::handle_elif(_InputIterator __first, _InputIterator __last) +{ + assert(iflevel > 0); + + if (iflevel == 0 && !skipping()) { + std::cerr << "** WARNING #else without #if" << std::endl; + } else if (!_M_true_test[iflevel] && !_M_skipping[iflevel - 1]) { + Value result; + __first = eval_expression(__first, __last, &result); + _M_true_test[iflevel] = !result.is_zero(); + _M_skipping[iflevel] = result.is_zero(); + } else { + _M_skipping[iflevel] = true; + } + + return __first; +} + +template +_InputIterator pp::handle_endif(_InputIterator __first, _InputIterator /*__last*/) +{ + if (iflevel == 0 && !skipping()) { + std::cerr << "** WARNING #endif without #if" << std::endl; + } else { + _M_skipping[iflevel] = 0; + _M_true_test[iflevel] = 0; + + --iflevel; + } + + return __first; +} + +template +_InputIterator pp::handle_ifdef(bool check_undefined, _InputIterator __first, _InputIterator __last) +{ + if (test_if_level()) { + _InputIterator end_macro_name = skip_identifier(__first, __last); + + std::size_t __size; +#if defined(__SUNPRO_CC) + std::distance(__first, end_macro_name, __size); +#else + __size = std::distance(__first, end_macro_name); +#endif + assert(__size < 256); + + char __buffer [256]; + std::copy(__first, end_macro_name, __buffer); + + bool value = env.resolve(__buffer, __size) != 0; + + __first = end_macro_name; + + if (check_undefined) + value = !value; + + _M_true_test[iflevel] = value; + _M_skipping[iflevel] = !value; + } + + return __first; +} + +template +_InputIterator pp::handle_undef(_InputIterator __first, _InputIterator __last) +{ + __first = skip_blanks(__first, __last); + _InputIterator end_macro_name = skip_identifier(__first, __last); + assert(end_macro_name != __first); + + std::size_t __size; +#if defined(__SUNPRO_CC) + std::distance(__first, end_macro_name, __size); +#else + __size = std::distance(__first, end_macro_name); +#endif + + assert(__size < 256); + + char __buffer [256]; + std::copy(__first, end_macro_name, __buffer); + + pp_fast_string const __tmp(__buffer, __size); + env.unbind(&__tmp); + + __first = end_macro_name; + + return __first; +} + +template +char pp::peek_char(_InputIterator __first, _InputIterator __last) +{ + if (__first == __last) + return 0; + + return *++__first; +} + +template +_InputIterator pp::next_token(_InputIterator __first, _InputIterator __last, int *kind) +{ + __first = skip_blanks(__first, __last); + + if (__first == __last) { + *kind = 0; + return __first; + } + + char ch = *__first; + char ch2 = peek_char(__first, __last); + + switch (ch) { + case '/': + if (ch2 == '/' || ch2 == '*') { + __first = skip_comment_or_divop(__first, __last); + return next_token(__first, __last, kind); + } + ++__first; + *kind = '/'; + break; + + case '<': + ++__first; + if (ch2 == '<') { + ++__first; + *kind = TOKEN_LT_LT; + } else if (ch2 == '=') { + ++__first; + *kind = TOKEN_LT_EQ; + } else + *kind = '<'; + + return __first; + + case '>': + ++__first; + if (ch2 == '>') { + ++__first; + *kind = TOKEN_GT_GT; + } else if (ch2 == '=') { + ++__first; + *kind = TOKEN_GT_EQ; + } else + *kind = '>'; + + return __first; + + case '!': + ++__first; + if (ch2 == '=') { + ++__first; + *kind = TOKEN_NOT_EQ; + } else + *kind = '!'; + + return __first; + + case '=': + ++__first; + if (ch2 == '=') { + ++__first; + *kind = TOKEN_EQ_EQ; + } else + *kind = '='; + + return __first; + + case '|': + ++__first; + if (ch2 == '|') { + ++__first; + *kind = TOKEN_OR_OR; + } else + *kind = '|'; + + return __first; + + case '&': + ++__first; + if (ch2 == '&') { + ++__first; + *kind = TOKEN_AND_AND; + } else + *kind = '&'; + + return __first; + + default: + if (pp_isalpha(ch) || ch == '_') { + _InputIterator end = skip_identifier(__first, __last); + _M_current_text.assign(__first, end); + + token_text = &_M_current_text; + __first = end; + + if (*token_text == "defined") + *kind = TOKEN_DEFINED; + else + *kind = TOKEN_IDENTIFIER; + } else if (pp_isdigit(ch)) { + _InputIterator end = skip_number(__first, __last); + std::string __str(__first, __last); + char ch = __str [__str.size() - 1]; + if (ch == 'u' || ch == 'U') { + token_uvalue = strtoul(__str.c_str(), 0, 0); + *kind = TOKEN_UNUMBER; + } else { + token_value = strtol(__str.c_str(), 0, 0); + *kind = TOKEN_NUMBER; + } + __first = end; + } else + *kind = *__first++; + } + + return __first; +} + +} // namespace rpp + +#endif // PP_ENGINE_BITS_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-engine.h b/parser/rpp/pp-engine.h new file mode 100644 index 000000000..79e74c1aa --- /dev/null +++ b/parser/rpp/pp-engine.h @@ -0,0 +1,274 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_ENGINE_H +#define PP_ENGINE_H + +namespace rpp +{ + +struct Value { + enum Kind { + Kind_Long, + Kind_ULong, + }; + + Kind kind; + + union { + long l; + unsigned long ul; + }; + + inline bool is_ulong() const { + return kind == Kind_ULong; + } + + inline void set_ulong(unsigned long v) { + ul = v; + kind = Kind_ULong; + } + + inline void set_long(long v) { + l = v; + kind = Kind_Long; + } + + inline bool is_zero() const { + return l == 0; + } + +#define PP_DEFINE_BIN_OP(name, op) \ + inline Value &name (const Value &other) \ + { \ + if (is_ulong () || other.is_ulong ()) \ + set_ulong (ul op other.ul); \ + else \ + set_long (l op other.l); \ + return *this; \ + } + + PP_DEFINE_BIN_OP(op_add, +) + PP_DEFINE_BIN_OP(op_sub, -) + PP_DEFINE_BIN_OP(op_mult, *) + PP_DEFINE_BIN_OP(op_div, /) + PP_DEFINE_BIN_OP(op_mod, %) + PP_DEFINE_BIN_OP(op_lhs, <<) + PP_DEFINE_BIN_OP(op_rhs, >>) + PP_DEFINE_BIN_OP(op_lt, <) + PP_DEFINE_BIN_OP(op_gt, >) + PP_DEFINE_BIN_OP(op_le, <=) + PP_DEFINE_BIN_OP(op_ge, >=) + PP_DEFINE_BIN_OP(op_eq, ==) + PP_DEFINE_BIN_OP(op_ne, !=) + PP_DEFINE_BIN_OP(op_bit_and, &) + PP_DEFINE_BIN_OP(op_bit_or, |) + PP_DEFINE_BIN_OP(op_bit_xor, ^) + PP_DEFINE_BIN_OP(op_and, &&) + PP_DEFINE_BIN_OP(op_or, ||) + +#undef PP_DEFINE_BIN_OP +}; + +class pp +{ + pp_environment &env; + pp_macro_expander expand; + pp_skip_identifier skip_identifier; + pp_skip_comment_or_divop skip_comment_or_divop; + pp_skip_blanks skip_blanks; + pp_skip_number skip_number; + std::vector include_paths; + std::string _M_current_text; + + enum { MAX_LEVEL = 512 }; + int _M_skipping[MAX_LEVEL]; + int _M_true_test[MAX_LEVEL]; + int iflevel; + + union { + long token_value; + unsigned long token_uvalue; + std::string *token_text; + }; + + enum INCLUDE_POLICY { + INCLUDE_GLOBAL, + INCLUDE_LOCAL + }; + + enum TOKEN_TYPE { + TOKEN_NUMBER = 1000, + TOKEN_UNUMBER, + TOKEN_IDENTIFIER, + TOKEN_DEFINED, + TOKEN_LT_LT, + TOKEN_LT_EQ, + TOKEN_GT_GT, + TOKEN_GT_EQ, + TOKEN_EQ_EQ, + TOKEN_NOT_EQ, + TOKEN_OR_OR, + TOKEN_AND_AND, + }; + + enum PP_DIRECTIVE_TYPE { + PP_UNKNOWN_DIRECTIVE, + PP_DEFINE, + PP_INCLUDE, + PP_INCLUDE_NEXT, + PP_ELIF, + PP_ELSE, + PP_ENDIF, + PP_IF, + PP_IFDEF, + PP_IFNDEF, + PP_UNDEF, + PP_PRAGMA, + PP_ERROR, + PP_WARNING + }; + +public: + pp(pp_environment &__env); + + inline std::back_insert_iterator > include_paths_inserter(); + + inline void push_include_path(std::string const &__path); + + inline std::vector::iterator include_paths_begin(); + inline std::vector::iterator include_paths_end(); + + inline std::vector::const_iterator include_paths_begin() const; + inline std::vector::const_iterator include_paths_end() const; + + template + inline _InputIterator eval_expression(_InputIterator __first, _InputIterator __last, Value *result); + + template + void file(std::string const &filename, _OutputIterator __result); + + template + void file(FILE *fp, _OutputIterator __result); + + template + void operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result); + +private: + inline bool file_isdir(std::string const &__filename) const; + inline bool file_exists(std::string const &__filename) const; + FILE *find_include_file(std::string const &__filename, std::string *__filepath, + INCLUDE_POLICY __include_policy, bool __skip_current_path = false) const; + + inline int skipping() const; + bool test_if_level(); + + inline std::string fix_file_path(std::string const &filename) const; + inline bool is_absolute(std::string const &filename) const; + + PP_DIRECTIVE_TYPE find_directive(char const *__directive, std::size_t __size) const; + + template + bool find_header_protection(_InputIterator __first, _InputIterator __last, std::string *__prot); + + template + _InputIterator skip(_InputIterator __first, _InputIterator __last); + + template + _InputIterator eval_primary(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_additive(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_shift(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_relational(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_equality(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_and(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_xor(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_or(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result); + + template + _InputIterator handle_directive(char const *__directive, std::size_t __size, + _InputIterator __first, _InputIterator __last, _OutputIterator __result); + + template + _InputIterator handle_include(bool skip_current_path, _InputIterator __first, _InputIterator __last, + _OutputIterator __result); + + template + _InputIterator handle_define(_InputIterator __first, _InputIterator __last); + + template + _InputIterator handle_if(_InputIterator __first, _InputIterator __last); + + template + _InputIterator handle_else(_InputIterator __first, _InputIterator __last); + + template + _InputIterator handle_elif(_InputIterator __first, _InputIterator __last); + + template + _InputIterator handle_endif(_InputIterator __first, _InputIterator __last); + + template + _InputIterator handle_ifdef(bool check_undefined, _InputIterator __first, _InputIterator __last); + + template + _InputIterator handle_undef(_InputIterator __first, _InputIterator __last); + + template + inline char peek_char(_InputIterator __first, _InputIterator __last); + + template + _InputIterator next_token(_InputIterator __first, _InputIterator __last, int *kind); +}; + +} // namespace rpp + +#endif // PP_ENGINE_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-environment.h b/parser/rpp/pp-environment.h new file mode 100644 index 000000000..6003c0820 --- /dev/null +++ b/parser/rpp/pp-environment.h @@ -0,0 +1,137 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_ENVIRONMENT_H +#define PP_ENVIRONMENT_H + +#include +#include + +namespace rpp +{ + +class pp_environment +{ +public: + typedef std::vector::const_iterator const_iterator; + +public: + pp_environment(): + current_line(0), + _M_hash_size(4093) { + _M_base = (pp_macro **) memset(new pp_macro* [_M_hash_size], 0, _M_hash_size * sizeof(pp_macro*)); + } + + ~pp_environment() { + for (std::size_t i = 0; i < _M_macros.size(); ++i) + delete _M_macros [i]; + + delete [] _M_base; + } + + const_iterator first_macro() const { + return _M_macros.begin(); + } + const_iterator last_macro() const { + return _M_macros.end(); + } + + inline void bind(pp_fast_string const *__name, pp_macro const &__macro) { + std::size_t h = hash_code(*__name) % _M_hash_size; + pp_macro *m = new pp_macro(__macro); + m->name = __name; + m->next = _M_base [h]; + m->hash_code = h; + _M_base [h] = m; + + _M_macros.push_back(m); + + if (_M_macros.size() == _M_hash_size) + rehash(); + } + + inline void unbind(pp_fast_string const *__name) { + if (pp_macro *m = resolve(__name)) + m->hidden = true; + } + + inline void unbind(char const *__s, std::size_t __size) { + pp_fast_string __tmp(__s, __size); + unbind(&__tmp); + } + + inline pp_macro *resolve(pp_fast_string const *__name) const { + std::size_t h = hash_code(*__name) % _M_hash_size; + pp_macro *it = _M_base [h]; + + while (it && it->name && it->hash_code == h && (*it->name != *__name || it->hidden)) + it = it->next; + + return it; + } + + inline pp_macro *resolve(char const *__data, std::size_t __size) const { + pp_fast_string const __tmp(__data, __size); + return resolve(&__tmp); + } + + std::string current_file; + int current_line; + +private: + inline std::size_t hash_code(pp_fast_string const &s) const { + std::size_t hash_value = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + hash_value = (hash_value << 5) - hash_value + s.at(i); + + return hash_value; + } + + void rehash() { + delete[] _M_base; + + _M_hash_size <<= 1; + + _M_base = (pp_macro **) memset(new pp_macro* [_M_hash_size], 0, _M_hash_size * sizeof(pp_macro*)); + for (std::size_t index = 0; index < _M_macros.size(); ++index) { + pp_macro *elt = _M_macros [index]; + std::size_t h = hash_code(*elt->name) % _M_hash_size; + elt->next = _M_base [h]; + elt->hash_code = h; + _M_base [h] = elt; + } + } + +private: + std::vector _M_macros; + pp_macro **_M_base; + std::size_t _M_hash_size; +}; + +} // namespace rpp + +#endif // PP_ENVIRONMENT_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-fwd.h b/parser/rpp/pp-fwd.h new file mode 100644 index 000000000..5b1c792f8 --- /dev/null +++ b/parser/rpp/pp-fwd.h @@ -0,0 +1,39 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_FWD_H +#define PP_FWD_H + +namespace rpp +{ + +template class pp_string; + +typedef pp_string pp_fast_string; + +} // namespace rpp + +#endif // PP_FWD_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-internal.h b/parser/rpp/pp-internal.h new file mode 100644 index 000000000..7e708101d --- /dev/null +++ b/parser/rpp/pp-internal.h @@ -0,0 +1,117 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_INTERNAL_H +#define PP_INTERNAL_H + +#include +#include +#include "pp.h" + +namespace rpp +{ + +namespace _PP_internal +{ + +inline void extract_file_path(const std::string &__filename, std::string *__filepath) +{ + std::size_t __index = __filename.rfind(PATH_SEPARATOR); + + if (__index == std::string::npos) + *__filepath = "/"; + + else + __filepath->assign(__filename, 0, __index + 1); +} + +template +void output_line(const std::string &__filename, int __line, _OutputIterator __result) +{ + std::string __msg; + + __msg += "# "; + + char __line_descr[16]; + pp_snprintf(__line_descr, 16, "%d", __line); + __msg += __line_descr; + + __msg += " \""; + + if (__filename.empty()) + __msg += ""; + else + __msg += __filename; + + __msg += "\"\n"; + std::copy(__msg.begin(), __msg.end(), __result); +} + +template +inline bool comment_p(_InputIterator __first, _InputIterator __last) /*const*/ +{ + if (__first == __last) + return false; + + if (*__first != '/') + return false; + + if (++__first == __last) + return false; + + return (*__first == '/' || *__first == '*'); +} + +struct _Compare_string: public std::binary_function { + inline bool operator()(pp_fast_string const *__lhs, pp_fast_string const *__rhs) const { + return *__lhs < *__rhs; + } +}; + +struct _Equal_to_string: public std::binary_function { + inline bool operator()(pp_fast_string const *__lhs, pp_fast_string const *__rhs) const { + return *__lhs == *__rhs; + } +}; + +struct _Hash_string: public std::unary_function { + inline std::size_t operator()(pp_fast_string const *__s) const { + char const *__ptr = __s->begin(); + std::size_t __size = __s->size(); + std::size_t __h = 0; + + for (std::size_t i = 0; i < __size; ++i) + __h = (__h << 5) - __h + __ptr [i]; + + return __h; + } +}; + +} // _PP_internal + +} // namespace rpp + +#endif // PP_INTERNAL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-iterator.h b/parser/rpp/pp-iterator.h new file mode 100644 index 000000000..fe846bd26 --- /dev/null +++ b/parser/rpp/pp-iterator.h @@ -0,0 +1,88 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_ITERATOR_H +#define PP_ITERATOR_H + +#include + +namespace rpp +{ + +class pp_null_output_iterator + : public std::iterator +{ +public: + pp_null_output_iterator() {} + + template + pp_null_output_iterator &operator=(_Tp const &) { + return *this; + } + + inline pp_null_output_iterator &operator *() { + return *this; + } + inline pp_null_output_iterator &operator ++ () { + return *this; + } + inline pp_null_output_iterator operator ++ (int) { + return *this; + } +}; + +template +class pp_output_iterator + : public std::iterator +{ + std::string &_M_result; + +public: + explicit pp_output_iterator(std::string &__result): + _M_result(__result) {} + + inline pp_output_iterator &operator=(typename _Container::const_reference __v) { + if (_M_result.capacity() == _M_result.size()) + _M_result.reserve(_M_result.capacity() << 2); + + _M_result.push_back(__v); + return *this; + } + + inline pp_output_iterator &operator *() { + return *this; + } + inline pp_output_iterator &operator ++ () { + return *this; + } + inline pp_output_iterator operator ++ (int) { + return *this; + } +}; + +} // namespace rpp + +#endif // PP_ITERATOR_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-macro-expander.h b/parser/rpp/pp-macro-expander.h new file mode 100644 index 000000000..fd875d980 --- /dev/null +++ b/parser/rpp/pp-macro-expander.h @@ -0,0 +1,351 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_MACRO_EXPANDER_H +#define PP_MACRO_EXPANDER_H + +namespace rpp +{ + +struct pp_frame { + pp_macro *expanding_macro; + std::vector *actuals; + + pp_frame(pp_macro *__expanding_macro, std::vector *__actuals): + expanding_macro(__expanding_macro), actuals(__actuals) {} +}; + +class pp_macro_expander +{ + pp_environment &env; + pp_frame *frame; + + pp_skip_number skip_number; + pp_skip_identifier skip_identifier; + pp_skip_string_literal skip_string_literal; + pp_skip_char_literal skip_char_literal; + pp_skip_argument skip_argument; + pp_skip_comment_or_divop skip_comment_or_divop; + pp_skip_blanks skip_blanks; + pp_skip_whitespaces skip_whitespaces; + + std::string const *resolve_formal(pp_fast_string const *__name) { + assert(__name != 0); + + if (! frame) + return 0; + + assert(frame->expanding_macro != 0); + + std::vector const formals = frame->expanding_macro->formals; + for (std::size_t index = 0; index < formals.size(); ++index) { + pp_fast_string const *formal = formals[index]; + + if (*formal != *__name) + continue; + + else if (frame->actuals && index < frame->actuals->size()) + return &(*frame->actuals)[index]; + + else + assert(0); // internal error? + } + + return 0; + } + +public: // attributes + int lines; + int generated_lines; + +public: + pp_macro_expander(pp_environment &__env, pp_frame *__frame = 0): + env(__env), frame(__frame), lines(0), generated_lines(0) {} + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { + generated_lines = 0; + __first = skip_blanks(__first, __last); + lines = skip_blanks.lines; + + while (__first != __last) { + if (*__first == '\n') { + *__result++ = *__first; + ++lines; + + __first = skip_blanks(++__first, __last); + lines += skip_blanks.lines; + + if (__first != __last && *__first == '#') + break; + } else if (*__first == '#') { + __first = skip_blanks(++__first, __last); + lines += skip_blanks.lines; + + _InputIterator end_id = skip_identifier(__first, __last); + + // ### rewrite: not safe + char name_buffer[512], *cp = name_buffer; + std::copy(__first, end_id, cp); + std::size_t name_size = end_id - __first; + name_buffer[name_size] = '\0'; + + pp_fast_string fast_name(name_buffer, name_size); + + if (std::string const *actual = resolve_formal(&fast_name)) { + *__result++ = '\"'; + + for (std::string::const_iterator it = skip_whitespaces(actual->begin(), actual->end()); + it != actual->end(); ++it) { + if (*it == '"') { + *__result++ = '\\'; + *__result++ = *it; + } + + else if (*it == '\n') { + *__result++ = '"'; + *__result++ = '\n'; + *__result++ = '"'; + } + + else + *__result++ = *it; + } + + *__result++ = '\"'; + __first = end_id; + } else + *__result++ = '#'; // ### warning message? + } else if (*__first == '\"') { + _InputIterator next_pos = skip_string_literal(__first, __last); + lines += skip_string_literal.lines; + std::copy(__first, next_pos, __result); + __first = next_pos; + } else if (*__first == '\'') { + _InputIterator next_pos = skip_char_literal(__first, __last); + lines += skip_char_literal.lines; + std::copy(__first, next_pos, __result); + __first = next_pos; + } else if (_PP_internal::comment_p(__first, __last)) { + __first = skip_comment_or_divop(__first, __last); + int n = skip_comment_or_divop.lines; + lines += n; + + while (n-- > 0) + *__result++ = '\n'; + } else if (pp_isspace(*__first)) { + for (; __first != __last; ++__first) { + if (*__first == '\n' || !pp_isspace(*__first)) + break; + } + + *__result = ' '; + } else if (pp_isdigit(*__first)) { + _InputIterator next_pos = skip_number(__first, __last); + lines += skip_number.lines; + std::copy(__first, next_pos, __result); + __first = next_pos; + } else if (pp_isalpha(*__first) || *__first == '_') { + _InputIterator name_begin = __first; + _InputIterator name_end = skip_identifier(__first, __last); + __first = name_end; // advance + + // search for the paste token + _InputIterator next = skip_blanks(__first, __last); + if (next != __last && *next == '#') { + ++next; + if (next != __last && *next == '#') + __first = skip_blanks(++next, __last); + } + + // ### rewrite: not safe + + std::ptrdiff_t name_size; +#if defined(__SUNPRO_CC) + std::distance(name_begin, name_end, name_size); +#else + name_size = std::distance(name_begin, name_end); +#endif + assert(name_size >= 0 && name_size < 512); + + char name_buffer[512], *cp = name_buffer; + std::size_t __size = name_end - name_begin; + std::copy(name_begin, name_end, cp); + name_buffer[__size] = '\0'; + + pp_fast_string fast_name(name_buffer, name_size); + + if (std::string const *actual = resolve_formal(&fast_name)) { + std::copy(actual->begin(), actual->end(), __result); + continue; + } + + static bool hide_next = false; // ### remove me + + pp_macro *macro = env.resolve(name_buffer, name_size); + if (! macro || macro->hidden || hide_next) { + hide_next = ! strcmp(name_buffer, "defined"); + + if (__size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_') { + if (! strcmp(name_buffer, "__LINE__")) { + char buf [16]; + char *end = buf + pp_snprintf(buf, 16, "%d", env.current_line + lines); + + std::copy(&buf [0], end, __result); + continue; + } + + else if (! strcmp(name_buffer, "__FILE__")) { + __result++ = '"'; + std::copy(env.current_file.begin(), env.current_file.end(), __result); // ### quote + __result++ = '"'; + continue; + } + } + + std::copy(name_begin, name_end, __result); + continue; + } + + if (! macro->function_like) { + pp_macro *m = 0; + + if (macro->definition) { + macro->hidden = true; + + std::string __tmp; + __tmp.reserve(256); + + pp_macro_expander expand_macro(env); + expand_macro(macro->definition->begin(), macro->definition->end(), std::back_inserter(__tmp)); + generated_lines += expand_macro.lines; + + if (! __tmp.empty()) { + std::string::iterator __begin_id = skip_whitespaces(__tmp.begin(), __tmp.end()); + std::string::iterator __end_id = skip_identifier(__begin_id, __tmp.end()); + + if (__end_id == __tmp.end()) { + std::string __id; + __id.assign(__begin_id, __end_id); + + std::size_t x; +#if defined(__SUNPRO_CC) + std::distance(__begin_id, __end_id, x); +#else + x = std::distance(__begin_id, __end_id); +#endif + m = env.resolve(__id.c_str(), x); + } + + if (! m) + std::copy(__tmp.begin(), __tmp.end(), __result); + } + + macro->hidden = false; + } + + if (! m) + continue; + + macro = m; + } + + // function like macro + _InputIterator arg_it = skip_whitespaces(__first, __last); + + if (arg_it == __last || *arg_it != '(') { + std::copy(name_begin, name_end, __result); + lines += skip_whitespaces.lines; + __first = arg_it; + continue; + } + + std::vector actuals; + actuals.reserve(5); + ++arg_it; // skip '(' + + pp_macro_expander expand_actual(env, frame); + + _InputIterator arg_end = skip_argument_variadics(actuals, macro, arg_it, __last); + if (arg_it != arg_end) { + std::string actual(arg_it, arg_end); + actuals.resize(actuals.size() + 1); + actuals.back().reserve(255); + expand_actual(actual.begin(), actual.end(), std::back_inserter(actuals.back())); + arg_it = arg_end; + } + + while (arg_it != __last && *arg_end == ',') { + ++arg_it; // skip ',' + + arg_end = skip_argument_variadics(actuals, macro, arg_it, __last); + std::string actual(arg_it, arg_end); + actuals.resize(actuals.size() + 1); + actuals.back().reserve(255); + expand_actual(actual.begin(), actual.end(), std::back_inserter(actuals.back())); + arg_it = arg_end; + } + + assert(arg_it != __last && *arg_it == ')'); + + ++arg_it; // skip ')' + __first = arg_it; + +#if 0 // ### enable me + assert((macro->variadics && macro->formals.size() >= actuals.size()) + || macro->formals.size() == actuals.size()); +#endif + + pp_frame frame(macro, &actuals); + pp_macro_expander expand_macro(env, &frame); + macro->hidden = true; + expand_macro(macro->definition->begin(), macro->definition->end(), __result); + macro->hidden = false; + generated_lines += expand_macro.lines; + } else + *__result++ = *__first++; + } + + return __first; + } + + template + _InputIterator skip_argument_variadics(std::vector const &__actuals, pp_macro *__macro, + _InputIterator __first, _InputIterator __last) { + _InputIterator arg_end = skip_argument(__first, __last); + + while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ',' + && (__actuals.size() + 1) == __macro->formals.size()) { + arg_end = skip_argument(++arg_end, __last); + } + + return arg_end; + } +}; + +} // namespace rpp + +#endif // PP_MACRO_EXPANDER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-macro.h b/parser/rpp/pp-macro.h new file mode 100644 index 000000000..e633834b1 --- /dev/null +++ b/parser/rpp/pp-macro.h @@ -0,0 +1,72 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_MACRO_H +#define PP_MACRO_H + +#include +#include "pp-fwd.h" + +namespace rpp +{ + +struct pp_macro { +#if defined (PP_WITH_MACRO_POSITION) + pp_fast_string const *file; +#endif + pp_fast_string const *name; + pp_fast_string const *definition; + std::vector formals; + + union { + int unsigned state; + + struct { + int unsigned hidden: 1; + int unsigned function_like: 1; + int unsigned variadics: 1; + }; + }; + + int lines; + pp_macro *next; + std::size_t hash_code; + + inline pp_macro(): +#if defined (PP_WITH_MACRO_POSITION) + file(0), +#endif + name(0), + definition(0), + state(0), + lines(0), + next(0), + hash_code(0) {} +}; + +} // namespace rpp + +#endif // PP_MACRO_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-main.cpp b/parser/rpp/pp-main.cpp new file mode 100644 index 000000000..4c37e754f --- /dev/null +++ b/parser/rpp/pp-main.cpp @@ -0,0 +1,295 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include "pp.h" + +using namespace rpp; + +#ifndef GCC_MACHINE +# define GCC_MACHINE "i386-redhat-linux" +#endif + +#ifndef GCC_VERSION +# define GCC_VERSION "4.1.1" +#endif + +void usage() +{ + std::cerr << "usage: rpp file.cpp" << std::endl; + ::exit(EXIT_FAILURE); +} + +void dump_macros(pp_environment &env, pp &, std::ostream &__out) +{ + for (pp_environment::const_iterator it = env.first_macro(); it != env.last_macro(); ++it) { + pp_macro const *m = *it; + + if (m->hidden) + continue; + + std::string id(m->name->begin(), m->name->end()); + __out << "#define " << id; + + if (m->function_like) { + __out << "("; + + for (std::size_t i = 0; i < m->formals.size(); ++i) { + if (i != 0) + __out << ", "; + + pp_fast_string const *f = m->formals [i]; + std::string name(f->begin(), f->end()); + __out << name; + } + + if (m->variadics) + __out << "..."; + + __out << ")"; + } + + __out << "\t"; + if (m->definition) { + std::string def(m->definition->begin(), m->definition->end()); + __out << def; + } + + __out << std::endl; + } +} +#if 0 +int main(int, char *argv []) +{ + char const *input_file = 0; + char const *output_file = 0; + char const *include_pch_file = 0; + bool opt_help = false; + bool opt_dump_macros = false; + bool opt_pch = false; + + pp_environment env; + pp preprocess(env); + + std::string result; + result.reserve(20 * 1024); // 20K + + pp_output_iterator out(result); + pp_null_output_iterator null_out; + + preprocess.push_include_path("/usr/include"); + preprocess.push_include_path("/usr/lib/gcc/" GCC_MACHINE "/" GCC_VERSION "/include"); + + preprocess.push_include_path("/usr/include/c++/" GCC_VERSION); + preprocess.push_include_path("/usr/include/c++/" GCC_VERSION "/" GCC_MACHINE); + + std::string extra_args; + + while (const char *arg = *++argv) { + if (arg [0] != '-') + input_file = arg; + + else if (! strcmp(arg, "-help")) + opt_help = true; + + else if (! strcmp(arg, "-dM")) + opt_dump_macros = true; + + else if (! strcmp(arg, "-pch")) + opt_pch = true; + + else if (! strcmp(arg, "-msse")) { + pp_macro __macro; + __macro.name = pp_symbol::get("__SSE__", 7); + env.bind(__macro.name, __macro); + + __macro.name = pp_symbol::get("__MMX__", 7); + env.bind(__macro.name, __macro); + } + + else if (! strcmp(arg, "-include")) { + if (argv [1]) + include_pch_file = *++argv; + } + + else if (! strncmp(arg, "-o", 2)) { + arg += 2; + + if (! arg [0] && argv [1]) + arg = *++argv; + + if (arg) + output_file = arg; + } + + else if (! strncmp(arg, "-conf", 8)) { + if (argv [1]) + preprocess.file(*++argv, null_out); + } + + else if (! strncmp(arg, "-I", 2)) { + arg += 2; + + if (! arg [0] && argv [1]) + arg = *++argv; + + if (arg) + preprocess.push_include_path(arg); + } + + else if (! strncmp(arg, "-U", 2)) { + arg += 2; + + if (! arg [0] && argv [1]) + arg = *++argv; + + if (arg) { + env.unbind(arg, strlen(arg)); + } + } + + else if (! strncmp(arg, "-D", 2)) { + arg += 2; + + if (! arg [0] && argv [1]) + arg = *++argv; + + if (arg) { + pp_macro __macro; + + char const *end = arg; + char const *eq = 0; + + for (; *end; ++end) { + if (*end == '=') + eq = end; + } + + if (eq != 0) { + __macro.name = pp_symbol::get(arg, eq - arg); + __macro.definition = pp_symbol::get(eq + 1, end - (eq + 1)); + } + + else { + __macro.name = pp_symbol::get(arg, end - arg); + __macro.definition = 0; + } + + env.bind(__macro.name, __macro); + } + } else { + extra_args += " "; + extra_args += arg; + } + } + + if (! input_file || opt_help) { + usage(); + return EXIT_FAILURE; + } + + std::string __ifile(input_file); + bool is_c_file = false; + if (__ifile.size() > 2 && __ifile [__ifile.size() - 1] == 'c' && __ifile [__ifile.size() - 2] == '.') { + is_c_file = true; + env.unbind("__cplusplus", 11); + + pp_macro __macro; + __macro.name = pp_symbol::get("__null"); + __macro.definition = pp_symbol::get("((void*) 0)"); + env.bind(__macro.name, __macro); + + // turn off the pch + include_pch_file = 0; + } else if (include_pch_file) { + std::string __pch(include_pch_file); + __pch += ".gch/c++.conf"; + + //std::cerr << "*** pch file " << __pch << std::endl; + preprocess.file(__pch, null_out); + } + + if (opt_dump_macros) { + preprocess.file(input_file, null_out); + dump_macros(env, preprocess, std::cout); + return EXIT_SUCCESS; + } + + preprocess.file(input_file, out); + + if (opt_pch) { + if (! output_file) { + std::cerr << "*** WARNING expected a file name" << std::endl; + return EXIT_FAILURE; + } + + std::string __conf_file(output_file); + __conf_file += ".conf"; + + std::ofstream __out; + __out.open(__conf_file.c_str()); + dump_macros(env, preprocess, __out); + __out.close(); + + std::string __pp_file(output_file); + __pp_file += ".i"; + + __out.open(__pp_file.c_str()); + __out.write(result.c_str(), result.size()); + __out.close(); + return EXIT_SUCCESS; + } + + std::ostream *__out = &std::cout; + std::ofstream __ofile; + + if (output_file) { + std::string __output_file_name(output_file); + __ofile.open(output_file); + __out = &__ofile; + } + + if (include_pch_file) { + std::string __pch(include_pch_file); + __pch += ".gch/c++.i"; + + std::ifstream __in(__pch.c_str()); + + char buffer [1024]; + while (__in.read(buffer, 1024)) + __out->write(buffer, 1024); + + __in.close(); + } + + __out->write(result.c_str(), result.size()); + + if (output_file) + __ofile.close(); + + return EXIT_SUCCESS; +} +#endif +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/parser/rpp/pp-qt-configuration b/parser/rpp/pp-qt-configuration new file mode 100644 index 000000000..206c3d643 --- /dev/null +++ b/parser/rpp/pp-qt-configuration @@ -0,0 +1,24 @@ +#define __cplusplus 1 + +#define __STDC__ + +// Qt +#define QOBJECTDEFS_H + +// not yet supported +#define Q_SLOTS slots +#define Q_SIGNALS signals +#define Q_FLAGS(a) +#define Q_PRIVATE_SLOT(a, b) +#define Q_DECLARE_INTERFACE(a,b) +#define Q_INTERFACES(a) +#define Q_GADGET +#define Q_OVERRIDE(a) +#define Q_OS_OS2 +#define Q_NO_USING_KEYWORD +#define QT_NO_QOBJECT_CHECK +#define QT_NO_MEMBER_TEMPLATES +// There are symbols in Qt that exist in Debug but +// not in release +#define QT_NO_DEBUG + diff --git a/parser/rpp/pp-scanner.h b/parser/rpp/pp-scanner.h new file mode 100644 index 000000000..e97b15843 --- /dev/null +++ b/parser/rpp/pp-scanner.h @@ -0,0 +1,313 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_SCANNER_H +#define PP_SCANNER_H + +#include "pp-cctype.h" +#include + +namespace rpp +{ + +struct pp_skip_blanks { + int lines; + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + if (*__first == '\\') { + _InputIterator __begin = __first; + ++__begin; + + if (__begin != __last && *__begin == '\n') + ++__first; + else + break; + } else if (*__first == '\n' || !pp_isspace(*__first)) + break; + } + + return __first; + } +}; + +struct pp_skip_whitespaces { + int lines; + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + if (! pp_isspace(*__first)) + break; + } + + return __first; + } +}; + +struct pp_skip_comment_or_divop { + int lines; + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + enum { + MAYBE_BEGIN, + BEGIN, + MAYBE_END, + END, + IN_COMMENT, + IN_CXX_COMMENT + } state(MAYBE_BEGIN); + + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + switch (state) { + default: + assert(0); + break; + + case MAYBE_BEGIN: + if (*__first != '/') + return __first; + + state = BEGIN; + break; + + case BEGIN: + if (*__first == '*') + state = IN_COMMENT; + else if (*__first == '/') + state = IN_CXX_COMMENT; + else + return __first; + break; + + case IN_COMMENT: + if (*__first == '*') + state = MAYBE_END; + break; + + case IN_CXX_COMMENT: + if (*__first == '\n') + return __first; + break; + + case MAYBE_END: + if (*__first == '/') + state = END; + else if (*__first != '*') + state = IN_COMMENT; + break; + + case END: + return __first; + } + } + + return __first; + } +}; + +struct pp_skip_identifier { + int lines; + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + if (! pp_isalnum(*__first) && *__first != '_') + break; + } + + return __first; + } +}; + +struct pp_skip_number { + int lines; + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + if (! pp_isalnum(*__first) && *__first != '.') + break; + } + + return __first; + } +}; + +struct pp_skip_string_literal { + int lines; + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + enum { + BEGIN, + IN_STRING, + QUOTE, + END + } state(BEGIN); + + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + switch (state) { + default: + assert(0); + break; + + case BEGIN: + if (*__first != '\"') + return __first; + state = IN_STRING; + break; + + case IN_STRING: + assert(*__first != '\n'); + + if (*__first == '\"') + state = END; + else if (*__first == '\\') + state = QUOTE; + break; + + case QUOTE: + state = IN_STRING; + break; + + case END: + return __first; + } + } + + return __first; + } +}; + +struct pp_skip_char_literal { + int lines; + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + enum { + BEGIN, + IN_STRING, + QUOTE, + END + } state(BEGIN); + + lines = 0; + + for (; state != END && __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + switch (state) { + default: + assert(0); + break; + + case BEGIN: + if (*__first != '\'') + return __first; + state = IN_STRING; + break; + + case IN_STRING: + assert(*__first != '\n'); + + if (*__first == '\'') + state = END; + else if (*__first == '\\') + state = QUOTE; + break; + + case QUOTE: + state = IN_STRING; + break; + } + } + + return __first; + } +}; + +struct pp_skip_argument { + pp_skip_identifier skip_number; + pp_skip_identifier skip_identifier; + pp_skip_string_literal skip_string_literal; + pp_skip_char_literal skip_char_literal; + pp_skip_comment_or_divop skip_comment_or_divop; + int lines; + + template + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + int depth = 0; + lines = 0; + + while (__first != __last) { + if (!depth && (*__first == ')' || *__first == ',')) + break; + else if (*__first == '(') + ++depth, ++__first; + else if (*__first == ')') + --depth, ++__first; + else if (*__first == '\"') { + __first = skip_string_literal(__first, __last); + lines += skip_string_literal.lines; + } else if (*__first == '\'') { + __first = skip_char_literal(__first, __last); + lines += skip_char_literal.lines; + } else if (*__first == '/') { + __first = skip_comment_or_divop(__first, __last); + lines += skip_comment_or_divop.lines; + } else if (pp_isalpha(*__first) || *__first == '_') { + __first = skip_identifier(__first, __last); + lines += skip_identifier.lines; + } else if (pp_isdigit(*__first)) { + __first = skip_number(__first, __last); + lines += skip_number.lines; + } else if (*__first == '\n') { + ++__first; + ++lines; + } else + ++__first; + } + + return __first; + } +}; + +} // namespace rpp + +#endif // PP_SCANNER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-string.h b/parser/rpp/pp-string.h new file mode 100644 index 000000000..31bca4f7b --- /dev/null +++ b/parser/rpp/pp-string.h @@ -0,0 +1,107 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_STRING_H +#define PP_STRING_H + +namespace rpp +{ + +template +class pp_string +{ + typedef std::char_traits<_CharT> traits_type; + typedef std::size_t size_type; + + _CharT const *_M_begin; + std::size_t _M_size; + +public: + inline pp_string(): + _M_begin(0), _M_size(0) {} + + explicit pp_string(std::string const &__s): + _M_begin(__s.c_str()), _M_size(__s.size()) {} + + inline pp_string(_CharT const *__begin, std::size_t __size): + _M_begin(__begin), _M_size(__size) {} + + inline _CharT const *begin() const { + return _M_begin; + } + inline _CharT const *end() const { + return _M_begin + _M_size; + } + + inline _CharT at(std::size_t index) const { + return _M_begin [index]; + } + + inline std::size_t size() const { + return _M_size; + } + + inline int compare(pp_string const &__other) const { + size_type const __size = this->size(); + size_type const __osize = __other.size(); + size_type const __len = std::min(__size, __osize); + + int __r = traits_type::compare(_M_begin, __other._M_begin, __len); + if (!__r) + __r = (int)(__size - __osize); + + return __r; + } + + inline bool operator == (pp_string const &__other) const { + return compare(__other) == 0; + } + + inline bool operator != (pp_string const &__other) const { + return compare(__other) != 0; + } + + inline bool operator < (pp_string const &__other) const { + return compare(__other) < 0; + } + + inline bool operator == (char const *s) const { + std::size_t n = strlen(s); + + if (n != _M_size) + return false; + + return ! strncmp(_M_begin, s, n); + } + + inline bool operator != (char const *s) const { + return ! operator == (s); + } +}; + +} // namespace rpp + +#endif // PP_STRING_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp-symbol.h b/parser/rpp/pp-symbol.h new file mode 100644 index 000000000..eef668379 --- /dev/null +++ b/parser/rpp/pp-symbol.h @@ -0,0 +1,87 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_SYMBOL_H +#define PP_SYMBOL_H + +#include +#include +#include "pp-fwd.h" +#include "parser/rxx_allocator.h" + +namespace rpp +{ + +class pp_symbol +{ + static rxx_allocator &allocator_instance() { + static rxx_allocator__allocator; + return __allocator; + } + +public: + static int &N() { + static int __N; + return __N; + } + + static pp_fast_string const *get(char const *__data, std::size_t __size) { + ++N(); + char *data = allocator_instance().allocate(__size + 1); + memcpy(data, __data, __size); + data[__size] = '\0'; + + char *where = allocator_instance().allocate(sizeof(pp_fast_string)); + return new(where) pp_fast_string(data, __size); + } + + template + static pp_fast_string const *get(_InputIterator __first, _InputIterator __last) { + ++N(); + std::ptrdiff_t __size; +#if defined(__SUNPRO_CC) + std::distance(__first, __last, __size); +#else + __size = std::distance(__first, __last); +#endif + assert(__size >= 0 && __size < 512); + + char *data = allocator_instance().allocate(__size + 1); + std::copy(__first, __last, data); + data[__size] = '\0'; + + char *where = allocator_instance().allocate(sizeof(pp_fast_string)); + return new(where) pp_fast_string(data, __size); + } + + static pp_fast_string const *get(std::string const &__s) { + return get(__s.c_str(), __s.size()); + } +}; + +} // namespace rpp + +#endif // PP_SYMBOL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/pp.h b/parser/rpp/pp.h new file mode 100644 index 000000000..3ff38c0d1 --- /dev/null +++ b/parser/rpp/pp.h @@ -0,0 +1,91 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PP_H +#define PP_H + +#if defined(_WIN64) || defined(WIN64) || defined(__WIN64__) \ + || defined(_WIN32) || defined(WIN32) || defined(__WIN32__) +# define PP_OS_WIN +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_MMAP +# include +#endif + +#include +#include + +#if (_MSC_VER >= 1400) +# define FILENO _fileno +#else +# define FILENO fileno +#endif + +#if defined (PP_OS_WIN) +# define PATH_SEPARATOR '\\' +#else +# define PATH_SEPARATOR '/' +#endif + +#if defined (RPP_JAMBI) +# include "parser/rxx_allocator.h" +#else +# include "parser/rpp-allocator.h" +#endif + +#if defined (_MSC_VER) +# define pp_snprintf _snprintf +#else +# define pp_snprintf snprintf +#endif + +#include "pp-fwd.h" +#include "pp-cctype.h" +#include "pp-string.h" +#include "pp-symbol.h" +#include "pp-internal.h" +#include "pp-iterator.h" +#include "pp-macro.h" +#include "pp-environment.h" +#include "pp-scanner.h" +#include "pp-macro-expander.h" +#include "pp-engine.h" +#include "pp-engine-bits.h" + +#endif // PP_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/rpp/preprocessor.cpp b/parser/rpp/preprocessor.cpp new file mode 100644 index 000000000..be6a85186 --- /dev/null +++ b/parser/rpp/preprocessor.cpp @@ -0,0 +1,158 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Harald Fernengel + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "preprocessor.h" + +#include + +// register callback for include hooks +static void includeFileHook(const std::string &, const std::string &, FILE *); + +#define PP_HOOK_ON_FILE_INCLUDED(A, B, C) includeFileHook(A, B, C) +#include "pp.h" + +using namespace rpp; + +#include + +class PreprocessorPrivate +{ +public: + QByteArray result; + pp_environment env; + QStringList includePaths; + + void initPP(pp &proc) { + foreach(QString path, includePaths) + proc.push_include_path(path.toStdString()); + } +}; + +QHash includedFiles; + +void includeFileHook(const std::string &fileName, const std::string &filePath, FILE *) +{ + includedFiles[QString::fromStdString(fileName)].append(QString::fromStdString(filePath)); +} + +Preprocessor::Preprocessor() +{ + d = new PreprocessorPrivate; + includedFiles.clear(); +} + +Preprocessor::~Preprocessor() +{ + delete d; +} + +void Preprocessor::processFile(const QString &fileName) +{ + pp proc(d->env); + d->initPP(proc); + + d->result.reserve(d->result.size() + 20 * 1024); + + d->result += "# 1 \"" + fileName.toLatin1() + "\"\n"; // ### REMOVE ME + proc.file(fileName.toLocal8Bit().constData(), std::back_inserter(d->result)); +} + +void Preprocessor::processString(const QByteArray &str) +{ + pp proc(d->env); + d->initPP(proc); + + proc(str.begin(), str.end(), std::back_inserter(d->result)); +} + +QByteArray Preprocessor::result() const +{ + return d->result; +} + +void Preprocessor::addIncludePaths(const QStringList &includePaths) +{ + d->includePaths += includePaths; +} + +QStringList Preprocessor::macroNames() const +{ + QStringList macros; + + pp_environment::const_iterator it = d->env.first_macro(); + while (it != d->env.last_macro()) { + const pp_macro *m = *it; + macros += QString::fromLatin1(m->name->begin(), m->name->size()); + ++it; + } + + return macros; +} + +QList Preprocessor::macros() const +{ + QList items; + + pp_environment::const_iterator it = d->env.first_macro(); + while (it != d->env.last_macro()) { + const pp_macro *m = *it; + MacroItem item; + item.name = QString::fromLatin1(m->name->begin(), m->name->size()); + item.definition = QString::fromLatin1(m->definition->begin(), + m->definition->size()); + for (size_t i = 0; i < m->formals.size(); ++i) { + item.parameters += QString::fromLatin1(m->formals[i]->begin(), + m->formals[i]->size()); + } + item.isFunctionLike = m->function_like; + +#ifdef PP_WITH_MACRO_POSITION + item.fileName = QString::fromLatin1(m->file->begin(), m->file->size()); +#endif + items += item; + + ++it; + } + + return items; +} + +/* +int main() +{ + Preprocessor pp; + + QStringList paths; + paths << "/usr/include"; + pp.addIncludePaths(paths); + + pp.processFile("pp-configuration"); + pp.processFile("/usr/include/stdio.h"); + + qDebug() << pp.result(); + + return 0; +} +*/ + diff --git a/parser/rpp/preprocessor.h b/parser/rpp/preprocessor.h new file mode 100644 index 000000000..c363ea7c8 --- /dev/null +++ b/parser/rpp/preprocessor.h @@ -0,0 +1,66 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright 2005 Harald Fernengel + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef PREPROCESSOR_H +#define PREPROCESSOR_H + +#include +#include +#include + +class QByteArray; +class PreprocessorPrivate; + +class Preprocessor +{ +public: + Preprocessor(); + ~Preprocessor(); + + void processFile(const QString &fileName); + void processString(const QByteArray &str); + + void addIncludePaths(const QStringList &includePaths); + + QByteArray result() const; + + QStringList macroNames() const; + + struct MacroItem { + QString name; + QStringList parameters; + QString definition; + bool isFunctionLike; +#ifdef PP_WITH_MACRO_POSITION + QString fileName; +#endif + }; + QList macros() const; + +private: + Q_DISABLE_COPY(Preprocessor) + PreprocessorPrivate *d; +}; + +#endif diff --git a/parser/rxx_allocator.h b/parser/rxx_allocator.h new file mode 100644 index 000000000..e4a387554 --- /dev/null +++ b/parser/rxx_allocator.h @@ -0,0 +1,130 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef RXX_ALLOCATOR_H +#define RXX_ALLOCATOR_H + +#include +#include +#include +#include + +template class rxx_allocator +{ +public: + typedef _Tp value_type; + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static const size_type max_block_count = size_type(-1); + static const size_type _S_block_size = 1 << 16; // 64K + + rxx_allocator() + { + _M_block_index = max_block_count; + _M_current_index = 0; + _M_storage = 0; + _M_current_block = 0; + } + + ~rxx_allocator() + { + for (size_type index = 0; index < _M_block_index + 1; ++index) + delete[] _M_storage[index]; + + ::free(_M_storage); + } + + pointer address(reference __val) { return &__val; } + const_pointer address(const_reference __val) const { return &__val; } + + pointer allocate(size_type __n, const void* = 0) + { + const size_type bytes = __n * sizeof(_Tp); + + if (_M_current_block == 0 + || _S_block_size < _M_current_index + bytes) { + ++_M_block_index; + + _M_storage = reinterpret_cast + (::realloc(_M_storage, sizeof(char*) * (1 + _M_block_index))); + + _M_current_block = _M_storage[_M_block_index] = reinterpret_cast + (new char[_S_block_size]); + +#if defined(RXX_ALLOCATOR_INIT_0) // ### make it a policy + ::memset(_M_current_block, 0, _S_block_size); +#endif + _M_current_index = 0; + } + + pointer p = reinterpret_cast + (_M_current_block + _M_current_index); + + _M_current_index += bytes; + + return p; + } + + void deallocate(pointer __p, size_type __n) {} + + size_type max_size() const + { + return size_type(-1) / sizeof(_Tp); + } + + void contruct(pointer __p, const_reference __val) + { + new(__p) _Tp(__val); + } + void destruct(pointer __p) + { + __p->~_Tp(); + } + +private: + template + struct rebind + { + typedef rxx_allocator<_Tp1> other; + }; + + template rxx_allocator(const rxx_allocator<_Tp1> &__o) {} + +private: + size_type _M_block_index; + size_type _M_current_index; + char *_M_current_block; + char **_M_storage; +}; + +#endif // RXX_ALLOCATOR_H + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/parser/smallobject.cpp b/parser/smallobject.cpp new file mode 100644 index 000000000..e96d417c6 --- /dev/null +++ b/parser/smallobject.cpp @@ -0,0 +1,28 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "smallobject.h" + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/smallobject.h b/parser/smallobject.h new file mode 100644 index 000000000..52cdc232f --- /dev/null +++ b/parser/smallobject.h @@ -0,0 +1,47 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef SMALLOBJECT_H +#define SMALLOBJECT_H + +#include "rxx_allocator.h" +#include + +class pool +{ + rxx_allocator __alloc; + +public: + inline void *allocate(std::size_t __size); +}; + +inline void *pool::allocate(std::size_t __size) +{ + return __alloc.allocate(__size); +} + +#endif + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/symbol.h b/parser/symbol.h new file mode 100644 index 000000000..8e393cddb --- /dev/null +++ b/parser/symbol.h @@ -0,0 +1,122 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef SYMBOL_H +#define SYMBOL_H + +#include +#include + +#include +#include + +struct NameSymbol +{ + const char *data; + std::size_t count; + + inline QString as_string() const + { + return QString::fromUtf8(data, (int) count); + } + + inline bool operator == (const NameSymbol &other) const + { + return count == other.count + && !std::strncmp(data, other.data, count); + } + +protected: + inline NameSymbol() {} + inline NameSymbol(const char *d, std::size_t c) + : data(d), count(c) {} + +private: + void operator = (const NameSymbol &); + + friend class NameTable; +}; + +inline uint qHash(const NameSymbol &r) +{ + uint hash_value = 0; + + for (std::size_t i = 0; i < r.count; ++i) + hash_value = (hash_value << 5) - hash_value + r.data[i]; + + return hash_value; +} + +inline uint qHash(const QPair &r) +{ + uint hash_value = 0; + + for (std::size_t i = 0; i < r.second; ++i) + hash_value = (hash_value << 5) - hash_value + r.first[i]; + + return hash_value; +} + +class NameTable +{ +public: + typedef QPair KeyType; + typedef QHash ContainerType; + +public: + NameTable() {} + + ~NameTable() + { + qDeleteAll(_M_storage); + } + + inline const NameSymbol *findOrInsert(const char *str, std::size_t len) + { + KeyType key(str, len); + + NameSymbol *name = _M_storage.value(key); + if (!name) { + name = new NameSymbol(str, len); + _M_storage.insert(key, name); + } + + return name; + } + + inline std::size_t count() const { return _M_storage.size(); } + +private: + ContainerType _M_storage; + +private: + NameTable(const NameTable &other); + void operator=(const NameTable &other); +}; + +#endif // SYMBOL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/parser/tokens.cpp b/parser/tokens.cpp new file mode 100644 index 000000000..2e054d894 --- /dev/null +++ b/parser/tokens.cpp @@ -0,0 +1,249 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include + +#include "tokens.h" + +static char const * const _S_token_names[] = { + "K_DCOP", + "Q_OBJECT", + "Q_PROPERTY", + "__attribute__", + "__typeof", + "and", + "and_eq", + "arrow", + "asm", + "assign", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char_literal", + "class", + "comment", + "compl", + "concat", + "const", + "const_cast", + "continue", + "decr", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "ellipsis", + "else", + "emit", + "enum", + "eq", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "geq", + "goto", + "identifier", + "if", + "incr", + "inline", + "int", + "k_dcop", + "k_dcop_signals", + "leq", + "long", + "mutable", + "namespace", + "new", + "not", + "not_eq", + "number_literal", + "operator", + "or", + "or_eq", + "preproc", + "private", + "protected", + "ptrmem", + "public", + "register", + "reinterpret_cast", + "return", + "scope", + "shift", + "short", + "signals", + "signed", + "sizeof", + "slots", + "static", + "static_cast", + "string_literal", + "struct", + "switch", + "template", + "this", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "whitespaces", + "xor", + "xor_eq", + "Q_ENUMS" +}; + +static char _S_printable[][2] = { + { char(32), '\0' }, + { char(33), '\0' }, + { char(34), '\0' }, + { char(35), '\0' }, + { char(36), '\0' }, + { char(37), '\0' }, + { char(38), '\0' }, + { char(39), '\0' }, + { char(40), '\0' }, + { char(41), '\0' }, + { char(42), '\0' }, + { char(43), '\0' }, + { char(44), '\0' }, + { char(45), '\0' }, + { char(46), '\0' }, + { char(47), '\0' }, + { char(48), '\0' }, + { char(49), '\0' }, + { char(50), '\0' }, + { char(51), '\0' }, + { char(52), '\0' }, + { char(53), '\0' }, + { char(54), '\0' }, + { char(55), '\0' }, + { char(56), '\0' }, + { char(57), '\0' }, + { char(58), '\0' }, + { char(59), '\0' }, + { char(60), '\0' }, + { char(61), '\0' }, + { char(62), '\0' }, + { char(63), '\0' }, + { char(64), '\0' }, + { char(65), '\0' }, + { char(66), '\0' }, + { char(67), '\0' }, + { char(68), '\0' }, + { char(69), '\0' }, + { char(70), '\0' }, + { char(71), '\0' }, + { char(72), '\0' }, + { char(73), '\0' }, + { char(74), '\0' }, + { char(75), '\0' }, + { char(76), '\0' }, + { char(77), '\0' }, + { char(78), '\0' }, + { char(79), '\0' }, + { char(80), '\0' }, + { char(81), '\0' }, + { char(82), '\0' }, + { char(83), '\0' }, + { char(84), '\0' }, + { char(85), '\0' }, + { char(86), '\0' }, + { char(87), '\0' }, + { char(88), '\0' }, + { char(89), '\0' }, + { char(90), '\0' }, + { char(91), '\0' }, + { char(92), '\0' }, + { char(93), '\0' }, + { char(94), '\0' }, + { char(95), '\0' }, + { char(96), '\0' }, + { char(97), '\0' }, + { char(98), '\0' }, + { char(99), '\0' }, + { char(100), '\0' }, + { char(101), '\0' }, + { char(102), '\0' }, + { char(103), '\0' }, + { char(104), '\0' }, + { char(105), '\0' }, + { char(106), '\0' }, + { char(107), '\0' }, + { char(108), '\0' }, + { char(109), '\0' }, + { char(110), '\0' }, + { char(111), '\0' }, + { char(112), '\0' }, + { char(113), '\0' }, + { char(114), '\0' }, + { char(115), '\0' }, + { char(116), '\0' }, + { char(117), '\0' }, + { char(118), '\0' }, + { char(119), '\0' }, + { char(120), '\0' }, + { char(121), '\0' }, + { char(122), '\0' }, + { char(123), '\0' }, + { char(124), '\0' }, + { char(125), '\0' }, + { char(126), '\0' }, + { char(127), '\0' }, +}; + +char const *token_name(int token) +{ + if (token == 0) + return "eof"; + else if (token >= 32 && token <= 127) + return _S_printable[token - 32]; + else if (token >= 1000) + return _S_token_names[token - 1000]; + + Q_ASSERT(0); + return 0; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/tokens.h b/parser/tokens.h new file mode 100644 index 000000000..257ff0992 --- /dev/null +++ b/parser/tokens.h @@ -0,0 +1,145 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef TOKENS_H +#define TOKENS_H + +enum TOKEN_KIND { + Token_EOF = 0, + + Token_K_DCOP = 1000, + Token_Q_OBJECT, + Token_Q_PROPERTY, + Token___attribute__, + Token___typeof, + Token_and, + Token_and_eq, + Token_arrow, + Token_asm, + Token_assign, + Token_auto, + Token_bitand, + Token_bitor, + Token_bool, + Token_break, + Token_case, + Token_catch, + Token_char, + Token_char_literal, + Token_class, + Token_comment, + Token_compl, + Token_concat, + Token_const, + Token_const_cast, + Token_continue, + Token_decr, + Token_default, + Token_delete, + Token_do, + Token_double, + Token_dynamic_cast, + Token_ellipsis, + Token_else, + Token_emit, + Token_enum, + Token_eq, + Token_explicit, + Token_export, + Token_extern, + Token_false, + Token_float, + Token_for, + Token_friend, + Token_geq, + Token_goto, + Token_identifier, + Token_if, + Token_incr, + Token_inline, + Token_int, + Token_k_dcop, + Token_k_dcop_signals, + Token_leq, + Token_long, + Token_mutable, + Token_namespace, + Token_new, + Token_not, + Token_not_eq, + Token_number_literal, + Token_operator, + Token_or, + Token_or_eq, + Token_preproc, + Token_private, + Token_protected, + Token_ptrmem, + Token_public, + Token_register, + Token_reinterpret_cast, + Token_return, + Token_scope, + Token_shift, + Token_short, + Token_signals, + Token_signed, + Token_sizeof, + Token_slots, + Token_static, + Token_static_cast, + Token_string_literal, + Token_struct, + Token_switch, + Token_template, + Token_this, + Token_throw, + Token_true, + Token_try, + Token_typedef, + Token_typeid, + Token_typename, + Token_union, + Token_unsigned, + Token_using, + Token_virtual, + Token_void, + Token_volatile, + Token_wchar_t, + Token_while, + Token_whitespaces, + Token_xor, + Token_xor_eq, + Token_Q_ENUMS, + Token_Q_INVOKABLE, + + TOKEN_KIND_COUNT +}; + +char const *token_name(int token); + +#endif + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/type_compiler.cpp b/parser/type_compiler.cpp new file mode 100644 index 000000000..4bcdb277a --- /dev/null +++ b/parser/type_compiler.cpp @@ -0,0 +1,129 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + + +#include "type_compiler.h" +#include "name_compiler.h" +#include "lexer.h" +#include "symbol.h" +#include "tokens.h" +#include "binder.h" + +#include + +TypeCompiler::TypeCompiler(Binder *binder) + : _M_binder(binder), _M_token_stream(binder->tokenStream()) +{ +} + +void TypeCompiler::run(TypeSpecifierAST *node) +{ + _M_type.clear(); + _M_cv.clear(); + + visit(node); + + if (node && node->cv) { + const ListNode *it = node->cv->toFront(); + const ListNode *end = it; + do { + int kind = _M_token_stream->kind(it->element); + if (!_M_cv.contains(kind)) + _M_cv.append(kind); + + it = it->next; + } while (it != end); + } +} + +void TypeCompiler::visitClassSpecifier(ClassSpecifierAST *node) +{ + visit(node->name); +} + +void TypeCompiler::visitEnumSpecifier(EnumSpecifierAST *node) +{ + visit(node->name); +} + +void TypeCompiler::visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node) +{ + visit(node->name); +} + +void TypeCompiler::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node) +{ + if (const ListNode *it = node->integrals) { + it = it->toFront(); + const ListNode *end = it; + QString current_item; + do { + std::size_t token = it->element; + current_item += token_name(_M_token_stream->kind(token)); + current_item += " "; + it = it->next; + } while (it != end); + _M_type += current_item.trimmed(); + } else if (node->type_of) { + // ### implement me + _M_type += QLatin1String("typeof<...>"); + } + + visit(node->name); +} + +void TypeCompiler::visitName(NameAST *node) +{ + NameCompiler name_cc(_M_binder); + name_cc.run(node); + _M_type = name_cc.qualifiedName(); +} + +QStringList TypeCompiler::cvString() const +{ + QStringList lst; + + foreach (int q, cv()) { + if (q == Token_const) + lst.append(QLatin1String("const")); + else if (q == Token_volatile) + lst.append(QLatin1String("volatile")); + } + + return lst; +} + +bool TypeCompiler::isConstant() const +{ + return _M_cv.contains(Token_const); +} + +bool TypeCompiler::isVolatile() const +{ + return _M_cv.contains(Token_volatile); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/type_compiler.h b/parser/type_compiler.h new file mode 100644 index 000000000..985cc8e2e --- /dev/null +++ b/parser/type_compiler.h @@ -0,0 +1,71 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef TYPE_COMPILER_H +#define TYPE_COMPILER_H + +#include "default_visitor.h" + +#include +#include +#include + +class TokenStream; +class Binder; + +class TypeCompiler: protected DefaultVisitor +{ +public: + TypeCompiler(Binder *binder); + + inline QStringList qualifiedName() const { return _M_type; } + inline QList cv() const { return _M_cv; } + + bool isConstant() const; + bool isVolatile() const; + + QStringList cvString() const; + + void run(TypeSpecifierAST *node); + +protected: + virtual void visitClassSpecifier(ClassSpecifierAST *node); + virtual void visitEnumSpecifier(EnumSpecifierAST *node); + virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node); + virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node); + + virtual void visitName(NameAST *node); + +private: + Binder *_M_binder; + TokenStream *_M_token_stream; + QStringList _M_type; + QList _M_cv; +}; + +#endif // TYPE_COMPILER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/parser/visitor.cpp b/parser/visitor.cpp new file mode 100644 index 000000000..742981414 --- /dev/null +++ b/parser/visitor.cpp @@ -0,0 +1,122 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "visitor.h" + +Visitor::visitor_fun_ptr Visitor::_S_table[AST::NODE_KIND_COUNT] = { + 0, + reinterpret_cast(&Visitor::visitAccessSpecifier), + reinterpret_cast(&Visitor::visitAsmDefinition), + reinterpret_cast(&Visitor::visitBaseClause), + reinterpret_cast(&Visitor::visitBaseSpecifier), + reinterpret_cast(&Visitor::visitBinaryExpression), + reinterpret_cast(&Visitor::visitCastExpression), + reinterpret_cast(&Visitor::visitClassMemberAccess), + reinterpret_cast(&Visitor::visitClassSpecifier), + reinterpret_cast(&Visitor::visitCompoundStatement), + reinterpret_cast(&Visitor::visitCondition), + reinterpret_cast(&Visitor::visitConditionalExpression), + reinterpret_cast(&Visitor::visitCppCastExpression), + reinterpret_cast(&Visitor::visitCtorInitializer), + reinterpret_cast(&Visitor::visitDeclarationStatement), + reinterpret_cast(&Visitor::visitDeclarator), + reinterpret_cast(&Visitor::visitDeleteExpression), + reinterpret_cast(&Visitor::visitDoStatement), + reinterpret_cast(&Visitor::visitElaboratedTypeSpecifier), + reinterpret_cast(&Visitor::visitEnumSpecifier), + reinterpret_cast(&Visitor::visitEnumerator), + reinterpret_cast(&Visitor::visitExceptionSpecification), + reinterpret_cast(&Visitor::visitExpressionOrDeclarationStatement), + reinterpret_cast(&Visitor::visitExpressionStatement), + reinterpret_cast(&Visitor::visitForStatement), + reinterpret_cast(&Visitor::visitFunctionCall), + reinterpret_cast(&Visitor::visitFunctionDefinition), + reinterpret_cast(&Visitor::visitIfStatement), + reinterpret_cast(&Visitor::visitIncrDecrExpression), + reinterpret_cast(&Visitor::visitInitDeclarator), + reinterpret_cast(&Visitor::visitInitializer), + reinterpret_cast(&Visitor::visitInitializerClause), + reinterpret_cast(&Visitor::visitLabeledStatement), + reinterpret_cast(&Visitor::visitLinkageBody), + reinterpret_cast(&Visitor::visitLinkageSpecification), + reinterpret_cast(&Visitor::visitMemInitializer), + reinterpret_cast(&Visitor::visitName), + reinterpret_cast(&Visitor::visitNamespace), + reinterpret_cast(&Visitor::visitNamespaceAliasDefinition), + reinterpret_cast(&Visitor::visitNewDeclarator), + reinterpret_cast(&Visitor::visitNewExpression), + reinterpret_cast(&Visitor::visitNewInitializer), + reinterpret_cast(&Visitor::visitNewTypeId), + reinterpret_cast(&Visitor::visitOperator), + reinterpret_cast(&Visitor::visitOperatorFunctionId), + reinterpret_cast(&Visitor::visitParameterDeclaration), + reinterpret_cast(&Visitor::visitParameterDeclarationClause), + reinterpret_cast(&Visitor::visitPostfixExpression), + reinterpret_cast(&Visitor::visitPrimaryExpression), + reinterpret_cast(&Visitor::visitPtrOperator), + reinterpret_cast(&Visitor::visitPtrToMember), + reinterpret_cast(&Visitor::visitReturnStatement), + reinterpret_cast(&Visitor::visitSimpleDeclaration), + reinterpret_cast(&Visitor::visitSimpleTypeSpecifier), + reinterpret_cast(&Visitor::visitSizeofExpression), + reinterpret_cast(&Visitor::visitStringLiteral), + reinterpret_cast(&Visitor::visitSubscriptExpression), + reinterpret_cast(&Visitor::visitSwitchStatement), + reinterpret_cast(&Visitor::visitTemplateArgument), + reinterpret_cast(&Visitor::visitTemplateDeclaration), + reinterpret_cast(&Visitor::visitTemplateParameter), + reinterpret_cast(&Visitor::visitThrowExpression), + reinterpret_cast(&Visitor::visitTranslationUnit), + reinterpret_cast(&Visitor::visitTryBlockStatement), + reinterpret_cast(&Visitor::visitTypeId), + reinterpret_cast(&Visitor::visitTypeIdentification), + reinterpret_cast(&Visitor::visitTypeParameter), + reinterpret_cast(&Visitor::visitTypedef), + reinterpret_cast(&Visitor::visitUnaryExpression), + reinterpret_cast(&Visitor::visitUnqualifiedName), + reinterpret_cast(&Visitor::visitUsing), + reinterpret_cast(&Visitor::visitUsingDirective), + reinterpret_cast(&Visitor::visitWhileStatement), + reinterpret_cast(&Visitor::visitWinDeclSpec), + reinterpret_cast(&Visitor::visitQProperty), + reinterpret_cast(&Visitor::visitForwardDeclarationSpecifier), + reinterpret_cast(&Visitor::visitQEnums) +}; + +Visitor::Visitor() +{ +} + +Visitor::~Visitor() +{ +} + +void Visitor::visit(AST *node) +{ + if (node) + (this->*_S_table[node->kind])(node); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/parser/visitor.h b/parser/visitor.h new file mode 100644 index 000000000..74edcca83 --- /dev/null +++ b/parser/visitor.h @@ -0,0 +1,140 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2002-2005 Roberto Raggi + * + * Contact: PySide team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#ifndef VISITOR_H +#define VISITOR_H + +#include "ast.h" + +class Visitor +{ +public: + Visitor(); + virtual ~Visitor(); + + virtual void visit(AST *node); + +protected: + virtual void visitAccessSpecifier(AccessSpecifierAST *) {} + virtual void visitAsmDefinition(AsmDefinitionAST *) {} + virtual void visitBaseClause(BaseClauseAST *) {} + virtual void visitBaseSpecifier(BaseSpecifierAST *) {} + virtual void visitBinaryExpression(BinaryExpressionAST *) {} + virtual void visitCastExpression(CastExpressionAST *) {} + virtual void visitClassMemberAccess(ClassMemberAccessAST *) {} + virtual void visitClassSpecifier(ClassSpecifierAST *) {} + virtual void visitCompoundStatement(CompoundStatementAST *) {} + virtual void visitCondition(ConditionAST *) {} + virtual void visitConditionalExpression(ConditionalExpressionAST *) {} + virtual void visitCppCastExpression(CppCastExpressionAST *) {} + virtual void visitCtorInitializer(CtorInitializerAST *) {} + virtual void visitDeclarationStatement(DeclarationStatementAST *) {} + virtual void visitDeclarator(DeclaratorAST *) {} + virtual void visitDeleteExpression(DeleteExpressionAST *) {} + virtual void visitDoStatement(DoStatementAST *) {} + virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *) {} + virtual void visitEnumSpecifier(EnumSpecifierAST *) {} + virtual void visitEnumerator(EnumeratorAST *) {} + virtual void visitExceptionSpecification(ExceptionSpecificationAST *) {} + virtual void visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *) {} + virtual void visitExpressionStatement(ExpressionStatementAST *) {} + virtual void visitForStatement(ForStatementAST *) {} + virtual void visitFunctionCall(FunctionCallAST *) {} + virtual void visitFunctionDefinition(FunctionDefinitionAST *) {} + virtual void visitIfStatement(IfStatementAST *) {} + virtual void visitIncrDecrExpression(IncrDecrExpressionAST *) {} + virtual void visitInitDeclarator(InitDeclaratorAST *) {} + virtual void visitInitializer(InitializerAST *) {} + virtual void visitInitializerClause(InitializerClauseAST *) {} + virtual void visitLabeledStatement(LabeledStatementAST *) {} + virtual void visitLinkageBody(LinkageBodyAST *) {} + virtual void visitLinkageSpecification(LinkageSpecificationAST *) {} + virtual void visitMemInitializer(MemInitializerAST *) {} + virtual void visitName(NameAST *) {} + virtual void visitNamespace(NamespaceAST *) {} + virtual void visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *) {} + virtual void visitNewDeclarator(NewDeclaratorAST *) {} + virtual void visitNewExpression(NewExpressionAST *) {} + virtual void visitNewInitializer(NewInitializerAST *) {} + virtual void visitNewTypeId(NewTypeIdAST *) {} + virtual void visitOperator(OperatorAST *) {} + virtual void visitOperatorFunctionId(OperatorFunctionIdAST *) {} + virtual void visitParameterDeclaration(ParameterDeclarationAST *) {} + virtual void visitParameterDeclarationClause(ParameterDeclarationClauseAST *) {} + virtual void visitPostfixExpression(PostfixExpressionAST *) {} + virtual void visitPrimaryExpression(PrimaryExpressionAST *) {} + virtual void visitPtrOperator(PtrOperatorAST *) {} + virtual void visitPtrToMember(PtrToMemberAST *) {} + virtual void visitReturnStatement(ReturnStatementAST *) {} + virtual void visitSimpleDeclaration(SimpleDeclarationAST *) {} + virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *) {} + virtual void visitSizeofExpression(SizeofExpressionAST *) {} + virtual void visitStringLiteral(StringLiteralAST *) {} + virtual void visitSubscriptExpression(SubscriptExpressionAST *) {} + virtual void visitSwitchStatement(SwitchStatementAST *) {} + virtual void visitTemplateArgument(TemplateArgumentAST *) {} + virtual void visitTemplateDeclaration(TemplateDeclarationAST *) {} + virtual void visitTemplateParameter(TemplateParameterAST *) {} + virtual void visitThrowExpression(ThrowExpressionAST *) {} + virtual void visitTranslationUnit(TranslationUnitAST *) {} + virtual void visitTryBlockStatement(TryBlockStatementAST *) {} + virtual void visitTypeId(TypeIdAST *) {} + virtual void visitTypeIdentification(TypeIdentificationAST *) {} + virtual void visitTypeParameter(TypeParameterAST *) {} + virtual void visitTypedef(TypedefAST *) {} + virtual void visitUnaryExpression(UnaryExpressionAST *) {} + virtual void visitUnqualifiedName(UnqualifiedNameAST *) {} + virtual void visitUsing(UsingAST *) {} + virtual void visitUsingDirective(UsingDirectiveAST *) {} + virtual void visitWhileStatement(WhileStatementAST *) {} + virtual void visitWinDeclSpec(WinDeclSpecAST *) {} + virtual void visitQProperty(QPropertyAST *) {} + virtual void visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *) {} + virtual void visitQEnums(QEnumsAST *) {} + +private: + typedef void (Visitor::*visitor_fun_ptr)(AST *); + static visitor_fun_ptr _S_table[]; +}; + +template +void visitNodes(Visitor *v, const ListNode<_Tp> *nodes) +{ + if (!nodes) + return; + + const ListNode<_Tp> + *it = nodes->toFront(), + *end = it; + + do { + v->visit(it->element); + it = it->next; + } while (it != end); +} + +#endif // VISITOR_H + +// kate: space-indent on; indent-width 2; replace-tabs on; -- cgit v1.2.3