Skip to content

Instantly share code, notes, and snippets.

@gvx
Created October 15, 2012 17:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gvx/3893986 to your computer and use it in GitHub Desktop.
Save gvx/3893986 to your computer and use it in GitHub Desktop.
Thingy to learn how to use Flex and Bison
%{
#include "units.tab.c"
%}
%option noyywrap
int -?[0-9]+
%%
[ \t] /*empty*/
m { return METER; }
kg { return KILOGRAM; }
s { return SECOND; }
A { return AMPERE; }
K { return KELVIN; }
mol { return MOLE; }
cd { return CANDELA; }
[a-zA-Z]+ { (*(char**)&yylval) = strdup(yytext); return OTHER; }
\* { return MUL; }
\/ { return DIV; }
\^ { return POW; }
{int} { yylval.i[0] = atoi(yytext); return INT; }
\n { return 0; }
\( { return LPAREN; }
\) { return RPAREN; }
\: { return COLON; }
. { return 256; }
%%
%{
#include <stdio.h>
#define YYSTYPE struct ints
struct ints {
int i[7];
};
int yylex(void);
void yyerror(char const*);
void construct(YYSTYPE);
YYSTYPE init(int);
char *names[7] = {"m", "kg", "s", "A", "K", "mol", "cd"};
#define NNAMES 32
char *othernames[NNAMES];
YYSTYPE othervalues[NNAMES];
int namesused = 0;
%}
%token METER
%token KILOGRAM
%token SECOND
%token AMPERE
%token KELVIN
%token MOLE
%token CANDELA
%token MUL
%token DIV
%token POW
%token INT
%token LPAREN
%token RPAREN
%token OTHER
%token COLON
%left MUL DIV
%right POW
%%
line :
| OTHER COLON exp {
char *s = *(char**)&$1;
if (namesused < NNAMES)
{
othernames[namesused] = s;
othervalues[namesused++] = $3;
}
else
{
puts("No names left.");
}
$$ = $3;
}
| exp { construct( $1 ); }
| error '\n' { yyerrok; }
;
exp:
METER { $$ = init(0); }
| KILOGRAM { $$ = init(1); }
| SECOND { $$ = init(2); }
| AMPERE { $$ = init(3); }
| KELVIN { $$ = init(4); }
| MOLE { $$ = init(5); }
| CANDELA { $$ = init(6); }
| exp MUL exp {
int i;
for (i = 0; i < 7; i++)
$$.i[i] = $1.i[i] + $3.i[i];
}
| exp DIV exp {
int i;
for (i = 0; i < 7; i++)
$$.i[i] = $1.i[i] - $3.i[i];
}
| exp POW INT {
int i;
for (i = 0; i < 7; i++)
$$.i[i] = $1.i[i] * $3.i[0];
}
| LPAREN exp RPAREN { $$ = $2; }
| OTHER {
char *s = *(char**)&$1;
int i;
YYSTYPE unit_less = {0};
$$ = unit_less;
for (i = 0; i < namesused; i++)
{
if (!strcmp(othernames[i], s))
{
$$ = othervalues[i];
break;
}
}
free(s);
}
;
%%
void construct(YYSTYPE input)
{
int i;
int p = 0;
for (i = 0; i < 7; i++)
{
int j = input.i[i];
if (j)
{
if (p)
{
putchar(j > 0 ? '*' : (j=-j, '/'));
}
else if (j < 0)
{
fputs("1/", stdout);
j=-j;
}
p = 1;
if (j == 1)
{
fputs(names[i], stdout);
}
else
{
printf("%s^%d", names[i], j);
}
}
}
if (!p)
{
fputs("unit-less", stdout);
}
putchar(10);
}
int main (void)
{
while (1)
{
fputs("? ", stdout);
yyparse ();
}
}
void yyerror (char const *s)
{
fprintf (stderr, "%s\n", s);
}
inline YYSTYPE init(int j)
{
YYSTYPE ss = {0};
ss.i[j] = 1;
return ss;
}
@gvx
Copy link
Author

gvx commented Oct 15, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment