사칙연산과 변수명을 지원하는 간단한 계산기 예제
calc.l
%{
#include <string.h>
%}
EXIT [quit()|exit()]
MSG \"[a-zA-Z0-9_\-\$:; ]{0,128}\"
NAME [a-zA-Z][_\-\$a-zA-Z0-9]{0,19}
NUMBER [0-9]+
%%
{EXIT} { exit(0); }
{MSG} {
int len = yyleng - 2;
strncpy(yylval.sMsg, yytext + 1, len);
yylval.sMsg[len] = '\0';
return MSG;
}
{NAME} { strcpy(yylval.sVal, yytext); return NAME; }
{NUMBER} { yylval.iVal = atoi(yytext); return NUMBER; }
[ \t] ;
"?" { return PRINT; }
"\n" { return '\n'; }
"\r" { return '\n'; }
. { return yytext[0]; }
calc.y
%{
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
extern int yylex();
void yyerror(const char *s);
int getVarIndex(const char *name);
#define MAX_VARS 100
#define MAX_NAME_LEN 20
typedef struct {
char name[MAX_NAME_LEN + 1];
int value;
} Variable;
Variable vars[MAX_VARS];
int varCount = 0;
char **fileList;
unsigned int currentFile = 0;
unsigned int nFiles = 0;
%}
%union {
int iVal;
char sVal[40];
char sMsg[128];
}
%token <iVal> NUMBER
%token <sVal> NAME
%token <sMsg> MSG
%token PRINT
%type <iVal> expr
%left '-' '+'
%left '*' '/'
%nonassoc UMINUS
%%
stat_list:
| stat_list stat '\n'
;
stat:
| PRINT MSG NAME {
int idx = getVarIndex($3);
int value = (idx != -1) ? vars[idx].value : 0;
printf("%s %d\n", $2, value);
}
| PRINT MSG { printf("%s\n", $2); }
| NAME '=' expr {
int idx = getVarIndex($1);
if (idx != -1) {
vars[idx].value = $3;
}
}
| expr { printf("= %d\n", $1); }
;
expr: NUMBER { $$ = $1; }
| NAME {
int idx = getVarIndex($1);
$$ = (idx != -1) ? vars[idx].value : 0;
}
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr {
if ($3 == 0) {
yyerror("Divide by zero");
$$ = 0;
} else {
$$ = $1 / $3;
}
}
| '-' expr %prec UMINUS { $$ = -$2; }
| '(' expr ')' { $$ = $2; }
;
%%
#include "lex.yy.c"
void yyerror(const char *s){
fprintf(stderr, "Error: %s\n", s);
}
int getVarIndex(const char *name) {
for (int i = 0; i < varCount; i++) {
if (strcmp(name, vars[i].name) == 0) {
return i;
}
}
if (varCount < MAX_VARS) {
strcpy(vars[varCount].name, name);
vars[varCount].value = 0;
return varCount++;
}
yyerror("Variable table full");
return -1;
}
int main(int argc, char **argv) {
printf("Chobocho'c Calc V0.1\n");
FILE *file = NULL;
fileList = argv + 1;
nFiles = argc - 1;
if (argc == 2) {
currentFile = 1;
file = fopen(argv[1], "r");
if (!file) {
fprintf(stderr, "Could not open %s\n", argv[1]);
exit(1);
}
yyin = file;
}
return yyparse();
}
makefile
CC = gcc
LIBS = -lfl
LEX = flex
YACC = yacc
all: calc2
calc2: y.tab.c lex.yy.c
$(CC) -o calc2 y.tab.c $(LIBS)
y.tab.c: calc.y
$(YACC) -dv calc.y
lex.yy.c: calc.l
$(LEX) calc.l
clean:
rm y.tab.h
rm y.tab.c
rm y.tab.h.pch
rm lex.yy.c
rm calc2
Test Sample
10 + 20
rabbit = 20
dog = 30
cat = 10
chicken = 10
total_legs = dog * 4 + rabbit * 4 + chicken * 2 + cat * 4
? "Total legs:" total_legs
totalAnimals = rabbit + dog + cat + chicken
? "Total Animals:" totalAnimals
Test 결과