%require "3.2" %language "c++" %define api.prefix {a2ml} %define api.namespace {a2l} %define api.parser.class {A2mlParser} %code requires { #include #include #include #include #include "a2l/a2mlobject.h" namespace a2l { class A2mlScanner; } } %parse-param { a2l::A2mlScanner &scanner } %code { #include #include "a2mlscanner.h" #include "a2lhelper.h" #include #undef yylex #define yylex scanner.a2mllex } %define api.value.type variant %token A2ML_BEGIN %token A2ML_END %token A2ML %token ARRAY_BEGIN %token ARRAY_END %token BLOCK %token BLOCK_BEGIN %token BLOCK_END %token CHAR %token CONSTANT %token DEF_END %token DOUBLE %token ENUM %token EQUAL %token FLOAT %token IDENT %token IF_DATA %token INT %token INT64 %token LONG %token MEM_BEGIN %token MEM_END %token STRING %token STRUCT %token TAGGED_STRUCT %token TAGGED_UNION %token TEXT_ARRAY %token UCHAR %token UINT %token UINT64 %token ULONG %nterm > enumerator %nterm enumerator_list %nterm identifier %nterm keyword %nterm predefined_type_name %nterm tag %nterm type_name %nterm type_definition %nterm block_definition %nterm enum_type_name %nterm struct_type_name %nterm member %nterm struct_member_list %nterm struct_member %nterm taggedstruct_type_name %nterm taggedstruct_member_list %nterm taggedstruct_member %nterm taggedstruct_definition %nterm taggedunion_type_name %nterm taggedunion_member_list %nterm taggedunion_member %nterm declaration %nterm declaration_list %start a2ml_block %% a2ml_block: %empty | A2ML_BEGIN A2ML declaration_list A2ML_END A2ML { scanner.BlockList($3); }; declaration_list: declaration { $$ = A2mlMemberList(); $$.emplace_back($1); } | declaration_list declaration { $$ = $1; $$.emplace_back($2); }; declaration: type_definition DEF_END { $$ = $1; } | block_definition DEF_END { $$ = $1; }; type_definition: type_name { $$ = $1;}; type_name : predefined_type_name { $$ = A2mlObject(A2mlTypeName::PREDEFINED); $$.DataType($1); } | struct_type_name { $$ = $1; } | taggedstruct_type_name { $$ = $1; } | taggedunion_type_name { $$ = $1; } | enum_type_name { $$ = $1; }; predefined_type_name: CHAR { $$ = A2mlDataType::CHAR;} | INT { $$ = A2mlDataType::INT;} | LONG { $$ = A2mlDataType::LONG;} | INT64 { $$ = A2mlDataType::INT64;} | UCHAR { $$ = A2mlDataType::UCHAR;} | UINT { $$ = A2mlDataType::UINT;} | UINT64 { $$ = A2mlDataType::UINT64;} | ULONG { $$ = A2mlDataType::ULONG;} | DOUBLE { $$ = A2mlDataType::DOUBLE;} | FLOAT { $$ = A2mlDataType::FLOAT;} | TEXT_ARRAY { $$ = A2mlDataType::TEXT_ARRAY;}; block_definition: BLOCK tag member { $$ = A2mlObject(A2mlTypeName::BLOCK); $$.Tag($2); $$.MemberList().emplace_back($3); } | BLOCK tag MEM_BEGIN member MEM_END { $$ = A2mlObject(A2mlTypeName::BLOCK); $$.Tag($2); $$.MemberList().emplace_back($4); }; enum_type_name : ENUM identifier BLOCK_BEGIN enumerator_list BLOCK_END { $$ = A2mlObject(A2mlTypeName::ENUMERATE); $$.Ident($2); $$.EnumerateList($4); } | ENUM IDENT { $$ = A2mlObject(A2mlTypeName::ENUMERATE); $$.Ident($2); }; enumerator_list: enumerator { A2mlEnumerateList list; auto& enumerator = $1; const auto itr = list.find(enumerator.first); if (itr == list.cend() ) { list.emplace(enumerator.first, enumerator.second); } else { // Change key auto key = list.rbegin()->first; ++key; list.emplace(key, enumerator.second); } $$ = list; } | enumerator_list enumerator { auto& list = $1; auto& enumerator = $2; const auto itr = list.find(enumerator.first); if (itr == list.cend() ) { list.emplace(enumerator.first, enumerator.second); } else { // Change key auto key = list.rbegin()->first; ++key; list.emplace(key, enumerator.second); } $$ = list; }; enumerator: keyword { $$.first = 0; $$.second = $1; } | keyword EQUAL CONSTANT { $$.first = $3; $$.second = $1; }; struct_type_name: STRUCT identifier BLOCK_BEGIN struct_member_list BLOCK_END { $$ = A2mlObject(A2mlTypeName::STRUCT); $$.Ident($2); $$.MemberList($4); } | STRUCT IDENT { $$ = A2mlObject(A2mlTypeName::STRUCT); $$.Ident($2); }; struct_member_list: %empty {} | struct_member_list struct_member { $$ = $1; $$.emplace_back($2); }; struct_member: member DEF_END { $$ = $1; } | MEM_BEGIN member MEM_END DEF_END { $$ = $2; }; member: type_name array_specifier { $$ = $1; // Todo Array specifier }; array_specifier: %empty | array_specifier ARRAY_BEGIN CONSTANT ARRAY_END; taggedstruct_type_name: TAGGED_STRUCT identifier BLOCK_BEGIN taggedstruct_member_list BLOCK_END { $$ = A2mlObject(A2mlTypeName::TAGGED_STRUCT); $$.Ident($2); $$.MemberList($4); } | TAGGED_STRUCT IDENT { $$ = A2mlObject(A2mlTypeName::TAGGED_STRUCT); $$.Ident($2); }; taggedstruct_member_list: taggedstruct_member { $$ = A2mlMemberList(); $$.emplace_back($1); } | taggedstruct_member_list taggedstruct_member { $$ = $1; $$.emplace_back($2); }; taggedstruct_member: taggedstruct_definition DEF_END { $$ = $1; } | MEM_BEGIN taggedstruct_definition MEM_END DEF_END { $$ = $2; } | block_definition DEF_END {$$ = $1;} | MEM_BEGIN block_definition MEM_END DEF_END { $$ = $2;}; taggedstruct_definition: tag { $$ = A2mlObject(A2mlTypeName::UNKNOWN); $$.Tag($1); } | tag member { $$ = $2; $$.Tag($1); } | tag MEM_BEGIN member MEM_END { $$ = $3; $$.Tag($1); }; taggedunion_type_name: TAGGED_UNION identifier BLOCK_BEGIN taggedunion_member_list BLOCK_END { $$ = A2mlObject(A2mlTypeName::TAGGED_UNION); $$.Ident($2); $$.MemberList( $4); } | TAGGED_UNION IDENT { $$ = A2mlObject(A2mlTypeName::TAGGED_UNION); $$.Ident($2); }; taggedunion_member_list: taggedunion_member { $$ = A2mlMemberList(); $$.emplace_back($1); } | taggedunion_member_list taggedunion_member { $$ = $1; $$.emplace_back($2); }; taggedunion_member: tag DEF_END { $$ = A2mlObject(A2mlTypeName::UNKNOWN); $$.Tag($1); } | tag member DEF_END { $$ = $2; $$.Tag($1); } | block_definition DEF_END { $$ = $1; }; keyword : STRING { $$ = $1; }; identifier: %empty {} | IDENT { $$ = $1; }; tag: STRING { $$ = $1; }; %% void a2l::A2mlParser::error(const std::string& err) { const auto line = scanner.lineno(); // const auto column = scanner.YYLeng(); const std::string near = scanner.YYText() != nullptr ? scanner.YYText() : ""; std::ostringstream error; error << "Parser error: " << err << ", Line: " << line << ", Near: " << near; scanner.LastError(error.str()); }