我该如何重写程序,这样我就不必调用`flex`而是仅调用`bison`和`cc`了? [英] How can I rewrite the programs, so that I don't have to call `flex` but only call `bison` and `cc`?

查看:127
本文介绍了我该如何重写程序,这样我就不必调用`flex`而是仅调用`bison`和`cc`了?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经有一个基于bison和flex的计算器程序,该程序从命令行参数中获取输入.

I already have a calculator program based on bison and flex which takes input from command line arguments.

现在我该如何重写程序,这样我就不必在构建过程中调用flex而只调用bisoncc了? (实现与 .stackexchange.com/questions/499190/where-is-the-of-official-documentation-debian-package-iproute-doc#comment919875_499225 ).

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); }
%%


更新:

我试图按照回复中的建议进行操作,请参阅下面的修改后的代码.在main()中,为什么在printf("argv[%d]: %s ", n, argv[n])之前调用yyerror()?不仅yyerror()仅由yyparse()调用,而且yyparse仅在main()main()中的printf("argv[%d]: %s ", n, argv[n])之后被调用.

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);
}

推荐答案

There is a basic implementation of a lexical scanner in the examples section of the bison manual. (Slightly less basic versions are later in the manual.)

这不会直接为您提供帮助,因为它基于fscanf,这意味着它适用于输入流.大多数C库包含使您可以将字符串视为FILE*的函数(例如,参见Posix标准

That won't help you directly because it is based on fscanf, which means that it works on an input stream. Most C libraries contain functions which let you treat a character string as a FILE* (see, for example, the Posix standard fmemopen). Failing that, you'd have to replace the getc and scanf calls with string based alternatives, which means you will need to keep track of a buffer and input pointer somewhere. strtoul (or strtod) will prove useful because the second argument helps you keep track of how much of the string was used by the number.

这篇关于我该如何重写程序,这样我就不必调用`flex`而是仅调用`bison`和`cc`了?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