itevad – How to write your own protocol and its stack – part 8

Previous_Part_7

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]#

About daveti

Interested in kernel hacking, compilers, machine learning and guitars.
This entry was posted in Dave's Tools, H.248/MEGACO/EGCP, Programming, Stuff about Compiler and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.