Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
GNU Bison
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==A complete reentrant parser example== {{how-to|section|date=September 2016}} The following example shows how to use Bison and flex to write a simple calculator program (only addition and multiplication) and a program for creating an [[abstract syntax tree]]. The next two files provide definition and implementation of the syntax tree functions. <syntaxhighlight lang="c"> /* * Expression.h * Definition of the structure used to build the syntax tree. */ #ifndef __EXPRESSION_H__ #define __EXPRESSION_H__ /** * @brief The operation type */ typedef enum tagEOperationType { eVALUE, eMULTIPLY, eADD } EOperationType; /** * @brief The expression structure */ typedef struct tagSExpression { EOperationType type; /* /< type of operation */ int value; /* /< valid only when type is eVALUE */ struct tagSExpression *left; /* /< left side of the tree */ struct tagSExpression *right; /* /< right side of the tree */ } SExpression; /** * @brief It creates an identifier * @param value The number value * @return The expression or NULL in case of no memory */ SExpression *createNumber(int value); /** * @brief It creates an operation * @param type The operation type * @param left The left operand * @param right The right operand * @return The expression or NULL in case of no memory */ SExpression *createOperation(EOperationType type, SExpression *left, SExpression *right); /** * @brief Deletes a expression * @param b The expression */ void deleteExpression(SExpression *b); #endif /* __EXPRESSION_H__ */ </syntaxhighlight> <syntaxhighlight lang="c"> /* * Expression.c * Implementation of functions used to build the syntax tree. */ #include "Expression.h" #include <stdlib.h> /** * @brief Allocates space for expression * @return The expression or NULL if not enough memory */ static SExpression *allocateExpression() { SExpression *b = (SExpression *)malloc(sizeof(SExpression)); if (b == NULL) return NULL; b->type = eVALUE; b->value = 0; b->left = NULL; b->right = NULL; return b; } SExpression *createNumber(int value) { SExpression *b = allocateExpression(); if (b == NULL) return NULL; b->type = eVALUE; b->value = value; return b; } SExpression *createOperation(EOperationType type, SExpression *left, SExpression *right) { SExpression *b = allocateExpression(); if (b == NULL) return NULL; b->type = type; b->left = left; b->right = right; return b; } void deleteExpression(SExpression *b) { if (b == NULL) return; deleteExpression(b->left); deleteExpression(b->right); free(b); } </syntaxhighlight> The tokens needed by the Bison parser will be generated using flex. <syntaxhighlight lang="c"> %{ /* * Lexer.l file * To generate the lexical analyzer run: "flex Lexer.l" */ #include "Expression.h" #include "Parser.h" #include <stdio.h> %} %option outfile="Lexer.c" header-file="Lexer.h" %option warn nodefault %option reentrant noyywrap never-interactive nounistd %option bison-bridge %% [ \r\n\t]* { continue; /* Skip blanks. */ } [0-9]+ { sscanf(yytext, "%d", &yylval->value); return TOKEN_NUMBER; } "*" { return TOKEN_STAR; } "+" { return TOKEN_PLUS; } "(" { return TOKEN_LPAREN; } ")" { return TOKEN_RPAREN; } . { continue; /* Ignore unexpected characters. */} %% int yyerror(SExpression **expression, yyscan_t scanner, const char *msg) { fprintf(stderr, "Error: %s\n", msg); return 0; } </syntaxhighlight> The names of the tokens are typically neutral: "TOKEN_PLUS" and "TOKEN_STAR", not "TOKEN_ADD" and "TOKEN_MULTIPLY". For instance if we were to support the unary "+" (as in "+1"), it would be wrong to name this "+" "TOKEN_ADD". In a language such as C, "int *ptr" denotes the definition of a pointer, not a product: it would be wrong to name this "*" "TOKEN_MULTIPLY". Since the tokens are provided by flex we must provide the means to communicate between the [[Lexical analysis|parser and the lexer]].<ref name="flex-bison-bridge">[http://flex.sourceforge.net/manual/Bison-Bridge.html Flex Manual: C Scanners with Bison Parsers] {{webarchive|url=https://web.archive.org/web/20101217042916/http://flex.sourceforge.net/manual/Bison-Bridge.html |date=2010-12-17 }}</ref> The data type used for communication, ''YYSTYPE'', is set using Bison ''%union'' declaration. Since in this sample we use the reentrant version of both flex and yacc we are forced to provide parameters for the ''yylex'' function, when called from ''yyparse''.<ref name="flex-bison-bridge" /> This is done through Bison ''%lex-param'' and ''%parse-param'' declarations.<ref name="pure-calling-conventions">[https://www.gnu.org/software/bison/manual/html_node/Pure-Calling.html Bison Manual: Calling Conventions for Pure Parsers]</ref> <syntaxhighlight lang="c"> %{ /* * Parser.y file * To generate the parser run: "bison Parser.y" */ #include "Expression.h" #include "Parser.h" #include "Lexer.h" // reference the implementation provided in Lexer.l int yyerror(SExpression **expression, yyscan_t scanner, const char *msg); %} %code requires { typedef void* yyscan_t; } %output "Parser.c" %defines "Parser.h" %define api.pure %lex-param { yyscan_t scanner } %parse-param { SExpression **expression } %parse-param { yyscan_t scanner } %union { int value; SExpression *expression; } %token TOKEN_LPAREN "(" %token TOKEN_RPAREN ")" %token TOKEN_PLUS "+" %token TOKEN_STAR "*" %token <value> TOKEN_NUMBER "number" %type <expression> expr /* Precedence (increasing) and associativity: a+b+c is (a+b)+c: left associativity a+b*c is a+(b*c): the precedence of "*" is higher than that of "+". */ %left "+" %left "*" %% input : expr { *expression = $1; } ; expr : expr[L] "+" expr[R] { $$ = createOperation( eADD, $L, $R ); } | expr[L] "*" expr[R] { $$ = createOperation( eMULTIPLY, $L, $R ); } | "(" expr[E] ")" { $$ = $E; } | "number" { $$ = createNumber($1); } ; %% </syntaxhighlight> The code needed to obtain the syntax tree using the parser generated by Bison and the scanner generated by flex is the following. <syntaxhighlight lang="c"> /* * main.c file */ #include "Expression.h" #include "Parser.h" #include "Lexer.h" #include <stdio.h> int yyparse(SExpression **expression, yyscan_t scanner); SExpression *getAST(const char *expr) { SExpression *expression; yyscan_t scanner; YY_BUFFER_STATE state; if (yylex_init(&scanner)) { /* could not initialize */ return NULL; } state = yy_scan_string(expr, scanner); if (yyparse(&expression, scanner)) { /* error parsing */ return NULL; } yy_delete_buffer(state, scanner); yylex_destroy(scanner); return expression; } int evaluate(SExpression *e) { switch (e->type) { case eVALUE: return e->value; case eMULTIPLY: return evaluate(e->left) * evaluate(e->right); case eADD: return evaluate(e->left) + evaluate(e->right); default: /* should not be here */ return 0; } } int main(void) { char test[] = " 4 + 2*10 + 3*( 5 + 1 )"; SExpression *e = getAST(test); int result = evaluate(e); printf("Result of '%s' is %d\n", test, result); deleteExpression(e); return 0; } </syntaxhighlight> A simple makefile to build the project is the following. <syntaxhighlight lang="make"> # Makefile FILES = Lexer.c Parser.c Expression.c main.c CC = g++ CFLAGS = -g -ansi test: $(FILES) $(CC) $(CFLAGS) $(FILES) -o test Lexer.c: Lexer.l flex Lexer.l Parser.c: Parser.y Lexer.c bison Parser.y clean: rm -f *.o *~ Lexer.c Lexer.h Parser.c Parser.h test </syntaxhighlight>
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)