'Flex/Bison - match random data
I'm implementing a custom CLI with flex/Bison. My sample command looks like this:
zone 3 set field some_value
where I can match keywords like zone and set, and I can match string in the place of field. However, at some_value can be anything, including keywords like 'zone'. The problem is that flex recognizes keywords like 'zone' in the position in some_value.
Moreover, I want spaces and any printing character in place of some_value.
This is my flex:
%option noyywrap nounput noinput
%option reentrant bison-bridge
digit [0-9]
integer [+-]?{digit}+
real [+-]?({digit}+[.]{digit}*)|({digit}*[.]{digit}+)
exp [+-]?({integer}|{real})[eE]-?{integer}
alpha [a-z][A-Z]+
%%
/*subsystems*/
zone {
return (cmd_sys_zone);
}
device {
return (cmd_sys_device);
}
system {
return (cmd_sys_system);
}
help {
return (cmd_sys_help);
}
ver|version {
return (cmd_sys_ver);
}
/*actions*/
set {return (cmd_action_set);}
get {return (cmd_action_get);}
start {return (cmd_action_start);}
stop {return (cmd_action_stop);}
/*Primitives*/
{integer} {
yylval->number = strtoul(yytext, NULL, 0);
return(cmd_num);
}
{real} {
yylval->real = strtod(yytext, NULL);
return(cmd_real);
}
{exp} {
yylval->real = strtod(yytext, NULL);
return(cmd_real);
}
[[:alpha:]]* {
yylval->name = strdup(yytext);
return(cmd_string);
}
[\n\r] {
}
[[:space:]]+ {
//return(cmd_space);
} /* Do nothing */
. {
yylval->name = strdup(yytext);
showError();
// return(cmd_other);
}
%%
void showError(){
printf("Other input ");
}
int cmd_parse(cmd_t *command) {
yyscan_t scanner;
YY_BUFFER_STATE buffer;
int ret_val;
ret_val = 0;
if ((ret_val = yylex_init(&scanner)) != 0) {
goto exit_point;
}
buffer = yy_scan_buffer(command->buffer, command->len, scanner);
yyparse(command, scanner);
yy_delete_buffer(buffer, scanner);
yylex_destroy(scanner);
exit_point:
return 0;
}
This is my bision:
%{
#include <stdio.h>
#include <stdint.h>
#include "cmd.h"
#include "hmd.tab.h"
int yylex();
int yyerror(void *userdata, void *scanner, const char *s);
%}
%define api.pure
%define parse.error verbose
/*System tokens*/
%token cmd_sys_zone cmd_sys_device cmd_sys_system cmd_sys_ver cmd_sys_help
%token cmd_num cmd_string cmd_real
/*Action tokens*/
%token cmd_action_set cmd_action_get cmd_action_start cmd_action_stop
%type <number> cmd_num
%type <real> cmd_real
%type <name> cmd_string
%destructor {
if ($$ == NULL) {
free($$);
}
} <name>
%union {
char *name;
uint64_t number;
double real;
}
%parse-param {void *user_data}
%param {void *scanner}
%%
prog:
stmts
;
stmts:
| stmt stmts
stmt:
cmd_sys_zone cmd_num cmd_action_set cmd_string cmd_string {
cmd_zone_set(user_data, $2, $4, $5);
cmd_free($4);
cmd_free($5);
} |
cmd_sys_zone cmd_num cmd_action_get cmd_string {
cmd_zone_get($2, $4);
cmd_free($4);
} |
cmd_sys_ver {
cmd_ver(user_data);
} |
cmd_sys_help {
cmd_help();
}
%%
int yyerror(void *userdata, void *scanner, const char *s)
{
(void) scanner;
(void) userdata;
printf("Syntax Error on line %s\n", s);
return 0;
}
I tried matching .*$, because my data always at the end of input, but that isn't working.
Solution 1:[1]
You have to use 'start states'. That is a feature of Flex.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Lev |
