Devspec: Add lexer and parser for devSpecs
This grammar looks simple but it consumed 2 days of my time and it's giving me bugs all the same, but mostly working nicely. See the syntax documentation in /docs
This commit is contained in:
@@ -1,4 +1,18 @@
|
|||||||
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
|
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
|
||||||
|
AM_YFLAGS = -d
|
||||||
|
|
||||||
noinst_LIBRARIES = libdeviceManager.a
|
noinst_LIBRARIES = libdeviceManager.a
|
||||||
libdeviceManager_a_SOURCES = deviceManager.cpp deviceSpecParser.cpp
|
libdeviceManager_a_SOURCES = deviceSpecp.yy deviceSpecl.ll \
|
||||||
|
deviceManager.cpp deviceSpecParser.cpp
|
||||||
|
|
||||||
|
deviceSpecl.cc: deviceSpecl.ll
|
||||||
|
deviceSpecl.o: AM_LFLAGS += --header-file=deviceSpecl.hh \
|
||||||
|
-o deviceSpecl.cc
|
||||||
|
deviceSpecp.cc deviceSpecp.hh: deviceSpecp.yy
|
||||||
|
deviceSpecp.o: AM_YFLAGS += -p deviceSpecp \
|
||||||
|
--header=deviceSpecp.hh -o deviceSpecp.cc
|
||||||
|
|
||||||
|
deviceSpecParser.o: AM_CXXFLAGS+=-Wno-ignored-attributes
|
||||||
|
|
||||||
|
CLEANFILES=deviceSpecp.cc deviceSpecp.hh \
|
||||||
|
deviceSpecl.cc deviceSpecl.hh
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
%option prefix="deviceSpecl"
|
||||||
|
%{
|
||||||
|
#include <vector>
|
||||||
|
#include <deviceManager/deviceManager.h>
|
||||||
|
#include "deviceSpecp.hh"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
^a {
|
||||||
|
deviceSpecplval.chr = yytext[0];
|
||||||
|
return KEYWORD_SPECTYPE_ACTUATOR;
|
||||||
|
}
|
||||||
|
^e {
|
||||||
|
deviceSpecplval.chr = yytext[0];
|
||||||
|
return KEYWORD_SPECTYPE_EXTROSPECTOR;
|
||||||
|
}
|
||||||
|
^i {
|
||||||
|
deviceSpecplval.chr = yytext[0];
|
||||||
|
return KEYWORD_SPECTYPE_INTEROSPECTOR;
|
||||||
|
}
|
||||||
|
"||" { return DOUBLE_PIPE; }
|
||||||
|
"|" { return PIPE; }
|
||||||
|
"(" { return LPAREN; }
|
||||||
|
")" { return RPAREN; }
|
||||||
|
[^\|\(\) \t\r\n]+ { deviceSpecplval.str = strdup(yytext); return STRING; }
|
||||||
|
\r?\n { /* ignore newlines */ }
|
||||||
|
[ \t]+ { /* ignore whitespace */ }
|
||||||
|
. { return yytext[0]; }
|
||||||
|
%%
|
||||||
|
|
||||||
|
int deviceSpeclwrap(void)
|
||||||
|
{
|
||||||
|
return 1; // Indicate end of input
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
%{
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <deviceManager/deviceManager.h>
|
||||||
|
|
||||||
|
#ifndef yylex
|
||||||
|
/* We use different prefixes for the lexer and parser.
|
||||||
|
* * Our lexer's prefix is deviceSpecl.
|
||||||
|
* * Our parser's prefix is deviceSpecp.
|
||||||
|
*
|
||||||
|
* 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, and we need to override it to tell yacc the name of our lex function."
|
||||||
|
#endif
|
||||||
|
#undef yylex
|
||||||
|
#define yylex deviceSpecllex
|
||||||
|
|
||||||
|
// Declare the symbols that our lexer will export.
|
||||||
|
int yylex(void);
|
||||||
|
void yyerror(const char *message)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("deviceSpec parser error: ")
|
||||||
|
+ std::string(message)) + yytext;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%union {
|
||||||
|
char* str;
|
||||||
|
char chr;
|
||||||
|
DeviceManager::SensorDeviceSpec* sensorSpec;
|
||||||
|
DeviceManager::InteroceptorDeviceSpec* interoceptorSpec;
|
||||||
|
DeviceManager::ExtrospectorDeviceSpec* extrospectorSpec;
|
||||||
|
std::vector<std::string>* stringVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
%token <str> STRING
|
||||||
|
%token PIPE DOUBLE_PIPE LPAREN RPAREN
|
||||||
|
%token <chr> KEYWORD_SPECTYPE_ACTUATOR
|
||||||
|
%token <chr> KEYWORD_SPECTYPE_EXTROSPECTOR KEYWORD_SPECTYPE_INTEROSPECTOR
|
||||||
|
|
||||||
|
%type <stringVector> params opt_params
|
||||||
|
%type <sensorSpec> spec_body
|
||||||
|
%type <interoceptorSpec> interoceptor_spec
|
||||||
|
%type <extrospectorSpec> extrospector_spec
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
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 {
|
||||||
|
DeviceManager::InteroceptorDeviceSpec *spec =
|
||||||
|
static_cast<DeviceManager::InteroceptorDeviceSpec *>($3);
|
||||||
|
|
||||||
|
spec->sensorType = $1;
|
||||||
|
DeviceManager::interoceptorDeviceSpecs.push_back(*spec);
|
||||||
|
delete spec;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
extrospector_spec:
|
||||||
|
KEYWORD_SPECTYPE_EXTROSPECTOR PIPE spec_body {
|
||||||
|
DeviceManager::ExtrospectorDeviceSpec *spec =
|
||||||
|
static_cast<DeviceManager::ExtrospectorDeviceSpec *>($3);
|
||||||
|
|
||||||
|
spec->sensorType = $1;
|
||||||
|
DeviceManager::extrospectorDeviceSpecs.push_back(*spec);
|
||||||
|
delete spec;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
spec_body:
|
||||||
|
STRING PIPE STRING LPAREN opt_params RPAREN PIPE STRING LPAREN opt_params RPAREN PIPE STRING {
|
||||||
|
$$ = new DeviceManager::SensorDeviceSpec();
|
||||||
|
$$->sensorType = '\0';
|
||||||
|
$$->implexor = std::string($1);
|
||||||
|
$$->api = std::string($3);
|
||||||
|
$$->apiParams = std::move(*$5);
|
||||||
|
$$->server = std::string($8);
|
||||||
|
$$->serverParams = std::move(*$10);
|
||||||
|
$$->deviceSelector = std::string($13);
|
||||||
|
delete $5;
|
||||||
|
delete $10;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
opt_params:
|
||||||
|
params
|
||||||
|
| /* empty */ { $$ = new std::vector<std::string>(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
params:
|
||||||
|
STRING { $$ = new std::vector<std::string>{ $1 }; }
|
||||||
|
| params PIPE STRING { $$ = $1; $$->push_back($3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
Reference in New Issue
Block a user