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'

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个计算课程平均分的 C 语言程序,使用链表实现: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 struct node { int score; struct node *next; }; void calc_average() { struct node *head = NULL; // 定义链表头指针 int count = 0, sum = 0; // 定义计数器和总分数变量 float average; // 定义平均分变量 // 循环读取用户输入的成绩,直到输入 -1 结束 while (1) { int score; printf("请输入成绩(-1表示结束):"); scanf("%d", &score); if (score == -1) { break; } // 创建新的链表节点并将其插入链表 struct node *new_node = (struct node *)malloc(sizeof(struct node)); new_node->score = score; new_node->next = head; head = new_node; // 更新计数器和总分数 count++; sum += score; } // 计算平均分 if (count > 0) { average = (float)sum / count; printf("平均分为:%.2f\n", average); } else { printf("没有输入成绩!\n"); } // 释放链表内存 while (head != NULL) { struct node *temp = head; head = head->next; free(temp); } } ``` 这个程序首先定义了一个链表节点结构体 `node`,其包含一个成绩 `score` 和一个指向下一个节点的指针 `next`。然后在 `calc_average` 函数,初始化链表头指针 `head` 为 `NULL`,计数器 `count` 和总分数 `sum` 为 0,平均分 `average` 为 0。 然后,程序使用一个无限循环读取用户输入的成绩,直到输入 -1 结束。每读取一个成绩,程序就创建一个新的链表节点并将其插入链表的头部,然后更新计数器和总分数。 循环结束后,程序计算平均分,如果输入了至少一个成绩,则输出计算结果;否则输出提示信息。 最后,程序释放链表内存,避免内存泄漏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值