summaryrefslogtreecommitdiffstats
path: root/wiretap/busmaster_parser.lemon
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--wiretap/busmaster_parser.lemon455
1 files changed, 455 insertions, 0 deletions
diff --git a/wiretap/busmaster_parser.lemon b/wiretap/busmaster_parser.lemon
new file mode 100644
index 00000000..ce62aada
--- /dev/null
+++ b/wiretap/busmaster_parser.lemon
@@ -0,0 +1,455 @@
+%include {
+
+/* busmaster_parser.lemon
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Support for Busmaster log file format
+ * Copyright (c) 2019 by Maksim Salau <maksim.salau@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+#include <assert.h>
+#include <string.h>
+#include <wireshark.h>
+#include <wiretap/file_wrappers.h>
+#include "busmaster_priv.h"
+
+extern void *BusmasterParserAlloc(void *(*mallocProc)(size_t));
+extern void BusmasterParser(void *yyp, int yymajor, token_t yyminor, busmaster_state_t *state);
+extern void BusmasterParserFree(void *p, void (*freeProc)(void*));
+
+#if defined(BUSMASTER_DEBUG) || defined(BUSMASTER_PARSER_TRACE)
+extern void BusmasterParserTrace(FILE *TraceFILE, char *zTracePrompt);
+#undef NDEBUG
+#endif
+
+static void merge_msg_data(msg_data_t *dst, const msg_data_t *a, const msg_data_t *b)
+{
+ dst->length = a->length + b->length;
+ memcpy(&dst->data[0], &a->data[0], a->length);
+ memcpy(&dst->data[a->length], &b->data[0], b->length);
+}
+
+DIAG_OFF_LEMON()
+} /* end of %include */
+
+%code {
+DIAG_ON_LEMON()
+}
+
+%name BusmasterParser
+
+%token_prefix TOKEN_
+
+%token_type { token_t }
+
+%token_destructor
+{
+ (void)state;
+ (void)yypParser;
+ (void)yypminor;
+}
+
+%extra_argument { busmaster_state_t* state }
+
+%syntax_error
+{
+ (void)yypParser;
+ (void)yyminor;
+
+#ifdef BUSMASTER_DEBUG
+ const int n = sizeof(yyTokenName) / sizeof(yyTokenName[0]);
+ busmaster_debug_printf("%s: got token: %s\n", G_STRFUNC, yyTokenName[yymajor]);
+ for (int i = 0; i < n; ++i) {
+ int a = yy_find_shift_action((YYCODETYPE)i, yypParser->yytos->stateno);
+ if (a < YYNSTATE + YYNRULE) {
+ busmaster_debug_printf("%s: possible token: %s\n", G_STRFUNC, yyTokenName[i]);
+ }
+ }
+#endif
+
+ g_free(state->parse_error);
+ state->entry_type = LOG_ENTRY_ERROR;
+ state->parse_error = ws_strdup_printf("Syntax Error");
+ busmaster_debug_printf("%s: Syntax Error\n", G_STRFUNC);
+}
+
+%parse_failure
+{
+ g_free(state->parse_error);
+ state->entry_type = LOG_ENTRY_ERROR;
+ state->parse_error = g_strdup("Parse Error");
+ busmaster_debug_printf("%s: Parse Error\n", G_STRFUNC);
+}
+
+%stack_overflow
+{
+ g_free(state->parse_error);
+ state->entry_type = LOG_ENTRY_ERROR;
+ state->parse_error = g_strdup("Parser stack overflow");
+ busmaster_debug_printf("%s: Parser stack overflow\n", G_STRFUNC);
+}
+
+%type msg_time { msg_time_t }
+%type msg_type { msg_type_t }
+%type err_msg_type { msg_type_t }
+%type msg_length { guint }
+%type msg_id { guint32 }
+
+%type ref_date { msg_date_t }
+%type ref_time { msg_time_t }
+
+%type start_time { msg_date_time_t }
+
+%type byte { guint8 }
+%type data { msg_data_t }
+%type data0 { msg_data_t }
+%type data1 { msg_data_t }
+%type data2 { msg_data_t }
+%type data3 { msg_data_t }
+%type data4 { msg_data_t }
+%type data5 { msg_data_t }
+%type data6 { msg_data_t }
+%type data7 { msg_data_t }
+%type data8 { msg_data_t }
+%type data12 { msg_data_t }
+%type data16 { msg_data_t }
+%type data20 { msg_data_t }
+%type data24 { msg_data_t }
+%type data32 { msg_data_t }
+%type data48 { msg_data_t }
+%type data64 { msg_data_t }
+
+%nonassoc INVALID_CHAR .
+%nonassoc INVALID_NUMBER .
+
+%start_symbol entry
+
+entry ::= empty_line .
+entry ::= footer_and_header .
+entry ::= header .
+entry ::= footer .
+entry ::= msg .
+entry ::= err_msg .
+entry ::= j1939_msg .
+
+empty_line ::= .
+{
+ busmaster_debug_printf("%s: EMPTY\n", G_STRFUNC);
+ state->entry_type = LOG_ENTRY_EMPTY;
+}
+
+footer_and_header ::= footer ENDL header .
+{
+ busmaster_debug_printf("%s: FOOTER AND HEADER\n", G_STRFUNC);
+ state->entry_type = LOG_ENTRY_FOOTER_AND_HEADER;
+}
+
+header ::= version ENDL maybe_lines
+ PROTOCOL_TYPE(P) ENDL maybe_lines
+ START_SESSION ENDL maybe_lines
+ start_time(S) ENDL maybe_lines
+ DATA_MODE(D) ENDL maybe_lines
+ TIME_MODE(T) ENDL anything .
+{
+ busmaster_debug_printf("%s: HEADER\n", G_STRFUNC);
+
+ state->entry_type = LOG_ENTRY_HEADER;
+ state->header.start_date = S.date;
+ state->header.start_time = S.time;
+ state->header.protocol = (protocol_type_t)P.v0;
+ state->header.data_mode = (data_mode_t)D.v0;
+ state->header.time_mode = (time_mode_t)T.v0;
+}
+
+version ::= HEADER_VER maybe_chars .
+
+maybe_chars ::= .
+maybe_chars ::= maybe_chars HEADER_CHAR .
+
+maybe_lines ::= .
+maybe_lines ::= maybe_lines maybe_chars ENDL .
+
+anything ::= .
+anything ::= anything HEADER_CHAR .
+anything ::= anything ENDL .
+
+start_time(R) ::= START_TIME ref_date(D) ref_time(T) .
+{
+ R.date = D;
+ R.time = T;
+}
+
+footer ::= end_time ENDL STOP_SESSION .
+{
+ busmaster_debug_printf("%s: FOOTER\n", G_STRFUNC);
+ state->entry_type = LOG_ENTRY_FOOTER;
+}
+
+end_time ::= END_TIME ref_date ref_time .
+
+/* <Time><Tx/Rx><Channel><CAN ID><Type><DLC><DataBytes> */
+msg ::= msg_time(msg_time) MSG_DIR INT msg_id(msg_id) msg_type(msg_type) msg_length(msg_length) data(msg_data) .
+{
+ msg_t msg;
+
+ /* DLC is always in DEC mode, thus we need to fix the value
+ * if it was read initially as HEX. */
+ if (state->header.data_mode == DATA_MODE_HEX)
+ {
+ msg_length = (msg_length / 16) * 10 + (msg_length % 16);
+ }
+
+ /* Fix data in RTR frames. Data may not be present,
+ * but length field is set. */
+ if (msg_type == MSG_TYPE_STD_RTR ||
+ msg_type == MSG_TYPE_EXT_RTR)
+ {
+ memset(&msg_data, 0, sizeof(msg_data));
+ msg_data.length = msg_length;
+ }
+
+ msg.timestamp = msg_time;
+ msg.id = msg_id;
+ msg.type = msg_type;
+ msg.data = msg_data;
+
+ busmaster_debug_printf("%s: MSG\n", G_STRFUNC);
+
+ state->msg = msg;
+ state->entry_type = LOG_ENTRY_MSG;
+}
+
+/* <Time><Tx/Rx><Channel><CAN ID><Type><Text> */
+err_msg ::= msg_time(msg_time) MSG_DIR INT INT err_msg_type(msg_type) .
+{
+ msg_t msg;
+
+ msg.timestamp = msg_time;
+ msg.id = 0;
+ msg.type = msg_type;
+ msg.data.length = CAN_MAX_DLEN;
+
+ memset(msg.data.data, 0, sizeof(msg.data.data));
+
+ busmaster_debug_printf("%s: ERR MSG\n", G_STRFUNC);
+
+ state->msg = msg;
+ state->entry_type = LOG_ENTRY_MSG;
+}
+
+/* <Time><Channel><CAN ID><PGN><Type><Source Node><Destination Node><Priority><Tx/Rx><DLC><DataBytes> */
+j1939_msg ::= msg_time(msg_time) INT msg_id(msg_id) INT J1939_MSG_TYPE INT INT INT MSG_DIR msg_length data(msg_data) .
+{
+ msg_t msg;
+
+ msg.timestamp = msg_time;
+ msg.id = msg_id;
+ msg.type = MSG_TYPE_EXT;
+ msg.data = msg_data;
+
+ busmaster_debug_printf("%s: J1939 MSG\n", G_STRFUNC);
+
+ state->msg = msg;
+ state->entry_type = LOG_ENTRY_MSG;
+}
+
+ref_date(R) ::= INT(D) COLON INT(M) COLON INT(Y) .
+{
+ R.year = (guint)Y.v0;
+ R.month = (guint)M.v0;
+ R.day = (guint)D.v0;
+}
+
+ref_time(R) ::= INT(H) COLON INT(M) COLON INT(S) COLON INT(U) .
+{
+ R.hours = (guint)H.v0;
+ R.minutes = (guint)M.v0;
+ R.seconds = (guint)S.v0;
+ R.micros = (guint)U.v0 * 1000;
+}
+
+msg_time(R) ::= MSG_TIME(M) .
+{
+ R.hours = (guint)M.v0;
+ R.minutes = (guint)M.v1;
+ R.seconds = (guint)M.v2;
+ R.micros = (guint)M.v3 * 100;
+}
+
+msg_id(R) ::= INT(V) .
+{
+ R = (guint)V.v0;
+}
+
+msg_length(R) ::= INT(V) .
+{
+ R = (guint)V.v0;
+}
+
+msg_type(R) ::= MSG_TYPE(V) .
+{
+ R = (msg_type_t)V.v0;
+}
+
+err_msg_type(R) ::= ERR_MSG_TYPE(V) .
+{
+ R = (msg_type_t)V.v0;
+}
+
+data(R) ::= data0(A) . { R = A; }
+data(R) ::= data1(A) . { R = A; }
+data(R) ::= data2(A) . { R = A; }
+data(R) ::= data3(A) . { R = A; }
+data(R) ::= data4(A) . { R = A; }
+data(R) ::= data5(A) . { R = A; }
+data(R) ::= data6(A) . { R = A; }
+data(R) ::= data7(A) . { R = A; }
+data(R) ::= data8(A) . { R = A; }
+data(R) ::= data12(A) . { R = A; }
+data(R) ::= data16(A) . { R = A; }
+data(R) ::= data20(A) . { R = A; }
+data(R) ::= data24(A) . { R = A; }
+data(R) ::= data32(A) . { R = A; }
+data(R) ::= data48(A) . { R = A; }
+data(R) ::= data64(A) . { R = A; }
+
+byte(R) ::= INT(A) .
+{
+ R = (guint8)A.v0;
+}
+
+data0(R) ::= .
+{
+ R.length = 0;
+}
+
+data1(R) ::= byte(A) .
+{
+ R.length = 1;
+ R.data[0] = A;
+}
+
+data2(R) ::= byte(A) byte(B) .
+{
+ R.length = 2;
+ R.data[0] = A;
+ R.data[1] = B;
+}
+
+data3(R) ::= byte(A) byte(B) byte(C) .
+{
+ R.length = 3;
+ R.data[0] = A;
+ R.data[1] = B;
+ R.data[2] = C;
+}
+
+data4(R) ::= byte(A) byte(B) byte(C) byte(D) .
+{
+ R.length = 4;
+ R.data[0] = A;
+ R.data[1] = B;
+ R.data[2] = C;
+ R.data[3] = D;
+}
+
+data5(R) ::= data4(A) data1(B) . { merge_msg_data(&R, &A, &B); }
+data6(R) ::= data4(A) data2(B) . { merge_msg_data(&R, &A, &B); }
+data7(R) ::= data4(A) data3(B) . { merge_msg_data(&R, &A, &B); }
+data8(R) ::= data4(A) data4(B) . { merge_msg_data(&R, &A, &B); }
+data12(R) ::= data8(A) data4(B) . { merge_msg_data(&R, &A, &B); }
+data16(R) ::= data8(A) data8(B) . { merge_msg_data(&R, &A, &B); }
+data20(R) ::= data16(A) data4(B) . { merge_msg_data(&R, &A, &B); }
+data24(R) ::= data16(A) data8(B) . { merge_msg_data(&R, &A, &B); }
+data32(R) ::= data16(A) data16(B) . { merge_msg_data(&R, &A, &B); }
+data48(R) ::= data32(A) data16(B) . { merge_msg_data(&R, &A, &B); }
+data64(R) ::= data32(A) data32(B) . { merge_msg_data(&R, &A, &B); }
+
+%code {
+
+#include "busmaster_scanner_lex.h"
+#include "busmaster_parser.h"
+
+gboolean
+run_busmaster_parser(busmaster_state_t *state,
+ int *err, gchar **err_info)
+{
+ int lex_code;
+ yyscan_t scanner;
+ void *parser;
+
+ state->entry_type = LOG_ENTRY_NONE;
+ state->parse_error = NULL;
+ state->err = 0;
+ state->err_info = NULL;
+
+ if (busmaster_lex_init_extra(state, &scanner) != 0)
+ {
+ *err = errno;
+ *err_info = g_strdup(g_strerror(errno));
+ return FALSE;
+ }
+
+ parser = BusmasterParserAlloc(g_malloc);
+
+#ifdef BUSMASTER_PARSER_TRACE
+ BusmasterParserTrace(stdout, "BusmasterParser >> ");
+#endif
+
+ busmaster_debug_printf("%s: Starting parsing of the line\n", G_STRFUNC);
+
+ do
+ {
+ lex_code = busmaster_lex(scanner);
+
+#ifdef BUSMASTER_DEBUG
+ if (lex_code)
+ busmaster_debug_printf("%s: Feeding %s '%s'\n",
+ G_STRFUNC, yyTokenName[lex_code],
+ busmaster_get_text(scanner));
+ else
+ busmaster_debug_printf("%s: Feeding %s\n",
+ G_STRFUNC, yyTokenName[lex_code]);
+#endif
+
+ BusmasterParser(parser, lex_code, state->token, state);
+
+ if (state->err || state->err_info || state->parse_error)
+ break;
+ }
+ while (lex_code);
+
+ busmaster_debug_printf("%s: Done (%d)\n", G_STRFUNC, lex_code);
+
+ BusmasterParserFree(parser, g_free);
+ busmaster_lex_destroy(scanner);
+
+ if (state->err || state->err_info || state->parse_error)
+ {
+ if (state->err_info)
+ {
+ *err_info = state->err_info;
+ g_free(state->parse_error);
+ }
+ else
+ {
+ *err_info = state->parse_error;
+ }
+
+ if (state->err)
+ *err = state->err;
+ else
+ *err = WTAP_ERR_BAD_FILE;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+}