一、词法语法标准
if ¶m1== 2:
if ¶m2== 0:1.0
else:
if ¶m3== 6 : 3.0
elif ¶m3==5 :3.0
elif ¶m3==8:
if ¶m4 == 6 :
if ¶m3== 1:3.3
elif ¶m3== 2:2.7
else:3.0
else:
if ¶m3== 2:2.6
else:2.8
elif ¶m5 == 3:
if ¶m4 == 1 : 7.0
elif ¶m4 == 2 : 3.5
else : 3.0
else : 2.6
else:1.0
按上图语法标准
关键字:if else elif
变量引用:&字母数字组合,字母开头
运算符:==,<= ,>=,>,<
分隔符::
格式符:if else elif前面的空格
二、词法分析
输入:一个代码段字符串,变量对应的值字典
代码段如上图,字典value_map:{param1: 2, param2: 4, ...}
输出:代码段分词后的列表ret_list
js代码
function _split_rule(value_map, rule) {
/**
* 对规则语句进行分词与识别,词法分析
* @param {object} value_map 数据映射表
* @param {String} rule 计算规则
* @return {Array} 分词好的规则列表
*/
rule = rule.replace(/\t/g, '');
let rule_array = rule.str2array();
// 命令寄存器
let temp_command = [];
// 操作符暂存器
let temp_str = "";
while (rule_array.length > 0) {
let current_char = rule_array.shift();
// 如果读取到“[”则进入列表读取模式,shift,直到读出“]”,并把读到的内容去除空格后加入操作符暂存器
if (current_char === "[") {
temp_command.push(_recognize_list(rule_array));
}
// 如果读取到“&”则进入变量读取模式
else if (current_char === "&") {
while (rule_array.length > 0 && rule_array[0].match(/[a-zA-Z\d]/) !== null) {
temp_str += rule_array.shift();
}
temp_command.push(value_map[temp_str]);
temp_str = "";
}
// 如果读取到'<', '>' ,'='则进入符号读取模式,判断下一位是否仍然是符号,如果是需要再读一位
else if (['<', '>' ,'='].contain(current_char)) {
temp_str += current_char;
if (rule_array.length > 0 && rule_array[0] === '=') {
temp_str += rule_array.shift();
}
temp_command.push(temp_str);
temp_str = "";
}
// 如果读取到数字,则进入数字读取模式,一直读取下去,直到将要读取到非数字时停止
else if (current_char.match(/\d/) !== null) {
temp_str += current_char;
while (rule_array.length > 0 && rule_array[0].match(/\d|\./) !== null) {
temp_str += rule_array.shift();
}
temp_command.push(parseFloat(temp_str));
// temp_command.push(temp_str);
temp_str = "";
}
// 匹配多个分隔符
else if ([' ', ':', '\n'].contain(current_char)) {
if (temp_str !== '') {
temp_command.push(temp_str);
temp_str = "";
}
if (current_char === ':') {
temp_command.push(current_char);
}
// 读到换行符后紧挨的空格需要记录
else if (current_char === '\n') {
while (rule_array.length > 0 && rule_array[0] === ' ') {
temp_str += rule_array.shift();
}
if (temp_str.length > 0) {
temp_command.push(temp_str);
temp_str = "";
}
}
}
else {
temp_str += current_char;
}
}
return temp_command;
}
function _recognize_list(rule_array) {
/**
* 识别列表与列表中的数,传入参数类似[1,2,[1,2 , 3],],会少前面一个[。识别完成后,返回的列表在原来的参数中将消失
* @param {Array} rule_array 待识别列表
* @return {Array} 识别完成的列表
*/
let temp_list = [];
let temp_str = '';
let sign = 1;
while (sign > 0 && rule_array.length > 0) {
let current_char = rule_array.shift();
// current_char = rule_array.shift();
if (current_char === '[') {
sign += 1;
temp_list.push(_recognize_list(rule_array));
}
else if (current_char === ']') {
sign -= 1;
if (temp_str !== '') {
// 匹配浮点数或整数
if (temp_str.match(/^(-?\d+)(\.\d+)?$/) !== null) {
temp_list.push(parseFloat(temp_str));
temp_str = '';
}
else {
temp_list.push(temp_str);
temp_str = '';
}
}
}
else if (current_char === ' ') {
continue;
}
else if (current_char === ',') {
if (temp_str !== '') {
// 匹配浮点数或整数
if (temp_str.match(/^(-?\d+)(\.\d+)?$/) !== null) {
temp_list.push(parseFloat(temp_str));
temp_str = '';
}
else {
temp_list.push(temp_str);
temp_str = '';
}
}
}
else {
temp_str += current_char;
}
}
return temp_list;
}
三、语法分析
输入:词法分析后的列表
输出:逻辑结果
const IF = "if";
const ELIF = 'elif';
const ELSE = 'else';
function _calculate_sentence(split_rule){
/**
* 根据已经分词好的规则列表计算语句的值,语法分析
* @param {Array} split_rule 分词好的规则列表
* @return {Array} 识别完成的列表
*/
let expression = [];
let judgment;
// if,elif,else前面的空格标志,起始为无空格,层级加一空格一
let sign = '';
while (split_rule.length > 0) {
let current_element = split_rule.shift();
if ([IF, ELIF, ELSE].contain(current_element)) {
if (current_element === ELSE) {
judgment = true;
}
else {
// 向后连取直到':'
while (split_rule.length > 0 && split_rule[0] !== ':') {
expression.push(split_rule.shift());
}
judgment = calculate_expression(expression);
expression = [];
}
// 把’;‘shift出去
split_rule.shift();
if (judgment) {
sign += ' ';
// 判断':'后面是格式符号还是结果值,如果是格式符号则后面必跟’空格‘+if,shift格式符,然后进行下一次循环
if (split_rule[0] === sign) {
split_rule.shift();
continue;
}
else {
return split_rule[0];
}
}
// 跳转到下一个对应的elif或者else
else {
if (sign === '') {
while (split_rule.length > 0 && ![IF, ELIF, ELSE].contain(split_rule[0])) {
current_element = split_rule.shift();
// 把空格后的if,elif,else都去除掉,以免误判
if (typeof(current_element) === 'string' && current_element.match(/\s/) !== null) {
split_rule.shift();
}
}
}
else{
while (split_rule.length > 0 && split_rule.shift() !== sign) {}
}
}
}
else {
return current_element;
}
}
return null;
}
const IN = 'in';
const AND = 'and';
const OR = 'or';
const CALCULATION_SYMBOL = ['<', '>', '=', '==', '>=', '<=', '!=', IN, AND, OR]
function calculate_expression(infix_expression) {
let postfix_expression = _transform_expression_2_postfix(infix_expression);
return _calculate_postfix_expression(postfix_expression);
}
function _get_priority(opt) {
/**
* 获取优先级
* @param {string} opt 计算符
* @return {number} 优先级大小
*/
if (['(', ')'].contain(opt)) {
// 随便给一个值,运算时不会取括号的优先级
return 1;
}
else if (['<', '>', '==', '>=', '<=', '!=', IN].contain(opt)) {
return 9;
}
else if ([AND, OR].contain(opt)) {
return 8;
}
else {
console.error('function:[_get_inferior] 异常运算符: ' + opt);
return 0;
}
}
function _transform_expression_2_postfix(infix_expression) {
/**
* 单元计算器
* @param {Array} infix_expression 中缀表达式
* @return {Array} 后缀表达式
*/
// 后缀表达式
let postfix_expression = [];
// 操作符栈
let opt_stack = [];
while (infix_expression.length > 0) {
let current_element = infix_expression.shift();
if (['number', 'object'].contain(typeof(current_element))) {
postfix_expression.push(current_element);
}
else {
if (opt_stack.length === 0 || current_element === '(' || opt_stack.slice(-1)[0] === '(') {
opt_stack.push(current_element);
}
else if (_get_priority(opt_stack.slice(-1)[0]) < _get_priority(current_element)) {
opt_stack.push(current_element);
}
else {
if (current_element === ')') {
while (opt_stack.slice(-1)[0] !== '(') {
postfix_expression.push(opt_stack.pop());
}
// 左括号出栈
opt_stack.pop();
}
else {
while (opt_stack.length > 0 && opt_stack.slice(-1)[0] !== '(' &&
_get_priority(opt_stack.slice(-1)[0]) >= _get_priority(current_element)) {
postfix_expression.push(opt_stack.pop());
}
opt_stack.push(current_element);
}
}
}
}
while (opt_stack.length > 0) {
postfix_expression.push(opt_stack.pop());
}
return postfix_expression;
}
function _calculate_postfix_expression(postfix_expression) {
let ret_stack = [];
while (postfix_expression.length > 0) {
let current_element = postfix_expression.shift();
if (['number', 'object'].contain(typeof(current_element))) {
ret_stack.push(current_element);
}
else {
ret_stack.push(_unit_calculator(ret_stack.pop(), current_element, ret_stack.pop()));
}
}
return ret_stack[0];
}
function _unit_calculator(num_b, opt, num_a) {
/**
* 单元计算器
* @param {Any} num_a 计算数A
* @param {string} opt 操作数
* @param {Any} num_b 计算数B
* @return {Any} 计算结果
*/
if (!CALCULATION_SYMBOL.contain(opt)) {
console.error("非法计算符" + opt);
return null;
}
if (opt === IN) {
return num_b.contain(num_a);
}
else if (opt === '==') {
return num_a === num_b;
}
else if (opt === '!=') {
return num_a !== num_b;
}
else if (opt === '>=') {
return num_a >= num_b;
}
else if (opt === '<=') {
return num_a <= num_b;
}
else if (opt === '>') {
return num_a > num_b;
}
else if (opt === '<') {
return num_a < num_b;
}
else if (opt === AND) {
return num_a && num_b;
}
else if (opt === OR) {
return num_a || num_b;
}
}