|
| 1 | +# Lex and Yacc: Simple Calculator Example |
| 2 | + |
| 3 | +## Introduction |
| 4 | +Lex and Yacc are powerful tools used to generate lexical analyzers (scanners) and parsers. In this guide, we will create a simple calculator using Lex (Flex) and Yacc (Bison) that can evaluate expressions with addition, subtraction, multiplication, and variable assignment. |
| 5 | + |
| 6 | +## Prerequisites |
| 7 | +Ensure you have `flex` and `bison` installed: |
| 8 | + |
| 9 | +### On Linux/macOS: |
| 10 | +```sh |
| 11 | +sudo apt install flex bison # Ubuntu/Debian |
| 12 | +sudo pacman -S flex bison # Arch Linux |
| 13 | +brew install flex bison # macOS (Homebrew) |
| 14 | +``` |
| 15 | + |
| 16 | +### On Windows: |
| 17 | +Use MinGW or Cygwin to install `flex` and `bison`. |
| 18 | + |
| 19 | +## Understanding Lex and Yacc Internal Functions |
| 20 | +Lex and Yacc use several internal functions that play key roles in lexical analysis and parsing: |
| 21 | + |
| 22 | +- **`yyparse()`**: This function is automatically generated by Yacc (Bison). It drives the parsing process by calling `yylex()` to fetch tokens and applying grammar rules. |
| 23 | +- **`yylex()`**: This function is generated by Lex (Flex). It scans the input text and returns tokens to the parser. It is responsible for pattern matching based on the rules defined in the `.l` file. |
| 24 | +- **`yyerror(const char *s)`**: This function is called by `yyparse()` whenever a syntax error occurs. It prints an error message, allowing debugging of incorrect input. |
| 25 | + |
| 26 | +## Writing the Lex Scanner |
| 27 | +Create a file named `scanner.l` with the following content: |
| 28 | + |
| 29 | +```c |
| 30 | +%{ |
| 31 | +#include "y.tab.h" |
| 32 | +#include <stdlib.h> |
| 33 | +extern int yylval; |
| 34 | +%} |
| 35 | + |
| 36 | +%option noyywrap |
| 37 | + |
| 38 | +%% |
| 39 | +[0-9]+ { yylval = atoi(yytext); return NUMBER; } |
| 40 | +[a-z] { yylval = yytext[0]; return NAME; } |
| 41 | +[ \t] ; /* Ignore whitespace */ |
| 42 | +\n return 0; /* Logical EOF */ |
| 43 | +. return yytext[0]; |
| 44 | +%% |
| 45 | +``` |
| 46 | +
|
| 47 | +## Writing the Yacc Parser |
| 48 | +Create a file named `parser.y`: |
| 49 | +
|
| 50 | +```c |
| 51 | +%{ |
| 52 | +#include <stdio.h> |
| 53 | +int yylex(); |
| 54 | +void yyerror (char const *s) { |
| 55 | + fprintf (stderr, "%s\n", s); |
| 56 | +} |
| 57 | +%} |
| 58 | +
|
| 59 | +%token NAME NUMBER |
| 60 | +
|
| 61 | +%% |
| 62 | +
|
| 63 | +statement: NAME '=' expression { printf("%c = %d\n", $1, $3); } |
| 64 | + | expression { printf("= %d\n", $1); } |
| 65 | + ; |
| 66 | +
|
| 67 | +expression: expression '+' NUMBER { $$ = $1 + $3; } |
| 68 | + | expression '-' NUMBER { $$ = $1 - $3; } |
| 69 | + | expression '*' NUMBER { $$ = $1 * $3; } |
| 70 | + | '(' expression ')' { $$ = $2; } |
| 71 | + | NUMBER { $$ = $1; } |
| 72 | + ; |
| 73 | +
|
| 74 | +%% |
| 75 | +
|
| 76 | +int main() { |
| 77 | + yyparse(); |
| 78 | + return 0; |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +## Compiling and Running the Calculator |
| 83 | +Run the following commands: |
| 84 | + |
| 85 | +```sh |
| 86 | +flex scanner.l |
| 87 | +bison -d parser.y |
| 88 | +gcc lex.yy.c parser.tab.c -o calculator -lm |
| 89 | +./calculator |
| 90 | +``` |
| 91 | + |
| 92 | +### Example Input/Output: |
| 93 | +``` |
| 94 | +x = 3 + 5 |
| 95 | +x = 8 |
| 96 | +5 * 2 |
| 97 | += 10 |
| 98 | +``` |
| 99 | + |
| 100 | +## Extending the Calculator |
| 101 | +- Add division (`/` operator) |
| 102 | +- Implement variable storage |
| 103 | +- Support floating-point numbers |
| 104 | + |
| 105 | +This guide provides a basic starting point for learning Lex and Yacc. Experiment and extend it to build more complex parsers! |
| 106 | + |
0 commit comments