OVMS3/OVMS.V3/components/dbc/src/dbc_parser.y

559 lines
16 KiB
Text

/*
; Project: Open Vehicle Monitor System
; Date: 15th November 2018
;
; Changes:
; 1.0 Initial release
;
; (C) 2011 Michael Stegen / Stegen Electronics
; (C) 2011-2017 Mark Webb-Johnson
; (C) 2011 Sonny Chen @ EPRO/DX
;
; With credit due to candbc-parser.y, for idea and structure
; https://github.com/Polyconseil/libcanardbc
; Copyright (C) 2007-2009 Andreas Heitmann
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
; THE SOFTWARE.
*/
%{
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include "dbc.h"
#include "ovms_log.h"
#ifdef CONFIG_OVMS
#define YYMALLOC ExternalRamMalloc
#include "ovms_malloc.h"
#endif // #ifdef CONFIG_OVMS
/* Tell Bison how much stack space is needed. */
#define YYERROR_VERBOSE 1
#define YYMAXDEPTH 1000
%}
%parse-param {void* dbcptr}
%union {
long long number;
double double_val;
char* string;
};
%{
extern int yylex (void);
extern char *yytext;
extern int yylineno;
static const char *TAG = "dbc-parser";
extern "C"
{
void yyerror(void* dbcptr, const char *msg)
{
ESP_LOGE(TAG,"Error in line %d '%s', symbol '%s'",
yylineno, msg, yytext);
}
#ifdef CONFIG_OVMS
void *yyalloc (size_t sz)
{
return ExternalRamMalloc(sz);
}
void *yyrealloc (void *ptr, size_t sz)
{
return ExternalRamRealloc(ptr,sz);
}
#endif // #ifdef CONFIG_OVMS
}
dbcfile* current_dbc = NULL;
dbcValueTable* current_value_table = NULL;
dbcMessage* current_message = NULL;
dbcSignal* current_signal = NULL;
%}
%token T_COLON
%token T_SEMICOLON
%token T_SEP
%token T_AT
%token T_PLUS
%token T_MINUS
%token T_BOX_OPEN
%token T_BOX_CLOSE
%token T_PAR_OPEN
%token T_PAR_CLOSE
%token T_COMMA
%token T_ID
%token T_STRING_VAL
%token T_INT_VAL
%token T_DOUBLE_VAL
%token T_VERSION
%token T_INT
%token T_FLOAT
%token T_NAN
%token T_STRING
%token T_ENUM
%token T_HEX
%token T_BO /* Botschaft */
%token T_BS
%token T_BU /* Steuergerät */
%token T_SG /* Signal */
%token T_EV /* Environment */
%token T_NS
%token T_NS_DESC
%token T_CM /* Comment */
%token T_BA_DEF /* Attribut-Definition */
%token T_BA /* Attribut */
%token T_VAL
%token T_CAT_DEF
%token T_CAT
%token T_FILTER
%token T_BA_DEF_DEF
%token T_EV_DATA
%token T_ENVVAR_DATA
%token T_SGTYPE
%token T_SGTYPE_VAL
%token T_BA_DEF_SGTYPE
%token T_BA_SGTYPE
%token T_SIG_TYPE_REF
%token T_VAL_TABLE
%token T_SIG_GROUP
%token T_SIG_VALTYPE
%token T_SIGTYPE_VALTYPE
%token T_BO_TX_BU
%token T_BA_DEF_REL
%token T_BA_REL
%token T_BA_DEF_DEF_REL
%token T_BU_SG_REL
%token T_BU_EV_REL
%token T_BU_BO_REL
%token T_SG_MUL_VAL
%token T_DUMMY_NODE_VECTOR
%type <string> T_ID T_STRING_VAL version_section signal_mux
%type <number> T_INT_VAL signal_endian signal_sign signal_start signal_length
%type <double_val> T_DOUBLE_VAL double_val signal_scale signal_offset signal_min signal_max
%%
dbc:
{
current_dbc = (dbcfile*)dbcptr;
current_value_table = NULL;
current_message = NULL;
current_signal = NULL;
}
dbc_sections
;
dbc_sections:
| dbc_sections dbc_section
;
dbc_section:
version_section
| symbol_section
| bit_timing_section
| node_list_section
| value_table_section
| message_section
| signal_section
| value_section
| attribute_section
| attribute_default_section
| comment_section
;
/************************************************************************/
/* version_section (VERSION) */
/************************************************************************/
version_section: T_VERSION T_STRING_VAL
{
ESP_LOGD(TAG,"VERSION parsed as: %s",$2);
current_dbc->m_version = std::string($2);
if ($2) { free($2); $2=NULL; }
};
/************************************************************************/
/* symbol_section (NS_) */
/************************************************************************/
symbol_section:
T_NS T_COLON symbol_list
{
ESP_LOGD(TAG,"NS_ parsed %d symbols",current_dbc->m_newsymbols.GetCount());
}
;
symbol_list:
| symbol_list symbol
;
symbol:
T_NS_DESC { current_dbc->m_newsymbols.AddSymbol("NS_DESC_"); }
| T_CM { current_dbc->m_newsymbols.AddSymbol("CM_"); }
| T_BA_DEF { current_dbc->m_newsymbols.AddSymbol("BA_DEF_"); }
| T_BA { current_dbc->m_newsymbols.AddSymbol("BA_"); }
| T_VAL { current_dbc->m_newsymbols.AddSymbol("VAL_"); }
| T_CAT_DEF { current_dbc->m_newsymbols.AddSymbol("CAT_DEF_"); }
| T_CAT { current_dbc->m_newsymbols.AddSymbol("CAT_"); }
| T_FILTER { current_dbc->m_newsymbols.AddSymbol("FILTER"); }
| T_BA_DEF_DEF { current_dbc->m_newsymbols.AddSymbol("BA_DEF_DEF_"); }
| T_EV_DATA { current_dbc->m_newsymbols.AddSymbol("EV_DATA_"); }
| T_ENVVAR_DATA { current_dbc->m_newsymbols.AddSymbol("ENVVAR_DATA_"); }
| T_SGTYPE { current_dbc->m_newsymbols.AddSymbol("SG_TYPE_"); }
| T_SGTYPE_VAL { current_dbc->m_newsymbols.AddSymbol("SG_TYPE_VAL_"); }
| T_BA_DEF_SGTYPE { current_dbc->m_newsymbols.AddSymbol("BA_DEF_SGTYPE_"); }
| T_BA_SGTYPE { current_dbc->m_newsymbols.AddSymbol("BA_SGTYPE_"); }
| T_SIG_TYPE_REF { current_dbc->m_newsymbols.AddSymbol("SIG_TYPE_REF_"); }
| T_VAL_TABLE { current_dbc->m_newsymbols.AddSymbol("VAL_TABLE_"); }
| T_SIG_GROUP { current_dbc->m_newsymbols.AddSymbol("SIG_GROUP_"); }
| T_SIG_VALTYPE { current_dbc->m_newsymbols.AddSymbol("SIG_VALTYPE_"); }
| T_SIGTYPE_VALTYPE { current_dbc->m_newsymbols.AddSymbol("SIGTYPE_VALTYPE_"); }
| T_BO_TX_BU { current_dbc->m_newsymbols.AddSymbol("BO_TX_BU_"); }
| T_BA_DEF_REL { current_dbc->m_newsymbols.AddSymbol("BA_DEF_REL_"); }
| T_BA_REL { current_dbc->m_newsymbols.AddSymbol("BA_REL_"); }
| T_BA_DEF_DEF_REL { current_dbc->m_newsymbols.AddSymbol("BA_DEF_DEF_REL_"); }
| T_BU_SG_REL { current_dbc->m_newsymbols.AddSymbol("BU_SG_REL_"); }
| T_BU_EV_REL { current_dbc->m_newsymbols.AddSymbol("BU_EV_REL_"); }
| T_BU_BO_REL { current_dbc->m_newsymbols.AddSymbol("BU_BO_REL_"); }
| T_SG_MUL_VAL { current_dbc->m_newsymbols.AddSymbol("SG_MUL_VAL_"); }
;
/************************************************************************/
/* bit_timing_section (BS_) */
/************************************************************************/
bit_timing_section:
T_BS T_COLON
{
ESP_LOGD(TAG,"BS_ parsed empty");
}
| T_BS T_COLON T_INT_VAL T_COLON T_INT_VAL T_COMMA T_INT_VAL
{
ESP_LOGD(TAG,"BS_ parsed %d,%d,%d",(int)$3,(int)$5,(int)$7);
current_dbc->m_bittiming.SetBaud($3,$5,$7);
}
;
/************************************************************************/
/* node_list_section (BU_) */
/************************************************************************/
node_list_section:
T_BU T_COLON node_list
{
ESP_LOGD(TAG,"BU_ parsed %d nodes",current_dbc->m_nodes.GetCount());
}
;
node_list:
| node_list T_ID
{
current_dbc->m_nodes.AddNode(new dbcNode($2));
free($2);
}
;
/************************************************************************/
/* value_table_section (VAL_TABLE_) */
/************************************************************************/
value_table_section:
T_VAL_TABLE value_table_list T_SEMICOLON
{
ESP_LOGD(TAG,"VAL_TABLE_ parsed %s %d values",
current_value_table->GetName().c_str(),
current_value_table->GetCount());
}
;
value_table_list:
T_ID T_INT_VAL T_STRING_VAL
{
current_value_table = new dbcValueTable($1);
current_dbc->m_values.AddValueTable($1, current_value_table);
current_value_table->AddValue($2, $3);
free($1); free($3);
}
|
value_table_list T_INT_VAL T_STRING_VAL
{
current_value_table->AddValue($2, $3);
free($3);
}
;
/************************************************************************/
/* message_section (BO_) */
/************************************************************************/
/* BO_ 1160 DAS_steeringControl: 4 NEO */
message_section:
T_BO T_INT_VAL T_ID T_COLON T_INT_VAL T_ID
{
ESP_LOGD(TAG,"BO_ parsed message %d",(int)$2);
current_message = new dbcMessage((uint32_t)$2);
current_message->SetName($3); free($3);
current_message->SetSize($5);
current_message->SetTransmitterNode($6); free($6);
current_dbc->m_messages.AddMessage($2,current_message);
}
;
/************************************************************************/
/* signal_section (SG_) */
/************************************************************************/
/* SG_ DAS_steeringAngleRequest : 6|15@0+ (0.1,-1638.35) [-1638.35|1638.35] "deg" EPAS */
signal_section:
T_SG T_ID signal_mux T_COLON
signal_start T_SEP signal_length T_AT signal_endian signal_sign
T_PAR_OPEN signal_scale T_COMMA signal_offset T_PAR_CLOSE
T_BOX_OPEN signal_min T_SEP signal_max T_BOX_CLOSE
T_STRING_VAL receiver_list
{
ESP_LOGD(TAG,"SG_ parsed signal %s",$2);
current_signal->SetName($2); free($2);
if (current_message == NULL)
{
yyerror(current_dbc, "SG_ not after a BO_ message");
free($21);
current_signal = NULL;
YYABORT;
}
if ($3 == NULL)
{
current_signal->ClearMultiplexed();
}
else
{
switch($3[0])
{
case 'M':
current_message->SetMultiplexorSignal(current_signal);
break;
case 'm':
current_signal->SetMultiplexed((uint32_t)strtoul($3+1, NULL, 10));
break;
default:
/* error: unknown mux type */
break;
}
free($3);
}
current_signal->SetStartSize($5,$7);
current_signal->SetByteOrder((dbcByteOrder_t)$9);
current_signal->SetValueType(($10 == 0)?DBC_VALUETYPE_UNSIGNED:DBC_VALUETYPE_SIGNED);
current_signal->SetFactorOffset($12,$14);
current_signal->SetMinMax($17,$19);
current_signal->SetUnit($21); free($21);
current_message->AddSignal(current_signal);
current_signal = NULL;
}
;
double_val:
T_DOUBLE_VAL { $$ = $1; }
| T_NAN { $$ = NAN; }
| T_INT_VAL { $$ = (double)$1; }
;
signal_mux:
{ $$ = NULL; }
| T_ID { $$ = $1; }
;
signal_endian:
T_INT_VAL { $$ = $1; }
;
signal_sign:
T_PLUS { $$ = 0; }
| T_MINUS { $$ = 1; }
;
signal_start: T_INT_VAL { $$ = $1; };
signal_length: T_INT_VAL { $$ = $1; };
signal_scale: double_val { $$ = $1; };
signal_offset: double_val { $$ = $1; };
signal_min: double_val { $$ = $1; };
signal_max: double_val { $$ = $1; };
receiver_list:
receiver
| receiver_list T_COMMA receiver
;
receiver:
T_ID
{
if (current_signal == NULL) current_signal = new dbcSignal();
current_signal->AddReceiver(std::string($1)); free($1);
}
;
/************************************************************************/
/* value_section (VAL_) */
/************************************************************************/
/* VAL_ 792 GTW_updateInProgress 1 "IN_PROGRESS" 2 "IN_PROGRESS_NOT_USED"; */
value_section:
value_list T_SEMICOLON
;
value_list:
| T_VAL T_INT_VAL T_ID T_INT_VAL T_STRING_VAL
{
dbcMessage* m = current_dbc->m_messages.FindMessage((uint32_t)$2);
if (m == NULL)
{
yyerror(current_dbc, "VAL_ message not found");
free($3); free($5);
YYABORT;
}
current_signal = m->FindSignal(std::string($3));
if (current_signal == NULL)
{
yyerror(current_dbc, "VAL_ signal not found (in message)");
free($3); free($5);
YYABORT;
}
ESP_LOGD(TAG,"VAL_ parsed %d/%s",(int)$2,$3);
current_signal->AddValue((uint32_t)$4, std::string($5));
free($3); free($5);
}
|
value_list T_INT_VAL T_STRING_VAL
{
current_signal->AddValue((uint32_t)$2, std::string($3));
free($3);
}
;
/************************************************************************/
/* attribute_section_list (BA_DEF_) */
/************************************************************************/
/* BA_DEF_ BO_ "GenMsgBackgroundColor" STRING ; */
attribute_section:
T_BA_DEF attribute_object_type T_STRING_VAL T_STRING T_SEMICOLON
| T_BA_DEF attribute_object_type T_STRING_VAL T_INT T_INT_VAL T_INT_VAL T_SEMICOLON
attribute_object_type: T_BU | T_BO | T_SG | T_EV
/************************************************************************/
/* attribute_default_section_list (BA_DEF_DEF_) */
/************************************************************************/
/* BA_DEF_DEF_ "GenMsgBackgroundColor" "#1e1e1e"; */
attribute_default_section:
T_BA_DEF_DEF T_STRING_VAL T_STRING_VAL T_SEMICOLON
| T_BA_DEF_DEF T_STRING_VAL T_INT_VAL T_SEMICOLON
/************************************************************************/
/* comment_section_list (CM_) */
/************************************************************************/
/* CM_ "This is my comment"; */
comment_section:
T_CM T_STRING_VAL T_SEMICOLON
{
ESP_LOGD(TAG,"CM_ parsed %s",$2);
current_dbc->m_comments.AddComment($2); free($2);
}
| T_CM T_BU T_ID T_STRING_VAL T_SEMICOLON
{
dbcNode* n = current_dbc->m_nodes.FindNode(std::string($3));
if (n != NULL)
{
ESP_LOGD(TAG,"CM_ BU_ parsed %s",$3);
n->AddComment($4);
}
else
{
yyerror(current_dbc, "BU_ node not found");
free($3); free($4);
YYABORT;
}
free($3); free($4);
}
| T_CM T_BO T_INT_VAL T_STRING_VAL T_SEMICOLON
{
dbcMessage* m = current_dbc->m_messages.FindMessage((uint32_t)$3);
if (m != NULL)
{
ESP_LOGD(TAG,"CM_ BO_ parsed %s",$4);
m->AddComment($4);
}
else
{
yyerror(current_dbc, "BO_ message not found");
free($4);
YYABORT;
}
free($4);
}
| T_CM T_SG T_INT_VAL T_ID T_STRING_VAL T_SEMICOLON
{
dbcMessage* m = current_dbc->m_messages.FindMessage((uint32_t)$3);
if (m != NULL)
{
dbcSignal* s = m->FindSignal(std::string($4));
if (s != NULL)
{
ESP_LOGD(TAG,"CM_ SG_ parsed %s",$5);
s->AddComment($5);
}
else
{
yyerror(current_dbc, "BO_ signal not found (in message)");
free($4); free($5);
YYABORT;
}
}
else
{
yyerror(current_dbc, "SG_ message not found");
free($4); free($5);
YYABORT;
}
free($4); free($5);
}
| T_CM T_EV T_ID T_STRING_VAL T_SEMICOLON
{
yyerror(current_dbc, "EV_ not currently supported");
free($3); free($4);
YYABORT;
}
;