+%{
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+
+extern FILE *yyin;
+
+static size_t errors;
+enum filter_dir {
+GTW_IN,
+GTW_OUT,
+GTW_INOUT
+};
+
+#define GODROP 0
+enum filter_action {
+GTW_DROP = 0,
+GTW_PASS,
+};
+
+struct mqtt_rule {
+ char topic[128];
+ char from[128];
+ enum filter_action action;
+ enum filter_dir dir;
+ int log;
+ int quick;
+};
+
+static size_t parsed_lines;
+%}
+
+%union {
+ int64_t number;
+ char *string;
+};
+
+%token ACTION IN OUT FROM QUICK LOG SOCKET
+%token TOPIC WORD
+%token ANY FROM
+%token SLASH HYPHEN
+%token <string> WORD SOCKET
+%token <number> NUMBER
+%type <number> ACTION DIR QUICK LOG
+%type <string> from topic
+
+
+%%
+
+ruleset: /* empty */
+ |
+ ruleset mqttrule
+ ;
+
+mqttrule : ACTION DIR topic from
+ {
+ parsed_lines++;
+ struct mqtt_rule r;
+ memset(&r, 0, sizeof(r));
+ r.action = $1;
+ r.dir = $2;
+ if ($3)
+ strlcpy(r.topic, $3, sizeof r.topic);
+ if ($4)
+ strlcpy(r.from, $4, sizeof r.from);
+
+ printf("%s %s <from> %s.\n", r.action == GTW_DROP ? "Drop" : "pass", r.topic[0]!=0 ? r.topic :"*", r.from[0]!=0 ? r.from : "<all>");
+ };
+
+topic : ANY {$$=NULL;}
+ | WORD {$$=$1;}
+ ;
+
+from : /* empty */ {$$=NULL;}
+ | FROM SOCKET {$$ = $2;}
+ ;
+%%
+
+void
+yyerror(msg)
+ char *msg;
+{
+ fprintf(stderr, "while parsing \"%s\"\n",
+ msg);
+
+ return;
+}
+
+int main( int argc, char **argv )
+{
+ ++argv, --argc; /* skip over program name */
+ if ( argc > 0 )
+ yyin = fopen( argv[0], "r" );
+ else
+ yyin = stdin;
+
+ yyparse();
+ printf("\n#%zu.\n", parsed_lines);
+
+}