After writing a Flex standalone lexer, we are going to make it a little bit useful – adding parser, Bison. When Flex and Bison work together, standalone flex file needs some changes to cooperate with Bison, as you will see. Though the Bison looks much more weird than Flex, fortunately, we only cover the basic meaning of $$, $1 and etc, leaving recursion and conflict alone…
/* Flex + Bison to scan and parse the Text Itevad Protocol */ /* Flex - as scanner */ [root@localhost itevad2]# cat itevadTxtFlex.l /* Itevad Protocol Text Encoding Lexical Analyzer Example April 6, 2012 http://daveti.blog.com Reference: itevad.abnf NOTE: This is a Flex file NOT Lex! */ %{ #include <stdlib.h> #include <string.h> #include <stdio.h> #include "ItevadMessage.h" #include "itevadTxtBison.tab.h" %} /* Configure our lexer */ %option stack noyywrap case-insensitive %% "." { return DOT; } /* Dot */ "[" { return LSB; } /* Left square bracket */ "]" { return RSB; } /* Right square bracket */ "=" { return EQUAL; } /* Equal */ ":" { return COLON; } /* Colon */ "{" { return LBRKT; } /* Left brace */ "}" { return RBRKT; } /* Right brace */ "/" { return SLASH; } /* Slash */ "Itevad" { return ItevadToken; } /* Itevad Token */ "Transaction" { return TransToken; } /* Transaction Token */ "Reply" { return ReplyToken; } /* Reply Token */ "Ask" { return AskToken; } /* Ask Token */ "Answer" { return AnswerToken; } /* Answer Token */ "(.)*" { printf("Debug - quoted string: %sn", yytext); /* Delete the prefix and suffix double quotes */ char *content = strndup( (yytext+1), (strlen(yytext)-2)); yylval.stringVal = content; printf("flex-debug: quotedString: %sn", yylval.stringVal); return quotedString; } /* Quoted String */ [0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3} { /* IPv4 address handling here */ printf("Debug - IPv4 address: %sn", yytext); /* Try to convert the IPv4 format into octet string format * to help the parser for value assignment. * "49.49.49.49" --> "1111" * char '1' has ASCII code "49" * NOTE: we do have a bug here as NOT all the IPv4 address * could be translated into "xxxx" format string!!!!!!!! */ char *ipv4Address = strdup( yytext); char *octecString = calloc( 1, 5); int i = 0; unsigned char value = ''; char *headPtr = ipv4Address; char *ptr = ipv4Address; while ( *ptr != '') { if ( *ptr == '.') { *ptr = ''; value = (unsigned char)strtoul( headPtr, NULL, 10); i += snprintf( octecString+i, 5-i, "%c", value); headPtr = ptr + 1; } ptr++; } /* Convert the last octec char */ value = (unsigned char)strtoul( headPtr, NULL, 10); i += snprintf( octecString+i, 5-i, "%c", value); yylval.stringVal = octecString; printf("flex-debug: IPv4Address: %sn", yylval.stringVal); return IPv4Address; } /* IPv4 Address */ [0-9]+ { printf("Debug - number: %sn", yytext); yylval.ulongVal = strtoul(yytext, NULL, 10); printf("flex-debug: NUMBER: %lun", yylval.ulongVal); return NUMBER; } /* Number */ [ trnv] { /* Ignore */ } /* White spaces */ . { printf( "Decode failure at %cn", *yytext); } %% [root@localhost itevad2]#
/* Bison - as parser */ [root@localhost itevad2]# cat itevadTxtBison.y /* Itevad Protocol Text Encoding Sematic Analyzer Example April 9, 2012 http://daveti.blog.com Reference: itevad.abnf NOTE: This is a Bison file NOT Yacc! */ %{ #include <stdlib.h> #include <string.h> #include <stdio.h> #include "ItevadMessage.h" %} /* Token list */ %token SLASH LBRKT RBRKT COLON EQUAL NUMBER LSB RSB quotedString %token ItevadToken TransToken ReplyToken AskToken AnswerToken %token DOT IPv4Address /* Type list */ %type <ulongVal> version transactionId portNumber NUMBER %type <stringVal> quotedString IPv4Address %type <itevadMsgVal> itevadMessage %type <ipv4AddressVal> ipv4Address %type <messageBodyVal> messageBody %type <messageReqVal> messageRequest %type <messageRepVal> messageReply %type <askContentVal> askContent %type <answerContentVal> answerContent %union { unsigned long ulongVal; char * stringVal; ItevadMessage_t itevadMsgVal; IP4Address_t ipv4AddressVal; MessageBody_t messageBodyVal; MessageRequest_t messageReqVal; MessageReply_t messageRepVal; AskContent_t askContentVal; AnswerContent_t answerContentVal; } %start itevadMessage %% itevadMessage: ItevadToken SLASH version ipv4Address messageBody { $$.version = $3; $$.ip4Address = $4; $$.messageBody = $5; } ; version: NUMBER { printf("bison-debug: version: %lun", $1); $$ = $1; } ; ipv4Address: LSB IPv4Address RSB { printf("bison-debug: IPv4Address-$2: %sn", $2); OCTET_STRING_t myAddress; memset( &myAddress, 0, sizeof(OCTET_STRING_t)); if ( OCTET_STRING_fromString( &myAddress, $2) == -1) { yyerror( "OCTET_STRING_fromString failure for ip4Address.addressn"); } $$.address = myAddress; } | LSB IPv4Address RSB COLON portNumber { printf("bison-debug: IPv4Address-$2: %sn", $2); OCTET_STRING_t myAddress; memset( &myAddress, 0, sizeof(OCTET_STRING_t)); if ( OCTET_STRING_fromString( &myAddress, $2) == -1) { yyerror( "OCTET_STRING_fromString failure for ip4Address.addressn"); } $$.address = myAddress; $$.portNumber = &($5); } ; portNumber: NUMBER { printf("bison-debug: portNumber: %lun", $1); $$ = $1; } ; messageBody: messageRequest { $$.present = MessageBody_PR_messageRequest; $$.choice.messageRequest = $1; } | messageReply { $$.present = MessageBody_PR_messageReply; $$.choice.messageReply = $1; } ; messageRequest: TransToken EQUAL transactionId LBRKT askContent RBRKT { INTEGER_t myTransId; memset( &myTransId, 0, sizeof(INTEGER_t)); if ( asn_long2INTEGER( &myTransId, $3) == -1) { yyerror( "asn_long2INTEGER failure for transId in messageRequestn"); } $$.transactionId = myTransId; $$.askContent = $5; } ; messageReply: ReplyToken EQUAL transactionId LBRKT answerContent RBRKT { INTEGER_t myTransId; memset( &myTransId, 0, sizeof(INTEGER_t)); if ( asn_long2INTEGER( &myTransId, $3) == -1) { yyerror( "asn_long2INTEGER failure for transId in messageReplyn"); } $$.transactionId = myTransId; $$.answerContent = $5; } ; transactionId: NUMBER { printf("bison-debug: transactionId: %lun", $1); $$ = $1; } ; askContent: AskToken EQUAL quotedString { printf("bison-debug: askContent-quotedString-$3: %sn", $3); AskContent_t myAskContent; memset( &myAskContent, 0, sizeof(OCTET_STRING_t)); if ( OCTET_STRING_fromString( &myAskContent, $3) == -1) { yyerror( "OCTET_STRING_fromString failure for askContentn"); } $$ = myAskContent; } ; answerContent: AnswerToken EQUAL quotedString { printf("bison-debug: answerContent-quotedString-$3: %sn", $3); AnswerContent_t myAnswerContent; memset( &myAnswerContent, 0, sizeof(OCTET_STRING_t)); if ( OCTET_STRING_fromString( &myAnswerContent, $3) == -1) { yyerror( "OCTET_STRING_fromString failure for answerContentn"); } $$ = myAnswerContent; } ; %% int main( int argc, char **argv) { yyparse(); return 0; } int yyerror( const char *msg) { fprintf( stderr, "yyerror: %sn", msg); } [root@localhost itevad2]# /* Generate and run itevadFlexBisonBin */ [root@localhost itevad2]# bison -d itevadTxtBison.y [root@localhost itevad2]# flex itevadTxtFlex.l [root@localhost itevad2]# gcc -I. -o itevadTxtFlexBisonBin *.c -lfl itevadTxtFlex.l: In function 342200230yylex342200231: itevadTxtFlex.l:37: warning: incompatible implicit declaration of built-in function 342200230strndup342200231 TransactionId.c: In function 342200230TransactionId_constraint342200231: TransactionId.c:31: warning: this decimal constant is unsigned only in ISO C90 [root@localhost itevad2]# ./itevadTxtFlexBisonBin Itevad/1 [49.49.49.49]:7777 Transaction = 65535 { Ask = "who r you?" } Debug - number: 1 flex-debug: NUMBER: 1 bison-debug: version: 1 Debug - IPv4 address: 49.49.49.49 flex-debug: IPv4Address: 1111 Debug - number: 7777 flex-debug: NUMBER: 7777 bison-debug: portNumber: 7777 bison-debug: IPv4Address-$2: 1111 Debug - number: 65535 flex-debug: NUMBER: 65535 bison-debug: transactionId: 65535 Debug - quoted string: "who r you?" flex-debug: quotedString: who r you? bison-debug: askContent-quotedString-$3: who r you? [root@localhost itevad2]#