lemon之Hello World(续3)

来源:互联网 发布:suse linux双网卡绑定 编辑:程序博客网 时间:2024/06/04 01:37

        之前几篇短文的主函数都是写死了代码,没有用户交互过程。现在,咱们利用flex和lemon结合,

制作一个简单的计算器。之所以说简单,是因为只含有+-*/四个运算,并且还不支持括号。

         相关文件如下:

1、数据结构exampleDef.h

#ifndef __EXAMPLE_DEF_H__
#define __EXAMPLE_DEF_H__

//lemon token struct
struct Token {
  double value;
  unsigned n;
};

//flex
typedef union {
  double    dval;
  struct symtab *symp;
} yystype;

# define YYSTYPE yystype
# define YYSTYPE_IS_TRIVIAL 1

/* extern YYSTYPE yylval; */
YYSTYPE yylval;

#endif

2、lemon语法规则文件example.y

%include {  
#include <iostream> 
#include "example.h"
#include "exampleDef.h"
/*
void destructor(Token t) {
    std::cout << "destructor.value=" << t.value << std::endl;
    std::cout << "destructor.n=" << t.n << std::endl;
}
*/

%token_prefix TOKEN_

%token_type {Token} 
// %token_destructor {destructor($$);}

%type expr {Token}
%type NUM {Token}
%left PLUS MINUS.  
%left DIVIDE TIMES. 
%syntax_error { 
  std::cout << "Syntax error!" << std::endl; 
}  
main ::= in.
in ::= .
in ::= in program NEWLINE.

program ::= expr(A).   {
    std::cout << "Result=" << A.value << std::endl;
//    std::cout << "Result.n=" << A.n << std::endl;
}
expr(A) ::= expr(B) MINUS  expr(C).   {
    A.value = B.value  - C.value ;
    A.n = B.n + 1 + C.n + 1;

expr(A) ::= expr(B) PLUS  expr(C).   {
    A.value  = B.value  + C.value ;
    A.n = B.n + 1 + C.n + 1;

expr(A) ::= expr(B) TIMES  expr(C).   {
    A.value  = B.value  * C.value ;
    A.n = B.n + 1 + C.n + 1;

expr(A) ::= expr(B) DIVIDE expr(C).  {
    if(C.value != 0){
        A.value  = B.value  / C.value ;
        A.n = B.n + 1 + C.n + 1;
    }else{
        std::cout << "divide by zero" << std::endl;
    }
}  /* end of DIVIDE */

expr(A) ::= NUM(B). {
    A.value = B.value;
    A.n = B.n + 1;
}

3、lex词法规则文件lexer.l

%{
#include "exampleDef.h"
#include "example.h"
#include <string.h>
#include <math.h>

int parserline = 1;
int parsercol = 1;

%}

%%

[0-9]+|[0-9]*/.[0-9]+ { /* float decimal */
    parsercol += (int) strlen(yytext);
    yylval.dval = atof(yytext);
    return TOKEN_NUM;
}

[ /t]   { /* ignore but count white space */
    parsercol += (int) strlen(yytext);
}

[A-Za-z][A-Za-z0-9]*  { /* ignore but needed for variables */
    return 0;
}

"+"           {  return TOKEN_PLUS; }
"-"           {  return TOKEN_MINUS; }
"*"           {  return TOKEN_TIMES; }
"/"           {  return TOKEN_DIVIDE; }

/n      {
    parsercol = 0;
    ++parserline;
    return TOKEN_NEWLINE;
}

.       {
    parsercol += (int) strlen(yytext);
    return yytext[0];
}

%%
/**
* reset the parserline and column count
*
*
*/
void reset_lexer(void)
{
  parserline = 1;
  parsercol  = 1;
}

/**
* yyerror() is invoked when the lexer or the parser encounter
* an error. The error message is passed via *s
*
*
*/
void yyerror(char *s)
{
  printf("error: %s at parserline: %d parsercol: %d/n",s,parserline,parsercol);
}

int yywrap(void)
{
  return 1;
}

4、头文件封装LAPI.h

#ifndef __LAPI_H__
#define __LAPI_H__
#include "example.c"

/**
* We have to declare these here - they're not  in any header files
* we can inclde.  yyparse() is declared with an empty argument list
* so that it is compatible with the generated C code from bison.
*
*/
extern FILE *yyin;
typedef struct yy_buffer_state *YY_BUFFER_STATE;

extern "C" {
  int             yylex( void );
  YY_BUFFER_STATE yy_scan_string( const char * );
  void            yy_delete_buffer( YY_BUFFER_STATE );
}

#endif

5、主函数main.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define BUFS 1024

#include "LAPI.h"

int main(int argc,char** argv)
{
  int n;
  int yv;
  char buf[BUFS+1];
  void* pParser = ParseAlloc (malloc);

  struct Token t0,t1;
  struct Token mToken;

  t0.n=0;
  t0.value=0;

  std::cout << "Enter an expression like 3+5 <return>" << std::endl;
  std::cout << "  Terminate with ^D" << std::endl;

  while ( ( n=read(fileno(stdin), buf, BUFS )) >  0)
    {
      buf[n]='/0';
      yy_scan_string(buf);
      // on EOF yylex will return 0
      while( (yv=yylex()) != 0)
        {
//          std::cout << " yylex() " << yv << " yylval.dval " << yylval.dval << std::endl;
          t0.value=yylval.dval;
          Parse (pParser, yv, t0);
        }

    }

  Parse (pParser, 0, t0);
  ParseFree(pParser, free );

}

6、Makefile

# Compiler flags
CFLAGS = -Wall -W -O2 -s -pipe
CLMFLAGS = -Wall -W -O2 -s -pipe -lm
LFLAGS =  -O2 -s -pipe

calc: main.c lex
    g++ -o calc -s -pipe  main.c lexer.o -lm

lex: lexer.l example
    flex lexer.l
    test -e lex.yy.c && mv lex.yy.c lexer.c
    gcc -o lexer.o -c lexer.c

example: example.y
      lemon example.y

原创粉丝点击