'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