Ulm I

ImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImage

Categories: Uncategorized

Ulm Church

ImageImageImageImageImageImageImageImageImageImageImageImageImage

Categories: Uncategorized

Travel to Frankfurt

ImageImageImageImageImageImageImageImageImageImageImageImageImageImage

Categories: Uncategorized

Build a reentrant string parser with bison and flex

Build a reentrant string parser with bison and flex

I wrote a runable reentrant string parser demo in bison + flex. Comment me for any problem.

Download these files into a folder of a Linux system and execute commands

 make
 ./a.out

to see the result. Main.c contains some test code for the scanner. Reading the source code, you will know how to use flex and bison to build a reetrant string scanner.

Platform version:

 bison (GNU Bison) 2.4.1
 flex 2.5.35
 gcc (GCC) 4.6.2
 Linux 3.3.6 SMP x86_64

++++++ calc.h begin ++++++
#ifndef __RS_HEADER_INCLUDED__
#define __RS_HEADER_INCLUDED__

#define RS_STR_MAX 255

typedef struct rs_data {
 struct rs_data * param_next;
 int len;
 union {
  char buffer[RS_STR_MAX + 1];
  char * pointer;
 } data;
} rs_data;

typedef rs_data * (* rs_cb)(rs_data *);

extern rs_data rs_exec(rs_data * id, rs_data * param_list);

#ifdef __IN_RS_BISON__
extern int rs_lex (void *, void *);
#endif /* __IN_RS_BISON__ */

#endif /* __RS_HEADER_INCLUDED__ */
++++++ calc.h end ++++++

++++++ exec.c begin ++++++
#define NO_CARE_NET

#include <string.h>

#include “calc.h”

/* invoked by the parser */
/* find proper cb to handle the input parameter string */
rs_data rs_exec(rs_data * id, rs_data * param_list)
{
#if 0
 printf(“id: %s\n”, id->data.buffer);
 if (param_list) {
  printf(“param: %s\n”, param_list->data.buffer);
 }
#endif
 return * id;
}

/* eof */
++++++ exec.c end ++++++

++++++ lex.l begin ++++++
%option prefix=”rs_”
%option noinput
%option nounput
%option bison-bridge
%option reentrant
%option noyywrap

%{

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include “calc.h”
#include “parser.h”

#define YY_NO_UNPUT

static void smd_calc_get_string_token(char * d, int * len, const char * s)     {
 int i;
 int after_slash = 0;
 int w = 0;

 for (i = 0; s[i]; i ++) {
  if (after_slash) {
   if (‘”‘ == s[i]) {
    d[w] = ‘”‘;
    w ++;
    after_slash = 0;
   }
   else if (‘\\’ == s[i]) {
    d[w] = ‘\\’;
    w ++;
   }
   else {
    d[w] = ‘\\’;
    w ++;
    d[w] = s[i];
    w ++;
    after_slash = 0;
   }
  }
  else {
   if (‘\\’ == s[i]) {
    after_slash = 1;
   }
   else {
    d[w] = s[i];
    w ++;
   }
  }
 }

 d[w] = ”;

 *len = w;

 return;
}

%}

%%

[ \t\n] { ; }

“,”  { return COMMA_TOKEN;  }
“;”  { return SEMICOLON_TOKEN; }
“(”  { return OPEN_TOKEN;  }
“)”  { return CLOSE_TOKEN;  }

[a-zA-Z_]+[a-zA-Z_0-9]* {
 /* match id */
 int l;

 l = strlen(yytext);
 if (l >= RS_STR_MAX) {
  return ERROR_TOKEN;
 }
 strcpy(yylval->calc.data.buffer, yytext);
 yylval->calc.len = l;
 return ID_TOKEN;
}

\”([^\”\\]?(\\.)?(\\\n)?)*\” {
 /* match string */
 int l;

 l = strlen(yytext);
 if (l >= RS_STR_MAX) {
  return ERROR_TOKEN;
 }
 yytext[l – 1] = ”;
 smd_calc_get_string_token(
   yylval->calc.data.buffer
   , &(yylval->calc.len)
   , yytext + 1
   );
 return STRING_TOKEN;
}

.  { return ERROR_TOKEN; }

%%

/* invoke by the packet receiver, start to parse a string */
/* s: string base address */
/* len: strlen() result of the string */
/* return 0 for success, -1 for parse error */
int smd_calc(char * s, int len) {
 YY_BUFFER_STATE yybs;
 yyscan_t scanner;
 int r;

 /* no parser status maintance in this function, the bison generated */
 /* source code can do that */

 /* redirect flex input buffer */
 r = rs_lex_init(&scanner);     /* flex */
 if (r) {
  return -1;
 }

 yybs = yy_scan_bytes(s, len, scanner);  /* flex */
 yy_switch_to_buffer(yybs, scanner);   /* flex */

 /* parser the input buffer */
 r = rs_pull_parse(NULL, scanner);   /* bison */

 /* detach flex & bison instance */
 yy_delete_buffer(yybs, scanner);   /* flex */
 rs_lex_destroy(scanner);     /* flex */

 /* return number trnaslate */
 if (r) {
  r = -1;
 }

 return r;
}

