I already have a calculator program based on bison and flex which takes input from command line arguments.
Now how can I rewrite the programs, so that I don't have to call flex
but only call bison
and cc
during building process? (Achieve something similar to https://unix.stackexchange.com/questions/499190/where-is-the-official-documentation-debian-package-iproute-doc#comment919875_499225).
$ ./fb1-5 '1+3'
= 4
Makefile:
fb1-5: fb1-5.l fb1-5.y
bison -d fb1-5.y
flex fb1-5.l
cc -o $@ fb1-5.tab.c lex.yy.c -lfl
fb1-5.y
/* simplest version of calculator */
%{
# include <stdio.h>
%}
/* declare tokens */
%token NUMBER
%token ADD SUB MUL DIV ABS
%token OP CP
%%
calclist: /* nothing */
| calclist exp { printf("= %d\n> ", $2); }
;
exp: factor
| exp ADD exp { $$ = $1 + $3; }
| exp SUB factor { $$ = $1 - $3; }
| exp ABS factor { $$ = $1 | $3; }
;
factor: term
| factor MUL term { $$ = $1 * $3; }
| factor DIV term { $$ = $1 / $3; }
;
term: NUMBER
| ABS term { $$ = $2 >= 0? $2 : - $2; }
| OP exp CP { $$ = $2; }
;
%%
int main(int argc, char** argv)
{
// printf("> ");
if(argc > 1) {
if(argv[1]){
yy_scan_string(argv[1]);
}
}
yyparse();
return 0;
}
yyerror(char *s)
{
fprintf(stderr, "error: %s\n", s);
}
fb1-5.l:
/* recognize tokens for the calculator and print them out */
%{
# include "fb1-5.tab.h"
%}
%%
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }
"/" { return DIV; }
"|" { return ABS; }
"(" { return OP; }
")" { return CP; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
"//".*
[ \t] { /* ignore white space */ }
. { yyerror("Mystery character %c\n", *yytext); }
%%
Update:
I tried to follow the advice in the reply, see the modified code below. in main()
, why is yyerror()
called before printf("argv[%d]: %s ", n, argv[n])
? Isn't yyerror()
called only by yyparse()
, and isn't yyparse
only called after printf("argv[%d]: %s ", n, argv[n])
in main()
in main()
.
$ ./fb1-5 2*4
2*4error: �
= 8
fb1-5.y
:
/* simplest version of calculator */
%{
# include <stdio.h>
FILE * fin;
int yylex (void);
void yyerror(char *s);
%}
/* declare tokens */
%token NUMBER
%token ADD SUB MUL DIV ABS
%token OP CP
%%
calclist: /* nothing */
| calclist exp { printf("= %d\n", $2); }
;
exp: factor
| exp ADD exp { $$ = $1 + $3; }
| exp SUB factor { $$ = $1 - $3; }
| exp ABS factor { $$ = $1 | $3; }
;
factor: term
| factor MUL term { $$ = $1 * $3; }
| factor DIV term { $$ = $1 / $3; }
;
term: NUMBER
| ABS term { $$ = $2 >= 0? $2 : - $2; }
| OP exp CP { $$ = $2; }
;
%%
/* The lexical analyzer returns a double floating point
number on the stack and the token NUM, or the numeric code
of the character read if not a number. It skips all blanks
and tabs, and returns 0 for end-of-input. */
#include <ctype.h>
#include <string.h>
int yylex (void)
{
char c;
/* Skip white space. */
while ((c = getc(fin)) == ' ' || c == '\t'){
continue;
}
// printf("%s", &c);
/* Process numbers. */
if (c == '.' || isdigit (c))
{
ungetc(c, fin);
fscanf (fin, "%d", &yylval);
return NUMBER;
}
/* Process addition. */
if (c == '+')
{
return ADD;
}
/* Process sub. */
if (c == '-')
{
return SUB;
}
/* Process mult. */
if (c == '*')
{
return MUL;
}
/* Process division. */
if (c == '/')
{
return DIV;
}
/* Process absolute. */
if (c == '|')
{
return ABS;
}
/* Process left paren. */
if (c == '(')
{
return OP;
}
/* Process right paren. */
if (c == ')')
{
return CP;
}
/* Return a single char. */
yyerror(&c);
return c;
}
int main(int argc, char** argv)
{
// evaluate each command line arg as an arithmetic expression
int n=1;
while (n < argc) {
if(argv[n]){
// yy_scan_string(argv[n]);
// fin = stdin;
fin = fmemopen(argv[n], strlen (argv[n]), "r");
printf("%s ",argv[n]);
fflush(stdout);
yyparse();
}
n++;
}
return 0;
}
void yyerror(char *s)
{
fprintf(stderr, "error: %s\n", s);
}
flex
reads the input.bison
doesn't: it just callsflex
. You don't have to do anything tobison
to take the input from the command line. The grammar has nothing do with it either. Removingflex
doesn't accomplish your objective. Your question doesn't make sense. – Appetencyyy_scan_string
function to read from a string instead of a file... – Flashover