Calculator Example
A complete calculator supporting arithmetic operations with proper precedence.
Lexer Specification (calc.l)
%{
/* Calculator Lexer */
%}
%%
[0-9]+ { return NUMBER; }
[0-9]+\.[0-9]+ { return FLOAT; }
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return TIMES; }
"/" { return DIVIDE; }
"%" { return MOD; }
"^" { return POWER; }
"(" { return LPAREN; }
")" { return RPAREN; }
[ \t]+ { /* skip whitespace */ }
\n { return NEWLINE; }
. { return ERROR; }
%%
Grammar Specification (calc.y)
%{
/* Calculator Parser */
#include <stdio.h>
#include <math.h>
%}
%union {
double dval;
}
%token <dval> NUMBER FLOAT
%token PLUS MINUS TIMES DIVIDE MOD POWER
%token LPAREN RPAREN NEWLINE ERROR
%type <dval> expr term factor primary
%left PLUS MINUS
%left TIMES DIVIDE MOD
%right POWER
%right UMINUS
%%
input:
/* empty */
| input line
;
line:
NEWLINE
| expr NEWLINE { printf("= %g\n", $1); }
| error NEWLINE { yyerrok; }
;
expr:
expr PLUS term { $$ = $1 + $3; }
| expr MINUS term { $$ = $1 - $3; }
| term { $$ = $1; }
;
term:
term TIMES factor { $$ = $1 * $3; }
| term DIVIDE factor {
if ($3 == 0) {
yyerror("division by zero");
$$ = 0;
} else {
$$ = $1 / $3;
}
}
| term MOD factor { $$ = fmod($1, $3); }
| factor { $$ = $1; }
;
factor:
primary POWER factor { $$ = pow($1, $3); }
| primary { $$ = $1; }
;
primary:
NUMBER { $$ = $1; }
| FLOAT { $$ = $1; }
| LPAREN expr RPAREN { $$ = $2; }
| MINUS primary %prec UMINUS { $$ = -$2; }
;
%%
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
Generate Code
openlexer gen-lexer --lexer calc.l --lang c --output ./
openlexer gen-parser --parser calc.y --lang c --output ./
Main Program (main.c)
#include <stdio.h>
#include <string.h>
/* Include generated code */
#include "lexer.c"
#include "parser.c"
int main() {
char line[1024];
printf("Calculator (type expressions, Ctrl+C to exit)\n");
while (1) {
printf("> ");
fflush(stdout);
if (fgets(line, sizeof(line), stdin) == NULL) {
break;
}
lex_init(line);
yyparse();
}
return 0;
}
Build and Run
gcc -o calc main.c -lm -Wall
./calc
Example Session
Calculator (type expressions, Ctrl+C to exit)
> 3 + 4
= 7
> 2 * 3 + 4
= 10
> 2 + 3 * 4
= 14
> (2 + 3) * 4
= 20
> 2 ^ 3 ^ 2
= 512
> -5 + 3
= -2
> 10 / 0
Error: division by zero
= 0
Notes
- Power (
^) is right-associative:2^3^2 = 2^9 = 512 - Unary minus has highest precedence
- Parentheses override precedence
- Division by zero is caught with error message