c语言void calc(),bison(yacc)中关于calc的一个C++版实现

bison中一个calc的C++版实现,区别于传统的C语言实现,我这边整理了一个可编译的版本用以参考

calc++-driver.h

#ifndef CALCXX_DRIVER_HH

# define CALCXX_DRIVER_HH

# include

# include

# include "calc++-parser.h"

// Tell Flex the lexer's prototype ...

# define YY_DECL\

yy::calcxx_parser::token_type\

yylex (yy::calcxx_parser::semantic_type* yylval,\

yy::calcxx_parser::location_type* yylloc,\

calcxx_driver& driver)

// ... and declare it for the parser's sake.

YY_DECL;

// Conducting the whole scanning and parsing of Calc++.

class calcxx_driver

{

public:

calcxx_driver ();

virtual ~calcxx_driver ();

std::map<:string int> variables;

int result;

// Handling the scanner.

void scan_begin ();

void scan_end ();

bool trace_scanning;

// Run the parser. Return 0 on success.

int parse (const std::string& f);

std::string file;

bool trace_parsing;

// Error handling.

void error (const yy::location& l, const std::string& m);

void error (const std::string& m);

};

#endif // ! CALCXX_DRIVER_HH

calc++-driver.cpp

#include "calc++-driver.h"

#include "calc++-parser.h"

calcxx_driver::calcxx_driver ()

: trace_scanning (false), trace_parsing (false)

{

variables["one"] = 1;

variables["two"] = 2;

}

calcxx_driver::~calcxx_driver ()

{

}

int

calcxx_driver::parse (const std::string &f)

{

file = f;

scan_begin ();

yy::calcxx_parser parser (*this);

parser.set_debug_level (trace_parsing);

int res = parser.parse ();

scan_end ();

return res;

}

void

calcxx_driver::error (const yy::location& l, const std::string& m)

{

std::cerr << l << ": " << m << std::endl;

}

void

calcxx_driver::error (const std::string& m)

{

std::cerr << m << std::endl;

}

calc++-scanner.l

%{ /* -*- C++ -*- */

# include

# include

# include

# include

# include "calc++-driver.h"

# include "calc++-parser.h"

/* Work around an incompatibility in flex (at least versions

2.5.31 through 2.5.33): it generates code that does

not conform to C89. See Debian bug 333231

. */

# undef yywrap

# define yywrap() 1

/* By default yylex returns int, we use token_type.

Unfortunately yyterminate by default returns 0, which is

not of token_type. */

#define yyterminate() return token::END

%}

%option noyywrap nounput batch debug nounistd never-interactive

id [a-zA-Z][a-zA-Z_0-9]*

int [0-9]+

blank [ \t]

%{

# define YY_USER_ACTION yylloc->columns (yyleng);

%}

%%

%{

yylloc->step ();

%}

{blank}+ yylloc->step ();

[\n]+ yylloc->lines (yyleng); yylloc->step ();

%{

typedef yy::calcxx_parser::token token;

%}

/* Convert ints to the actual type of tokens. */

[-+*/]return yy::calcxx_parser::token_type (yytext[0]);

":="return token::ASSIGN;

{int}{

errno = 0;

long n = strtol (yytext, NULL, 10);

if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))

driver.error (*yylloc, "integer is out of range");

yylval->ival = n;

return token::NUMBER;

}

{id}{

yylval->sval = new std::string (yytext);

return token::IDENTIFIER;

}

.driver.error (*yylloc, "invalid character");

%%

void

calcxx_driver::scan_begin ()

{

yy_flex_debug = trace_scanning;

if (file.empty () || file == "-")

yyin = stdin;

else if (!(yyin = fopen (file.c_str (), "r")))

{

error ("cannot open " + file + ": " + strerror(errno));

exit (EXIT_FAILURE);

}

}

void

calcxx_driver::scan_end ()

{

fclose (yyin);

}

calc++-parser.y

%skeleton "lalr1.cc" /* -*- C++ -*- */

//%require "2.7"

%defines

%define parser_class_name "calcxx_parser"

%code requires {

# include

class calcxx_driver;

}

// The parsing context.

%parse-param { calcxx_driver& driver }

%lex-param { calcxx_driver& driver }

%locations

%initial-action

{

// Initialize the initial location.

@$.begin.filename = @$.end.filename = &driver.file;

};

%debug

%error-verbose

// Symbols.

%union

{

int ival;

std::string *sval;

};

%code {

# include "calc++-driver.h"

}

%token END 0 "end of file"

%token ASSIGN ":="

%token IDENTIFIER "identifier"

%token NUMBER "number"

%type exp

%printer { std::cout << *$$; } "identifier"

%destructor { delete $$; } "identifier"

%printer { std::cout << $$; }

%%

%start unit;

unit: assignments exp{ driver.result = $2; };

assignments:

/* Nothing. */{}

| assignments assignment{};

assignment:

"identifier" ":=" exp

{ driver.variables[*$1] = $3; delete $1; };

%left '+' '-';

%left '*' '/';

exp: exp '+' exp{ $$ = $1 + $3; }

| exp '-' exp{ $$ = $1 - $3; }

| exp '*' exp{ $$ = $1 * $3; }

| exp '/' exp{ $$ = $1 / $3; }

| "identifier"{ $$ = driver.variables[*$1]; delete $1; }

| "number"{ $$ = $1; };

%%

void

yy::calcxx_parser::error (const yy::calcxx_parser::location_type& l,

const std::string& m)

{

driver.error (l, m);

}

main.cpp

#include

#include "calc++-driver.h"

int

main (int argc, char *argv[])

{

calcxx_driver driver;

for (int i = 1; i < argc; ++i)

{

if (argv[i] == std::string ("-p"))

driver.trace_parsing = true;

else if (argv[i] == std::string ("-s"))

driver.trace_scanning = true;

else if (!driver.parse (argv[i]))

std::cout << driver.result << std::endl;

}

return 0;

}

最后对应的Makefile

all: calc++.exe

calc++.exe: calc++-driver.o calc++-parser.o calc++-scanner.o main.o

g++ -o calc++.exe calc++-driver.o calc++-parser.o calc++-scanner.o main.o

calc++-driver.o: calc++-driver.cpp calc++-driver.h calc++-parser.h

g++ -c calc++-driver.cpp

calc++-parser.o: calc++-parser.cpp calc++-parser.h calc++-driver.h

g++ -c calc++-parser.cpp

calc++-parser.cpp calc++-parser.h: calc++-parser.y

bison --defines=calc++-parser.h -ocalc++-parser.cpp calc++-parser.y

calc++-scanner.o: calc++-scanner.cpp calc++-parser.h calc++-driver.h

g++ -c calc++-scanner.cpp

calc++-scanner.cpp: calc++-scanner.l

flex -ocalc++-scanner.cpp calc++-scanner.l

main.o:

.PHONY: clean

clean:

-rm *.o calc++-parser.h calc++-parser.cpp calc++-scanner.cpp location.hh position.hh stack.hh calc++.exe

注意:在lexer文件中有这样的选项

%option .. nounistd never-interactive

其目的是避免在VC++中出现的编译错误 Cannot open include file: 'unistd.h'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值