// Copyright (C) 2022 Satya Das and CppParser contributors // SPDX-License-Identifier: MIT /* TODOs: (1) Parsing of following needs improvements/support: (a) Imp: Function pointer (b) Sup: Reference to array (c) Sup: Pointer to array Need to borrow ideas from https://www.nongnu.org/hcb/ and may be http://www.computing.surrey.ac.uk/research/dsrg/fog/CxxGrammar.y too can help. */ // clang-format off %{ #include "cpptoken.h" #include "cpp_entity_builders.h" #include "cppast/cppast.h" #include "optional.h" #include "parser.tab.h" #include "parser.l.h" #include "utils.h" #include "memory_util.h" #include #include #include #include #include ////////////////////////////////////////////////////////////////////////// #ifndef NDEBUG # define YYDEBUG 1 #else # define YYDEBUG 0 #endif //#ifndef NDEBUG #define YYERROR_DETAILED #define YYDELETEPOSN(x, y) #define YYDELETEVAL(x, y) #ifndef TRUE // Need this to fix BtYacc compilation error. # define TRUE true #endif static int gParseLog = 0; #define ZZLOG \ { \ if (gParseLog) \ printf("ZZLOG @line#%d, parsing stream line#%d\n", __LINE__, g.mLineNo); \ } static int gDisableYyValid = 0; #define ZZVALID { \ if (gParseLog) \ printf("ZZVALID: "); \ ZZLOG; \ if (!gDisableYyValid) \ YYVALID; \ } #define ZZERROR \ do { \ if (gParseLog) \ printf("ZZERROR: "); \ ZZLOG; \ YYERROR; \ } while(0) #define ZZVALID_DISABLE \ ++gDisableYyValid; #define ZZVALID_ENABLE \ --gDisableYyValid; /** {Globals} */ /** * A program unit is the entire parse tree of a source/header file */ static cppast::CppCompound* gProgUnit; // FuncdeclHack: // Following gets parsed as variable with initialization: // Type Identifier(Type * Id); // `Type * Id` gets parsed as expression involving multiplication and so `Identifier` // followed by expression in brackets becomes a call to constructor of `Type`. // Actually there is an ambiguity in the grammer which compilers solve by using context. // For purpose of this parser we cannot collect all required context to solve this ambiguity. // So, we use a hack: // We define a production rule for this case and flag it as error. But before flagging error // we save the position of operator '*' (or '&', or "&&") and then we check for location of // the same operator in other expression production rule before accepting that as valid expression. // For us we always want to parse it as function declaration rather than call to constructor by passing an expression, // and so the hack is expected to serve us well. static const char* gParamModPos = nullptr; // TemplateParamHack: // Template parameter gets parsed as vardecl which then gets reduced as templateparam without name as used in forward declaration. // We don't want that, so to avoid such templateparam getting reduced as vardecl we apply some hack. static const char* gTemplateParamStart = nullptr; static bool gInTemplateSpec = false; /** * A stack to know where (i.e. how deep inside class defnition) the current parsing activity is taking place. */ using CppCompoundStack = std::stack; static CppCompoundStack gCompoundStack; /** {End of Globals} */ #define YYPOSN char* extern int yylex(); // Yacc generated code causes warnings that need suppression. // This pragma should be at the end. #if defined(__clang__) || defined(__GNUC__) # pragma GCC diagnostic ignored "-Wwrite-strings" #endif using namespace cppast; // FIXME: Improve template arg parsing. // Template argument needs more robust support. // As of now we are treating them just as string. // But for parsing we need to have a type. class CppTemplateArg; %} %union { struct CppToken str; struct CppFunctionData funcDeclData; cppast::CppMemberInit* memInit; cppast::CppEntity* cppEntity; cppast::CppEntityAccessSpecifier* accessSpecifier; cppast::CppTypeModifier typeModifier; cppast::CppVarType* cppVarType; cppast::CppVar* cppVarObj; cppast::CppEnum* cppEnum; cppast::CppEnumItem* enumItem; std::list* enumItemList; cppast::CppTypedefName* typedefName; cppast::CppTypedefList* typedefList; cppast::CppUsingDecl* usingDecl; cppast::CppUsingNamespaceDecl* usingNamespaceDecl; cppast::CppNamespaceAlias* namespaceAlias; cppast::CppCompound* cppCompundObj; cppast::CppTemplateParam* templateParam; std::vector* templateParamList; cppast::CppDocumentationComment* docCommentObj; cppast::CppForwardClassDecl* fwdDeclObj; cppast::CppVarList* cppVarObjList; cppast::CppPreprocessorUnrecognized* unRecogPreProObj; cppast::CppExpression* cppExprObj; cppast::CppCallArgs* exprList; cppast::CppLambda* cppLambda; cppast::CppFunction* cppFuncObj; cppast::CppFunctionPointer* cppFuncPointerObj; cppast::CppEntity* varOrFuncPtr; std::vector>* paramList; cppast::CppConstructor* cppCtorObj; cppast::CppDestructor* cppDtorObj; cppast::CppTypeConverter* cppTypeConverter; cppast::CppMemberInits* memInitList; std::list* inheritList; bool inheritType; std::vector* identifierList; std::vector* funcThrowSpec; class CppTemplateArg* templateArg; cppast::CppAsmBlock* asmBlock; cppast::CppCompoundType compoundType; unsigned short ptrLevel; cppast::CppRefType refType; unsigned int attr; Optional objAccessType; cppast::CppCallArgs* attribSpecifiers; cppast::CppIfBlock* ifBlock; cppast::CppWhileBlock* whileBlock; cppast::CppDoWhileBlock* doWhileBlock; cppast::CppForBlock* forBlock; cppast::CppRangeForBlock* forRangeBlock; cppast::CppSwitchBlock* switchBlock; std::vector* switchBody; cppast::CppTryBlock* tryBlock; cppast::CppCatchBlock* catchBlock; cppast::CppPreprocessorDefine* hashDefine; cppast::CppPreprocessorUndef* hashUndef; cppast::CppPreprocessorInclude* hashInclude; cppast::CppPreprocessorImport* hashImport; cppast::CppPreprocessorConditional* hashIf; cppast::CppPreprocessorError* hashError; cppast::CppPreprocessorWarning* hashWarning; cppast::CppPreprocessorPragma* hashPragma; cppast::CppReturnStatement* returnStmt; cppast::CppThrowStatement* throwStmt; cppast::CppGotoStatement* gotoStmt; cppast::CppBlob* blob; cppast::CppLabel* label; cppast::CppVarInitInfo* cppVarInitInfo; } %token tknName tknID tknStrLit tknCharLit tknNumber tknMacro tknApiDecor %token tknTypedef tknUsing %token tknInteger tknChar tknDouble tknFloat %token tknEnum %token tknAuto %token tknPreProDef %token tknClass tknStruct tknUnion tknNamespace %token tknTemplate tknTypename tknDecltype %token tknFreeStandingBlockComment tknSideBlockComment tknFreeStandingLineComment tknSideLineComment %token tknScopeResOp %token tknNumSignSpec // signed/unsigned %token tknPublic tknProtected tknPrivate %token tknExternC %token tknUnRecogPrePro %token tknStdHdrInclude %token tknPragma tknHashError tknHashWarning %token tknEllipsis %token tknConstCast tknStaticCast tknDynamicCast tknReinterpretCast %token tknTry tknCatch tknThrow tknSizeOf %token tknOperator tknPlusEq tknMinusEq tknMulEq tknDivEq tknPerEq tknXorEq tknAndEq tknOrEq %token tknLShift tknRShift tknLShiftEq tknRShiftEq tknCmpEq tknNotEq tknLessEq tknGreaterEq %token tkn3WayCmp tknAnd tknOr tknInc tknDec tknArrow tknArrowStar %token tknLT tknGT // We will need the position of these operators in stream when used for declaring template instance. %token '+' '-' '*' '/' '%' '^' '&' '|' '~' '!' '=' ',' '(' ')' '[' ']' ';' '.' %token tknNew tknDelete %token tknConst tknConstExpr %token tknVoid // For the cases when void is used as function parameter. %token tknOverride tknFinal // override, final are not a reserved keywords %token tknAsm %token tknBlob %token tknGoto %token tknStatic tknExtern tknVirtual tknInline tknExplicit tknFriend tknVolatile tknMutable tknNoExcept %token tknPreProHash /* When # is encountered for pre processor definition */ %token tknDefine tknUndef %token tknInclude tknImport %token tknIf tknIfDef tknIfNDef tknElse tknElIf tknEndIf %token tknFor tknWhile tknDo tknSwitch tknCase tknDefault %token tknReturn %token tknBlankLine %type strlit %type optapidecor apidecor apidecortokensq %type identifier optidentifier numbertype typeidentifier varidentifier optname id name designatedname operfuncname funcname %type templidentifier templqualifiedid %type doccommentstr optdoccommentstr %type rshift %type macrocall %type stmt %type opttypemodifier typemodifier %type enumdefn enumfwddecl enumdefnstmt %type enumitem %type enumitemlist %type fwddecl %type vartype %type vardecl varinit vardeclstmt %type varassign optvarassign %type param %type funcobjstr /* Identify funcobjstr as str, at least for time being */ %type templatearg templatearglist /* For time being. We may need to make it more robust in future. */ %type asmblock %type vardecllist vardeclliststmt %type paramlist lambdaparams %type typedefname typedefnamestmt %type typedeflist typedefliststmt %type usingnamespacedecl %type namespacealias %type usingdecl %type stmtlist optstmtlist progunit classdefn namespacedefn classdefnstmt externcblock block %type templatespecifier templateparamlist %type templateparam %type doccomment %type expr exprstmt optexpr lambdacapture captureallbyref captureallbyval exprorlist optexprorlist desinatedinitialization %type exprlist optexprlist %type objcarg objcarglist %type lambda %type ifblock; %type whileblock; %type dowhileblock; %type forblock; %type forrangeblock; %type switchstmt; %type caselist; %type tryblock; %type catchblock; %type functionpointer functionptrtype funcpointerdecl funcptrtypedef funcptrortype funcobj %type funcdecldata %type funcdecl funcdeclstmt funcdefn %type ctordecl ctordeclstmt ctordefn %type dtordecl dtordeclstmt dtordefn %type typeconverter typeconverterstmt %type meminitlist %type meminit %type classspecifier %type varattrib exptype optfuncattrib functype optfunctype optfinal %type optinheritlist %type optinherittype %type protlevel %type entityaccessspecifier %type identifierlist %type functhrowspec optfuncthrowspec %type attribs optattribs attribspecifier attribspecifiers optattribspecifiers %type define %type undef %type include %type import %type hashif %type hasherror %type hashwarning %type pragma %type returnstmt %type throwstmt %type gotostmt %type preprocessor %type blob %type