%parser_sparse_table yes; # 使用稀疏分析表。
%token_class_name Token; # 设置生成代码中的词元类名。
%lexer_class_name Tokenizer; # 设置生成代码中的词法分析器类名。
%parer_class_name Parser; # 设置生成代码中的语法分析器类名。
%interpreter_class_name Interpreter; # 设置生成代码中的语义分析器类名。
%conflict_resolver yes; # 启用冲突解决。
%shift_reduce_conflict_resolver order; # 使用优先级解决冲突。
%start_symbol calculator; # 指明起始分析符号。
# 词法描述部分。
t_symbol = <[_a-zA-Z][_a-zA-Z0-9]*>; # 普通符号只能有字母、数字和下划线构成,且不能以数字开头。
t_number = <[0-9]+(\.[0-9]*)?>; # 数字可以为整数和小数,不支持科学计数。
skip = <[\ \t]+>@{skip}; # 过滤掉空白字符。
newline = <\n\r|\n>@{skip, newline}; # 过滤掉换号并累计行号。
calculator: statement*; # 计算器脚本由若干语句构成。
statement: t_symbol '=' expression = set_variable($0, $2) # 语句可以是一个赋值语句,使用set_variable动作带入t_symbol和expression进行语义处理。
| function # 语句可以是一个函数调用。
;
function: t_symbol '(' expression (',' expression)* ')' = function($0, $2, *$3[$1]); # 函数调用由函数名和参数列表组成,使用function动作带入t_symbol和unpack的参数列表。
expression: expression '^' expression = compute($0, $1, $2) # 指数运算,作为最高优先级放在前面。
| expression ('*' | '/') expression = compute($0, *$1, $2) # 其次是乘法和除法运算。
| expression ('+' | '-') expression = compute($0, *$1, $2) # 优先级最低的是加减法。
| '(' expression ')' = [$1] # 由括号包围的子表达式。
| function # 函数调用的返回值。
| t_symbol = get_variable($0) # 定义过的变量值。
| t_number = number($0) # 立即数。
;
执行
boson parser.boson -l c++ -o parser
生成对应的分析器代码到parser
目录。
Boson v1.5 - Grammar Analyzer Generator
Author: ict
Email: [email protected]
URL: https://github.com/ictxiangxin/boson
[Generate Analyzer Code]
[1] Parse Boson Script... Done [0.0040s]
> Commands Count: 8
> Lexical Definition: Yes
> Grammar Definition: Yes
[2] Generate Lexical Analysis Table... Done [0.0050s]
> Lexical Definition Count: 13
> Character Set Size: 77
> DFA State Count: 6
[3] Generate Grammar Analysis Table... Done [0.0031s]
> Algorithm: LALR
> Grammar Sentence Count: 22
> Non-Terminal Symbol Count: 12
> Terminal Symbol Count: 12
> PDA State Count: 33
> Action Table Size/Sparse-Size (Rate): 429/154 (35.90%)
> Goto Table Size/Sparse-Size (Rate): 396/48 (12.12%)
[4] Generate Code... Done [0.0968s]
> Language: C++
> Mode: Integration
> Checker: No
> Generate Lexer: Yes
> Generate Parser: Yes
> Generate Interpreter: Yes
> Output Path: "parser"
[Complete!!! 0.1403s]
调用词法分析和语法分析获得完整的抽象语法树。
Tokenizer tokenizer; // 创建词法分析器实例。
Parser parser; // 创建语法分析器实例。
Interpreter<mpfr_t> interpreter; // 创建语义分析器实例。
tokenizer.tokenize(code); // 对计算代码进行词法分析。
if (tokenizer.tokenize(code) != tokenizer.no_error_index()) { // 如果错误行存在则代码存在词法错误。
std::cerr << "[ERROR] Lexical error, index: " << tokenizer.error_index() << std::endl; // 打印错误对应行号。
return -1;
}
BosonGrammar grammar_tree = parser.parse(tokenizer.token_list()); // 进行语法分析。
if (grammar_tree.get_error_index() != -1) { // 如果错误行存在则代码存在语法错误。
int line = tokenizer.token_list()[grammar_tree.get_error_index()].line; // 获取语法出错代码行号。
std::cerr << "[ERROR] Grammar error, line: " << line << std::endl; // 打印出错代码行号。
for (auto &t: tokenizer.token_list()) { // 打印出错代码行内容。
if (line == t.line) {
std::cerr << t.text << ' ';
}
}
std::cerr << std::endl;
return -1;
}
注册语义动作,以
function
函数调用语义动作为例。
interpreter.register_action("function", [](BosonSemanticsNode<mpfr_t> &node) -> BosonSemanticsNode<mpfr_t> { // 参数和返回值均为语义节点。
BosonSemanticsNode<mpfr_t> function_return; // 创建函数返回值语义节点。
mpfr_init(function_return.get_data()); // 初始化返回值mpfr值。
std::string function_name = node[0].get_text(); // 根据语法定义,函数调用第一个参数为函数名。
if (function_name == "sqrt") { // 如果函数名为sqrt,调用mpfr对应的开平方函数。
mpfr_sqrt(function_return.get_data(), node[1].get_data(), GMP_RNDD);
} else if (function_name == "sin") {
mpfr_sin(function_return.get_data(), node[1].get_data(), GMP_RNDD);
} else if (function_name == "cos") {
mpfr_cos(function_return.get_data(), node[1].get_data(), GMP_RNDD);
} else if (function_name == "tan") {
mpfr_tan(function_return.get_data(), node[1].get_data(), GMP_RNDD);
} else if (function_name == "pow") { // 该函数需2个参数。
mpfr_pow(function_return.get_data(), node[1].get_data(), node[2].get_data(), GMP_RNDD);
} else if (function_name == "print") { // 输出函数,该函数无返回值。
mpfr_printf("%.32Rf\n", node[1].get_data());
return BosonSemanticsNode<mpfr_t>::null_node(); // 无返回值,返回null语义节点。
}
return function_return; // 返回函数调用结果。
});
调用语义分析完成计算过程。
interpreter.execute(grammar_tree.get_grammar_tree());
使用cmake编译程序。
cmake_minimum_required(VERSION 3.10)
project(calculator)
set(CMAKE_CXX_STANDARD 11)
add_executable(calculator main.cpp)
target_link_libraries(calculator mpfr)
编写测试计算脚本
test.txt
。
c = 299792458
m0 = 70
v = 0.1 * c
m = m0 / (1 - (v / c) ^ 2)
print(m)
print(sin(m * pow(2, m0)))
b = tan(m) / m
print(b)
执行
calculator -f a.txt
进行脚本计算,得到结果输出。
70.70707070707070707070707070707071
0.01501900015975742618890663327067
-0.66588482869753354169765171137603