blob: 1a79acd75cab34e7d4e385528b81ecd03df66287 [file] [log] [blame]
%code requires {
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include "declarations.h"
#include "logging.h"
#include "field_list.h"
#include "fields/all_fields.h"
}
%{
#include "language_y.h"
extern int yylex(yy::parser::semantic_type*, yy::parser::location_type*, void *);
ParseLocation toParseLocation(yy::parser::location_type loc) {
return ParseLocation(loc.begin.line);
}
#define LOC toParseLocation(yylloc)
%}
%parse-param { void* scanner }
%parse-param { Declarations* decls }
%lex-param { void* scanner }
%glr-parser
%skeleton "glr.cc"
%expect-rr 0
%debug
%define parse.error verbose
%locations
%verbose
%union {
int integer;
std::string* string;
EnumDef* enum_definition;
std::map<int, std::string>* enumeration_values;
std::pair<int, std::string>* enumeration_value;
PacketDef* packet_definition_value;
FieldList* packet_field_definitions;
PacketField* packet_field_type;
StructDef* struct_definition_value;
std::set<std::string*>* test_cases_t;
std::string* test_case_t;
std::map<std::string, std::variant<int64_t, std::string>>* constraint_list_t;
std::pair<std::string, std::variant<int64_t, std::string>>* constraint_t;
}
%token <integer> INTEGER
%token <integer> IS_LITTLE_ENDIAN
%token <string> IDENTIFIER
%token <string> SIZE_MODIFIER
%token <string> STRING
%token ENUM "enum"
%token PACKET "packet"
%token PAYLOAD "payload"
%token BODY "body"
%token STRUCT "struct"
%token SIZE "size"
%token COUNT "count"
%token FIXED "fixed"
%token RESERVED "reserved"
%token GROUP "group"
%token CUSTOM_FIELD "custom_field"
%token CHECKSUM "checksum"
%token CHECKSUM_START "checksum_start"
%token PADDING "padding"
%token TEST "test"
%type<enum_definition> enum_definition
%type<enumeration_values> enumeration_list
%type<enumeration_value> enumeration
%type<packet_definition_value> packet_definition;
%type<packet_field_definitions> field_definition_list;
%type<packet_field_type> field_definition;
%type<packet_field_type> group_field_definition;
%type<packet_field_type> type_def_field_definition;
%type<packet_field_type> scalar_field_definition;
%type<packet_field_type> checksum_start_field_definition;
%type<packet_field_type> padding_field_definition;
%type<packet_field_type> size_field_definition;
%type<packet_field_type> payload_field_definition;
%type<packet_field_type> body_field_definition;
%type<packet_field_type> fixed_field_definition;
%type<packet_field_type> reserved_field_definition;
%type<packet_field_type> array_field_definition;
%type<struct_definition_value> struct_definition;
%type<test_cases_t> test_definition;
%type<test_cases_t> test_case_list;
%type<test_case_t> test_case;
%type<constraint_list_t> constraint_list;
%type<constraint_t> constraint;
%destructor { std::cout << "DESTROYING STRING " << *$$ << "\n"; delete $$; } IDENTIFIER STRING SIZE_MODIFIER
%%
file
: IS_LITTLE_ENDIAN declarations
{
decls->is_little_endian = ($1 == 1);
if (decls->is_little_endian) {
DEBUG() << "LITTLE ENDIAN ";
} else {
DEBUG() << "BIG ENDIAN ";
}
}
declarations
: /* empty */
| declarations declaration
declaration
: enum_definition
{
DEBUG() << "FOUND ENUM\n\n";
decls->AddTypeDef($1->name_, $1);
}
| packet_definition
{
DEBUG() << "FOUND PACKET\n\n";
decls->AddPacketDef($1->name_, $1);
}
| struct_definition
{
DEBUG() << "FOUND STRUCT\n\n";
decls->AddTypeDef($1->name_, $1);
}
| group_definition
{
// All actions are handled in group_definition
}
| checksum_definition
{
// All actions are handled in checksum_definition
}
| custom_field_definition
{
// All actions are handled in custom_field_definition
}
| test_definition
{
// All actions are handled in test_definition
}
enum_definition
: ENUM IDENTIFIER ':' INTEGER '{' enumeration_list ',' '}'
{
DEBUG() << "Enum Declared: name=" << *$2
<< " size=" << $4 << "\n";
$$ = new EnumDef(std::move(*$2), $4);
for (const auto& e : *$6) {
$$->AddEntry(e.second, e.first);
}
delete $2;
delete $6;
}
enumeration_list
: enumeration
{
DEBUG() << "Enumerator with comma\n";
$$ = new std::map<int, std::string>();
$$->insert(std::move(*$1));
delete $1;
}
| enumeration_list ',' enumeration
{
DEBUG() << "Enumerator with list\n";
$$ = $1;
$$->insert(std::move(*$3));
delete $3;
}
enumeration
: IDENTIFIER '=' INTEGER
{
DEBUG() << "Enumerator: name=" << *$1
<< " value=" << $3 << "\n";
$$ = new std::pair($3, std::move(*$1));
delete $1;
}
group_definition
: GROUP IDENTIFIER '{' field_definition_list '}'
{
decls->AddGroupDef(*$2, $4);
delete $2;
}
checksum_definition
: CHECKSUM IDENTIFIER ':' INTEGER STRING
{
DEBUG() << "Checksum field defined\n";
decls->AddTypeDef(*$2, new ChecksumDef(*$2, *$5, $4));
delete $2;
delete $5;
}
custom_field_definition
: CUSTOM_FIELD IDENTIFIER ':' INTEGER STRING
{
decls->AddTypeDef(*$2, new CustomFieldDef(*$2, *$5, $4));
delete $2;
delete $5;
}
| CUSTOM_FIELD IDENTIFIER STRING
{
decls->AddTypeDef(*$2, new CustomFieldDef(*$2, *$3));
delete $2;
delete $3;
}
test_definition
: TEST IDENTIFIER '{' test_case_list ',' '}'
{
auto&& packet_name = *$2;
DEBUG() << "Test Declared: name=" << *$2 << "\n";
auto packet = decls->GetPacketDef(packet_name);
if (packet == nullptr) {
ERRORLOC(LOC) << "Could not find packet " << packet_name << "\n";
}
for (const auto& t : *$4) {
packet->AddTestCase(*t);
}
delete $2;
delete $4;
}
test_case_list
: test_case
{
DEBUG() << "Test case with comma\n";
$$ = new std::set<std::string*>();
$$->insert($1);
}
| test_case_list ',' test_case
{
DEBUG() << "Test case with list\n";
$$ = $1;
$$->insert($3);
}
test_case
: STRING
{
DEBUG() << "Test Case: name=" << *$1 << "\n";
$$ = $1;
}
struct_definition
: STRUCT IDENTIFIER '{' field_definition_list '}'
{
auto&& struct_name = *$2;
auto&& field_definition_list = *$4;
DEBUG() << "Struct " << struct_name << " with no parent";
DEBUG() << "STRUCT FIELD LIST SIZE: " << field_definition_list.size();
auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list));
struct_definition->AssignSizeFields();
$$ = struct_definition;
delete $2;
delete $4;
}
| STRUCT IDENTIFIER ':' IDENTIFIER '{' field_definition_list '}'
{
auto&& struct_name = *$2;
auto&& parent_struct_name = *$4;
auto&& field_definition_list = *$6;
DEBUG() << "Struct " << struct_name << " with parent " << parent_struct_name << "\n";
DEBUG() << "STRUCT FIELD LIST SIZE: " << field_definition_list.size() << "\n";
auto parent_struct = decls->GetTypeDef(parent_struct_name);
if (parent_struct == nullptr) {
ERRORLOC(LOC) << "Could not find struct " << parent_struct_name
<< " used as parent for " << struct_name;
}
if (parent_struct->GetDefinitionType() != TypeDef::Type::STRUCT) {
ERRORLOC(LOC) << parent_struct_name << " is not a struct";
}
auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list), (StructDef*)parent_struct);
struct_definition->AssignSizeFields();
$$ = struct_definition;
delete $2;
delete $4;
delete $6;
}
| STRUCT IDENTIFIER ':' IDENTIFIER '(' constraint_list ')' '{' field_definition_list '}'
{
auto&& struct_name = *$2;
auto&& parent_struct_name = *$4;
auto&& constraints = *$6;
auto&& field_definition_list = *$9;
auto parent_struct = decls->GetTypeDef(parent_struct_name);
if (parent_struct == nullptr) {
ERRORLOC(LOC) << "Could not find struct " << parent_struct_name
<< " used as parent for " << struct_name;
}
if (parent_struct->GetDefinitionType() != TypeDef::Type::STRUCT) {
ERRORLOC(LOC) << parent_struct_name << " is not a struct";
}
auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list), (StructDef*)parent_struct);
struct_definition->AssignSizeFields();
for (const auto& constraint : constraints) {
const auto& constraint_name = constraint.first;
const auto& constraint_value = constraint.second;
DEBUG() << "Parent constraint on " << constraint_name;
struct_definition->AddParentConstraint(constraint_name, constraint_value);
}
$$ = struct_definition;
delete $2;
delete $4;
delete $6;
delete $9;
}
packet_definition
: PACKET IDENTIFIER '{' field_definition_list '}' /* Packet with no parent */
{
auto&& packet_name = *$2;
auto&& field_definition_list = *$4;
DEBUG() << "Packet " << packet_name << " with no parent";
DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size();
auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list));
packet_definition->AssignSizeFields();
$$ = packet_definition;
delete $2;
delete $4;
}
| PACKET IDENTIFIER ':' IDENTIFIER '{' field_definition_list '}'
{
auto&& packet_name = *$2;
auto&& parent_packet_name = *$4;
auto&& field_definition_list = *$6;
DEBUG() << "Packet " << packet_name << " with parent " << parent_packet_name << "\n";
DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size() << "\n";
auto parent_packet = decls->GetPacketDef(parent_packet_name);
if (parent_packet == nullptr) {
ERRORLOC(LOC) << "Could not find packet " << parent_packet_name
<< " used as parent for " << packet_name;
}
auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list), parent_packet);
packet_definition->AssignSizeFields();
$$ = packet_definition;
delete $2;
delete $4;
delete $6;
}
| PACKET IDENTIFIER ':' IDENTIFIER '(' constraint_list ')' '{' field_definition_list '}'
{
auto&& packet_name = *$2;
auto&& parent_packet_name = *$4;
auto&& constraints = *$6;
auto&& field_definition_list = *$9;
DEBUG() << "Packet " << packet_name << " with parent " << parent_packet_name << "\n";
DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size() << "\n";
DEBUG() << "CONSTRAINT LIST SIZE: " << constraints.size() << "\n";
auto parent_packet = decls->GetPacketDef(parent_packet_name);
if (parent_packet == nullptr) {
ERRORLOC(LOC) << "Could not find packet " << parent_packet_name
<< " used as parent for " << packet_name << "\n";
}
auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list), parent_packet);
packet_definition->AssignSizeFields();
for (const auto& constraint : constraints) {
const auto& constraint_name = constraint.first;
const auto& constraint_value = constraint.second;
DEBUG() << "Parent constraint on " << constraint_name;
packet_definition->AddParentConstraint(constraint_name, constraint_value);
}
$$ = packet_definition;
delete $2;
delete $4;
delete $6;
delete $9;
}
field_definition_list
: /* empty */
{
DEBUG() << "Empty Field definition\n";
$$ = new FieldList();
}
| field_definition
{
DEBUG() << "Field definition\n";
$$ = new FieldList();
if ($1->GetFieldType() == GroupField::kFieldType) {
auto group_fields = static_cast<GroupField*>($1)->GetFields();
FieldList reversed_fields(group_fields->rbegin(), group_fields->rend());
for (auto& field : reversed_fields) {
$$->PrependField(field);
}
delete $1;
break;
}
$$->PrependField($1);
}
| field_definition ',' field_definition_list
{
DEBUG() << "Field definition with list\n";
$$ = $3;
if ($1->GetFieldType() == GroupField::kFieldType) {
auto group_fields = static_cast<GroupField*>($1)->GetFields();
FieldList reversed_fields(group_fields->rbegin(), group_fields->rend());
for (auto& field : reversed_fields) {
$$->PrependField(field);
}
delete $1;
break;
}
$$->PrependField($1);
}
field_definition
: group_field_definition
{
DEBUG() << "Group Field";
$$ = $1;
}
| type_def_field_definition
{
DEBUG() << "Field with a pre-defined type\n";
$$ = $1;
}
| scalar_field_definition
{
DEBUG() << "Scalar field\n";
$$ = $1;
}
| checksum_start_field_definition
{
DEBUG() << "Checksum start field\n";
$$ = $1;
}
| padding_field_definition
{
DEBUG() << "Padding field\n";
$$ = $1;
}
| size_field_definition
{
DEBUG() << "Size field\n";
$$ = $1;
}
| body_field_definition
{
DEBUG() << "Body field\n";
$$ = $1;
}
| payload_field_definition
{
DEBUG() << "Payload field\n";
$$ = $1;
}
| fixed_field_definition
{
DEBUG() << "Fixed field\n";
$$ = $1;
}
| reserved_field_definition
{
DEBUG() << "Reserved field\n";
$$ = $1;
}
| array_field_definition
{
DEBUG() << "ARRAY field\n";
$$ = $1;
}
group_field_definition
: IDENTIFIER
{
auto group = decls->GetGroupDef(*$1);
if (group == nullptr) {
ERRORLOC(LOC) << "Could not find group with name " << *$1;
}
std::list<PacketField*>* expanded_fields;
expanded_fields = new std::list<PacketField*>(group->begin(), group->end());
$$ = new GroupField(LOC, expanded_fields);
delete $1;
}
| IDENTIFIER '{' constraint_list '}'
{
DEBUG() << "Group with fixed field(s) " << *$1 << "\n";
auto group = decls->GetGroupDef(*$1);
if (group == nullptr) {
ERRORLOC(LOC) << "Could not find group with name " << *$1;
}
std::list<PacketField*>* expanded_fields = new std::list<PacketField*>();
for (const auto field : *group) {
const auto constraint = $3->find(field->GetName());
if (constraint != $3->end()) {
if (field->GetFieldType() == ScalarField::kFieldType) {
DEBUG() << "Fixing group scalar value\n";
expanded_fields->push_back(new FixedScalarField(field->GetSize().bits(), std::get<int64_t>(constraint->second), LOC));
} else if (field->GetFieldType() == EnumField::kFieldType) {
DEBUG() << "Fixing group enum value\n";
auto type_def = decls->GetTypeDef(field->GetDataType());
EnumDef* enum_def = (type_def->GetDefinitionType() == TypeDef::Type::ENUM ? (EnumDef*)type_def : nullptr);
if (enum_def == nullptr) {
ERRORLOC(LOC) << "No enum found of type " << field->GetDataType();
}
if (!enum_def->HasEntry(std::get<std::string>(constraint->second))) {
ERRORLOC(LOC) << "Enum " << field->GetDataType() << " has no enumeration " << std::get<std::string>(constraint->second);
}
expanded_fields->push_back(new FixedEnumField(enum_def, std::get<std::string>(constraint->second), LOC));
} else {
ERRORLOC(LOC) << "Unimplemented constraint of type " << field->GetFieldType();
}
$3->erase(constraint);
} else {
expanded_fields->push_back(field);
}
}
if ($3->size() > 0) {
ERRORLOC(LOC) << "Could not find member " << $3->begin()->first << " in group " << *$1;
}
$$ = new GroupField(LOC, expanded_fields);
delete $1;
delete $3;
}
constraint_list
: constraint ',' constraint_list
{
DEBUG() << "Group field value list\n";
$3->insert(*$1);
$$ = $3;
delete($1);
}
| constraint
{
DEBUG() << "Group field value\n";
$$ = new std::map<std::string, std::variant<int64_t, std::string>>();
$$->insert(*$1);
delete($1);
}
constraint
: IDENTIFIER '=' INTEGER
{
DEBUG() << "Group with a fixed integer value=" << $1 << " value=" << $3 << "\n";
$$ = new std::pair(*$1, std::variant<int64_t,std::string>($3));
delete $1;
}
| IDENTIFIER '=' IDENTIFIER
{
DEBUG() << "Group with a fixed enum field value=" << *$3 << " enum=" << *$1;
$$ = new std::pair(*$1, std::variant<int64_t,std::string>(*$3));
delete $1;
delete $3;
}
type_def_field_definition
: IDENTIFIER ':' IDENTIFIER
{
DEBUG() << "Predefined type field " << *$1 << " : " << *$3 << "\n";
if (auto type_def = decls->GetTypeDef(*$3)) {
$$ = type_def->GetNewField(*$1, LOC);
} else {
ERRORLOC(LOC) << "No type with this name\n";
}
delete $1;
delete $3;
}
scalar_field_definition
: IDENTIFIER ':' INTEGER
{
DEBUG() << "Scalar field " << *$1 << " : " << $3 << "\n";
$$ = new ScalarField(*$1, $3, LOC);
delete $1;
}
body_field_definition
: BODY
{
DEBUG() << "Body field\n";
$$ = new BodyField(LOC);
}
payload_field_definition
: PAYLOAD ':' '[' SIZE_MODIFIER ']'
{
DEBUG() << "Payload field with modifier " << *$4 << "\n";
$$ = new PayloadField(*$4, LOC);
delete $4;
}
| PAYLOAD
{
DEBUG() << "Payload field\n";
$$ = new PayloadField("", LOC);
}
checksum_start_field_definition
: CHECKSUM_START '(' IDENTIFIER ')'
{
DEBUG() << "ChecksumStart field defined\n";
$$ = new ChecksumStartField(*$3, LOC);
delete $3;
}
padding_field_definition
: PADDING '[' INTEGER ']'
{
DEBUG() << "Padding field defined\n";
$$ = new PaddingField($3, LOC);
}
size_field_definition
: SIZE '(' IDENTIFIER ')' ':' INTEGER
{
DEBUG() << "Size field defined\n";
$$ = new SizeField(*$3, $6, LOC);
delete $3;
}
| SIZE '(' PAYLOAD ')' ':' INTEGER
{
DEBUG() << "Size for payload defined\n";
$$ = new SizeField("payload", $6, LOC);
}
| SIZE '(' BODY ')' ':' INTEGER
{
DEBUG() << "Size for body defined\n";
$$ = new SizeField("body", $6, LOC);
}
| COUNT '(' IDENTIFIER ')' ':' INTEGER
{
DEBUG() << "Count field defined\n";
$$ = new CountField(*$3, $6, LOC);
delete $3;
}
fixed_field_definition
: FIXED '=' INTEGER ':' INTEGER
{
DEBUG() << "Fixed field defined value=" << $3 << " size=" << $5 << "\n";
$$ = new FixedScalarField($5, $3, LOC);
}
| FIXED '=' IDENTIFIER ':' IDENTIFIER
{
DEBUG() << "Fixed enum field defined value=" << *$3 << " enum=" << *$5;
auto type_def = decls->GetTypeDef(*$5);
if (type_def != nullptr) {
EnumDef* enum_def = (type_def->GetDefinitionType() == TypeDef::Type::ENUM ? (EnumDef*)type_def : nullptr);
if (!enum_def->HasEntry(*$3)) {
ERRORLOC(LOC) << "Previously defined enum " << enum_def->GetTypeName() << " has no entry for " << *$3;
}
$$ = new FixedEnumField(enum_def, *$3, LOC);
} else {
ERRORLOC(LOC) << "No enum found with name " << *$5;
}
delete $3;
delete $5;
}
reserved_field_definition
: RESERVED ':' INTEGER
{
DEBUG() << "Reserved field of size=" << $3 << "\n";
$$ = new ReservedField($3, LOC);
}
array_field_definition
: IDENTIFIER ':' INTEGER '[' ']'
{
DEBUG() << "Vector field defined name=" << *$1 << " element_size=" << $3;
$$ = new VectorField(*$1, $3, "", LOC);
delete $1;
}
| IDENTIFIER ':' INTEGER '[' SIZE_MODIFIER ']'
{
DEBUG() << "Vector field defined name=" << *$1 << " element_size=" << $3
<< " size_modifier=" << *$5;
$$ = new VectorField(*$1, $3, *$5, LOC);
delete $1;
delete $5;
}
| IDENTIFIER ':' INTEGER '[' INTEGER ']'
{
DEBUG() << "Array field defined name=" << *$1 << " element_size=" << $3
<< " fixed_size=" << $5;
$$ = new ArrayField(*$1, $3, $5, LOC);
delete $1;
}
| IDENTIFIER ':' IDENTIFIER '[' ']'
{
DEBUG() << "Vector field defined name=" << *$1 << " type=" << *$3;
if (auto type_def = decls->GetTypeDef(*$3)) {
$$ = new VectorField(*$1, type_def, "", LOC);
} else {
ERRORLOC(LOC) << "Can't find type used in array field.";
}
delete $1;
delete $3;
}
| IDENTIFIER ':' IDENTIFIER '[' SIZE_MODIFIER ']'
{
DEBUG() << "Vector field defined name=" << *$1 << " type=" << *$3
<< " size_modifier=" << *$5;
if (auto type_def = decls->GetTypeDef(*$3)) {
$$ = new VectorField(*$1, type_def, *$5, LOC);
} else {
ERRORLOC(LOC) << "Can't find type used in array field.";
}
delete $1;
delete $3;
delete $5;
}
| IDENTIFIER ':' IDENTIFIER '[' INTEGER ']'
{
DEBUG() << "Array field defined name=" << *$1 << " type=" << *$3
<< " fixed_size=" << $5;
if (auto type_def = decls->GetTypeDef(*$3)) {
$$ = new ArrayField(*$1, type_def, $5, LOC);
} else {
ERRORLOC(LOC) << "Can't find type used in array field.";
}
delete $1;
delete $3;
}
%%
void yy::parser::error(const yy::parser::location_type& loc, const std::string& error) {
ERROR() << error << " at location " << loc << "\n";
abort();
}