%{ #include #include #include #include #include #include #include #include #include #include #ifndef yylex /* We use different prefixes for the lexer and parser. * * Our lexer's prefix is deviceAttachmentPipeSpecl. * * Our parser's prefix is deviceAttachmentPipeSpecp. * * Yacc and Bison don't have a way to handle the scenario where the lexer has * a different prefix from the parser that they generate. They assume that the * lexer must have the same prefix as the parser they generate. So we just use * this #define below to override yacc/bison's presumed prefix for the lexer. */ #error "Yacc should have defined yylex as a preprocessor token, and we need to override it to tell yacc the name of our lex function." #endif #undef yylex #define yylex deviceAttachmentPipeSpecllex #ifdef yytext #undef yytext #endif #define yytext deviceAttachmentPipeSpecltext // Declare the symbols that our lexer will export. int yylex(void); extern char* yytext; // Declare yytext to access the current token text void yyerror(const char *message) { throw std::runtime_error( std::string("deviceAttachmentPipeSpec parser error: ") + std::string(message) + " at token: " + std::string(yytext)); } %} %union { char* str; char chr; smo::device::DeviceAttachmentSpec* sensorSpec; smo::device::InteroceptorDevAttachmentSpec* interoceptorSpec; smo::device::ExtrospectorDevAttachmentSpec* extrospectorSpec; std::vector>* paramVector; std::pair* param; smo::device::DapSegment* DapSpecSegment; std::vector* DapSegmentVector; } %token STRING %token PIPE DOUBLE_PIPE LPAREN RPAREN %token KEYWORD_SPECTYPE_ACTUATOR %token KEYWORD_SPECTYPE_EXTROSPECTOR KEYWORD_SPECTYPE_INTEROSPECTOR %token EQUALS // Add new token for '=' %type params opt_params %type param %type spec_body %type interoceptor_spec %type extrospector_spec %type specifier_segment %type specifier_segments %% file: /* NOTHING */ | sensor_specs ; sensor_specs: sensor_spec | sensor_specs DOUBLE_PIPE sensor_spec ; sensor_spec: interoceptor_spec | extrospector_spec ; interoceptor_spec: KEYWORD_SPECTYPE_INTEROSPECTOR PIPE spec_body { auto spec = std::make_shared( *static_cast($3)); spec->sensorType = $1; smo::device::DeviceManager::commandLineDASpecs.push_back(*spec); delete $3; } ; extrospector_spec: KEYWORD_SPECTYPE_EXTROSPECTOR PIPE spec_body { auto spec = std::make_shared( *static_cast($3)); spec->sensorType = $1; smo::device::DeviceManager::commandLineDASpecs.push_back(*spec); delete $3; } ; spec_body: STRING PIPE specifier_segments PIPE STRING { auto segments = std::unique_ptr>($3); if (segments->size() < 3 || segments->size() > 5) { throw std::runtime_error( "DAP spec for device '" + std::string($1) + "' must declare " "qualeIfaceApi, stimBuffApi and provider (optionally preceded " "by up to one postrin and one negtrin segment); got " + std::to_string(segments->size()) + " pre-devSelector segments."); } const size_t nIntrins = segments->size() - 3; $$ = new smo::device::DeviceAttachmentSpec(); $$->deviceIdentifier = std::string($1); $$->sensorType = '\0'; // This will be set by the parent rule for (size_t i = 0; i < nIntrins; ++i) { auto& seg = (*segments)[i]; if (seg.name == "postrin") { if (!$$->postrin.empty()) { throw std::runtime_error( "DAP spec for device '" + $$->deviceIdentifier + "' declares more than one postrin segment."); } $$->postrin = seg.name; $$->postrinParams = std::move(seg.params); } else if (seg.name == "negtrin") { if (!$$->negtrin.empty()) { throw std::runtime_error( "DAP spec for device '" + $$->deviceIdentifier + "' declares more than one negtrin segment."); } $$->negtrin = seg.name; $$->negtrinParams = std::move(seg.params); } else { throw std::runtime_error( "DAP spec segment before qualeIfaceApi must be 'postrin' " "or 'negtrin' (got '" + seg.name + "') for device '" + $$->deviceIdentifier + "'."); } } auto& qSeg = (*segments)[nIntrins]; auto& sSeg = (*segments)[nIntrins + 1]; auto& pSeg = (*segments)[nIntrins + 2]; $$->qualeIfaceApi = std::move(qSeg.name); $$->qualeIfaceApiParams = std::move(qSeg.params); $$->stimBuffApi = std::move(sSeg.name); $$->stimBuffApiParams = std::move(sSeg.params); $$->provider = std::move(pSeg.name); $$->providerParams = std::move(pSeg.params); $$->deviceSelector = std::string($5); } ; specifier_segments: specifier_segment { $$ = new std::vector(); $$->push_back(std::move(*$1)); delete $1; } | specifier_segments PIPE specifier_segment { $$ = $1; $$->push_back(std::move(*$3)); delete $3; } ; specifier_segment: STRING LPAREN opt_params RPAREN { $$ = new smo::device::DapSegment(); $$->name = std::string($1); $$->params = std::move(*$3); delete $3; } ; opt_params: params | /* empty */ { $$ = new std::vector>(); } ; params: param { $$ = new std::vector>(); $$->push_back(*$1); delete $1; } | params PIPE param { $$ = $1; $$->push_back(*$3); delete $3; } ; param: STRING { $$ = new std::pair($1, ""); } | STRING EQUALS { $$ = new std::pair($1, ""); } | STRING EQUALS STRING { $$ = new std::pair($1, $3); } ; %%