/* eof */
++++++ lex.l end ++++++

++++++ main.c begin ++++++
#include “calc.h”
#include “parser.h”

#include <stdio.h>
#include <string.h>

typedef struct pair_t {
 int expect;
 char * input_string;
} pair_t;

static pair_t input[] = {
 {0,  “hello();”},
 {0,  “;”},
 {0,  “; ; ;”},
 {-1, “()”},
 {-1, “hello”},
 {-1, “\”hello\””},
 {-1, “(\”hello\”)”},
 {-1, “d(\”hello\”)”},
 {0,  “d(\”hello\”);”},
 {-1, “d(\”hello\”,);”},
 {-1, “d(\”hello\”,ddf);”},
 {-1, “d(\”hello\”,ddf();”},
 {0,  “d(\”hello\”,ddf());”},
 {0,  “d(\”hello\”, \”\”);”},
 {0,  “d(\”hello\”, \”dfasdf\”);”},
 {-1, “d(\”hello\”, \”dfasdf);”},
 {-1, “d(\”hello\” \”dfasdf\”);”},
};

int main(int argc, char ** argv) {
 int i;
 int r;

 for (i = 0; i < sizeof(input) / sizeof(input[0]); i ++) {
  printf(“## %d: \”%s\”\n”, i, input[i].input_string);
  r = smd_calc(
    input[i].input_string
    , strlen(input[i].input_string)
    );

  if (r == input[i].expect) {
  }
  else {
   printf(“Wrong, return %d, should be %d : x\n”
     , r
     , input[i].expect
     );
  }
 }

 return 0;
}

/* eof */
++++++ main.c end ++++++

++++++ parser.y begin ++++++
/* vi: set sw=4 ts=4: */

%define api.pure
%define api.push_pull “both”
%lex-param  {void * scanner}
%parse-param {void * scanner}

%{

#define __IN_RS_BISON__

#include <stdio.h>
#include “calc.h”

int rs_error(void * dumy, char * s) {
 return 0;
}

%}

%union {
 rs_data calc;
}

%token COMMA_TOKEN SEMICOLON_TOKEN
%token OPEN_TOKEN CLOSE_TOKEN
%token ID_TOKEN STRING_TOKEN
%token ERROR_TOKEN

%type <calc> ID_TOKEN STRING_TOKEN
%type <calc> function_call parameter_list parameter

%%

input: statements;

statements:
 /* nothing */
 | statements statement
 ;

statement: function_call SEMICOLON_TOKEN
 | SEMICOLON_TOKEN
 ;

function_call:
  ID_TOKEN OPEN_TOKEN parameter_list CLOSE_TOKEN {
  $$ = rs_exec(&$1, &$3);
 }
 | ID_TOKEN OPEN_TOKEN CLOSE_TOKEN {
  $$ = rs_exec(&$1, NULL);
 }
 ;

parameter_list: parameter { $$ = $1; }
 | parameter_list COMMA_TOKEN parameter
  { $1.param_next = &$3; $$ = $1; }
 ;

parameter: function_call { $1.param_next = NULL; $$ = $1; }
 | STRING_TOKEN  { $1.param_next = NULL; $$ = $1; }
 ;
 

%%

/* eof */
++++++ parser.y end ++++++

++++++ Makefile begin ++++++
TARGET := a.out
OBJS := parser.o lex.o exec.o main.o
CC := gcc -I../../
BISON := bison
FLEX := flex

all: $(TARGET)

parser.o: parser.c
 @$(CC) -c $< -o $@

parser.c: parser.y
 @$(BISON) -d -p rs_ $< -o $@ $(BISONOPT)

$(TARGET): $(OBJS)
 @$(CC) $(OBJS) -o $@

lex.o: lex.c
 @$(CC) -c $< -o $@

lex.c: lex.l
 @$(FLEX) -o$@ $<

exec.o: exec.c
 @$(CC) -c $< -o $@

main.o: main.c
 @$(CC) -c $< -o $@

clean:
 -@rm -f $(OBJS) $(TARGET) parser.h parser.c lex.c

# eof
++++++ Makefile end ++++++

Categories: Uncategorized

Qingdao

 

Categories: Landscope

Guojielou Alley II

Categories: Uncategorized

Guojielou Alley

Categories: Portrait