在本文中,我们将详细介绍PHP实现的简单四则运算计算器功能示例的各个方面,并为您提供关于php实现的简单四则运算计算器功能示例图的相关解答,同时,我们也将为您带来关于C#基于简单工厂模式实现的计算器功
在本文中,我们将详细介绍PHP实现的简单四则运算计算器功能示例的各个方面,并为您提供关于php实现的简单四则运算计算器功能示例图的相关解答,同时,我们也将为您带来关于C#基于简单工厂模式实现的计算器功能示例、C#实现的简单整数四则运算计算器功能示例、C++实现能四则运算计算器、golang 四则运算计算器yacc归约手写实现的有用知识。
本文目录一览:- PHP实现的简单四则运算计算器功能示例(php实现的简单四则运算计算器功能示例图)
- C#基于简单工厂模式实现的计算器功能示例
- C#实现的简单整数四则运算计算器功能示例
- C++实现能四则运算计算器
- golang 四则运算计算器yacc归约手写实现
PHP实现的简单四则运算计算器功能示例(php实现的简单四则运算计算器功能示例图)
本文实例讲述了PHP实现的简单四则运算计算器功能。分享给大家供大家参考,具体如下:
php实现一个简单的四则运算计算器(还不支持括号的优先级)。利用栈这种数据结构来计算表达式很赞。
这里可以使用栈的结构,由于php的数组“天然”就有栈的特性,这里直接就利用了数组。当然可以使用栈结构写,道理一样的。
前辈(波兰一位科学家)在计算带有括号的四则表达式,利用逆波兰算法(后缀表达法)。简直神了!!其实代码code并不难,难的是算法的指导,要先理解算法,才能编码。
<?php $num_arr = array();// 声明数字栈 $op_arr = array();// 声明符号栈 $str = "10+6*2-18/2-2"; preg_match_all(''/./'', $str, $arr);// 把运算串分解成每个字符到$arr数组 $str_arr = $arr[0]; $length = count($str_arr); $pre_num = ''''; // 开始入栈 for($i=0; $i<$length; $i++){ $val = $str_arr[$i]; // 数字 if (is_numeric($val)){ $pre_num .= $val;// 兼顾下一个字符可能也是数字的情况(多位数) if($i+1>=$length || isOper($str_arr[$i+1])){// 下一个是运算符或者到头了,则把数字塞进数字栈 array_push($num_arr, $pre_num); $pre_num = ''''; } // 符号判断优先级,选择是否入栈 } else if (isOper($val)){ if (count($op_arr)>0){ // 判断优先级,只要不大于符号栈顶的优先级,就开始计算,直到优先级大于了栈顶的,计算后才再把这个运算符入栈 while (end($op_arr) && priority($val) <= priority(end($op_arr))){ calc($num_arr, $op_arr); } } array_push($op_arr, $val); } } //echo ''<pre>''; //print_r($num_arr); //print_r($op_arr); // 计算栈里剩余的 while(count($num_arr)>0){ calc($num_arr, $op_arr); if (count($num_arr)==1){ $result = array_pop($num_arr); break; } } echo $str,'' = '', $result; // 计算,获取数字栈的两个数,符号栈顶的运算符 function calc(&$num_arr, &$op_arr){ if (count($num_arr)>0){ $num1 = array_pop($num_arr); $num2 = array_pop($num_arr); $op = array_pop($op_arr); if ($op==''*'') $re = $num1*$num2; if ($op==''/'') $re = $num2/$num1;// 这里注意顺序,栈是先进后出,所以$num2是被除数 if ($op==''+'') $re = $num2+$num1; if ($op==''-'') $re = $num2-$num1; array_push($num_arr, $re); } } // 获取优先级 function priority($str){ if ($str == ''*'' || $str == ''/''){ return 1; } else { return 0; } } // 判断是否是运算符 function isOper($oper){ $oper_array = array(''+'',''-'',''*'',''/''); if (in_array($oper, $oper_array)){ return true; } return false; }
运行结果:
10+6*2-18/2-2 = 11
PS:这里再为大家推荐几款计算工具供大家进一步参考借鉴:
在线一元函数(方程)求解计算工具:
http://tools.jb51.net/jisuanqi/equ_jisuanqi
科学计算器在线使用_高级计算器在线计算:
http://tools.jb51.net/jisuanqi/jsqkexue
在线计算器_标准计算器:
http://tools.jb51.net/jisuanqi/jsq
更多关于PHP相关内容感兴趣的读者可查看本站专题:《PHP数学运算技巧总结》、《PHP运算与运算符用法总结》、《php字符串(string)用法总结》、《PHP数组(Array)操作技巧大全》、《PHP数据结构与算法教程》、《php程序设计算法总结》及《php正则表达式用法总结》
希望本文所述对大家PHP程序设计有所帮助。
- PHP 使用位运算实现四则运算的代码
- 用PHP实现的四则运算表达式计算实现代码
- php实现简单四则运算器
C#基于简单工厂模式实现的计算器功能示例
本文实例讲述了C#基于简单工厂模式实现的计算器功能。分享给大家供大家参考,具体如下:
子类拥有父类除私有之外的所有属性字段和方法
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 工厂方法实现计算器 { /// <summary> /// 计算器类(抽象类,由子类重写) /// </summary> public abstract class Calculator { public double Number1 { get; set; } public double Number2 { get; set; } public Calculator() { } public Calculator(double a,double b) { this.Number1=a; this.Number2=b; } /// <summary> /// 计算 /// </summary> /// <returns></returns> public abstract double jsuan(); } /// <summary> /// 加法类 /// </summary> public class jiafaDll:Calculator //子类拥有父类除私有之外的所有属性字段和方法 { public jiafaDll() { } public jiafaDll(double a,double b) : base(a,b) //调用父类带两个参数的构造函数,来初始化Number1 和Number2 (注意:因为jianfaDll类继承了Calculator,所以jianfaDll类是有Number1,和Number2两个属性的) { } /// <summary> /// 重写父类的jsuan方法 /// </summary> /// <returns></returns> public override double jsuan() { return Number1 + Number2; } } /// <summary> /// 减法类 /// </summary> public class jianfaDll : Calculator { public jianfaDll() { } public jianfaDll(double a,b) { } public override double jsuan() { return Number1 - Number2; } } class Program { static void Main(string[] args) { Console.WriteLine("请输入第一个数"); double number1 = Convert.Todouble(Console.ReadLine()); Console.WriteLine("请输入一个操作符"); string caozuofu = Console.ReadLine(); Console.WriteLine("请输入第二个数"); double number2 = Convert.Todouble(Console.ReadLine()); Calculator c=null; switch (caozuofu) { case "+": c = new jiafaDll(number1,number2); break; case "-": c = new jianfaDll(number1,number2); break; } double i= c.jsuan(); Console.WriteLine(i); Console.ReadKey(); } } }
PS:这里再为大家推荐几款计算工具供大家进一步参考借鉴:
在线一元函数(方程)求解计算工具:
http://tools.jb51.net/jisuanqi/equ_jisuanqi
科学计算器在线使用_高级计算器在线计算:
http://tools.jb51.net/jisuanqi/jsqkexue
在线计算器_标准计算器:
http://tools.jb51.net/jisuanqi/jsq
更多关于C#相关内容感兴趣的读者可查看本站专题:《C#数学运算技巧总结》、《C#数据结构与算法教程》、《C#程序设计之线程使用技巧总结》、《C#常见控件用法教程》、《WinForm控件用法总结》、《C#数组操作技巧总结》及《C#面向对象程序设计入门教程》
希望本文所述对大家C#程序设计有所帮助。
C#实现的简单整数四则运算计算器功能示例
本文实例讲述了C#实现的简单整数四则运算计算器功能。分享给大家供大家参考,具体如下:
运行效果图如下:
具体代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace 计算器 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } public string num; public int flag;//用于判断输入的操作符 public double num1,num2; private void num0_button_Click(object sender,EventArgs e) { num = num + "0"; num2 = Convert.Todouble(num); textBox.Text = num; } private void num1_button_Click(object sender,EventArgs e)//重点算法1 { if (textBox.Text == "0") { num = "1"; textBox.Text = Convert.ToString(num); } else { num = num + "1"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void num2_button_Click(object sender,EventArgs e) { if (textBox.Text == "0") { num = "2"; textBox.Text = Convert.ToString(num); } else { num = num + "2"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void num3_button_Click(object sender,EventArgs e) { if (textBox.Text == "0") { num = "3"; textBox.Text = Convert.ToString(num); } else { num = num + "3"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void num4_button_Click(object sender,EventArgs e) { if (textBox.Text == "0") { num = "4"; textBox.Text = Convert.ToString(num); } else { num = num + "4"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void num5_button_Click(object sender,EventArgs e) { if (textBox.Text == "0") { num = "5"; textBox.Text = Convert.ToString(num); } else { num = num + "5"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void num6_button_Click(object sender,EventArgs e) { if (textBox.Text == "0") { num = "6"; textBox.Text = Convert.ToString(num); } else { num = num + "6"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void num7_button_Click(object sender,EventArgs e) { if (textBox.Text == "0") { num = "7"; textBox.Text = Convert.ToString(num); } else { num = num + "7"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void num8_button_Click(object sender,EventArgs e) { if (textBox.Text == "0") { num = "8"; textBox.Text = Convert.ToString(num); } else { num = num + "8"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void num9_button_Click(object sender,EventArgs e) { if (textBox.Text == "0") { num = "9"; textBox.Text = Convert.ToString(num); } else { num = num + "9"; num2 = Convert.Todouble(num); textBox.Text = num; } } private void add_button_Click(object sender,EventArgs e)//重点算法2 { if (textBox.Text.Length > 0) { num1 = Convert.Todouble(textBox .Text); num = ""; flag = 1; textBox.Text = ""; textBox.Focus(); } } private void dev_button_Click(object sender,EventArgs e) { if (textBox.Text.Length > 0) { num1 = Convert.Todouble(textBox.Text); num = ""; flag = 2; textBox.Text = ""; textBox.Focus(); } } private void mul_button_Click(object sender,EventArgs e) { if (textBox.Text.Length > 0) { num1 = Convert.Todouble(textBox.Text); num = ""; flag = 3; textBox.Text = ""; textBox.Focus(); } } private void chu_button_Click(object sender,EventArgs e) { if (textBox.Text.Length > 0) { num1 = Convert.Todouble(textBox.Text); num = ""; flag = 4; // textBox.Text = ""; textBox.Focus(); } } private void equ_button_Click(object sender,EventArgs e) { switch (flag) { case 1: textBox.Text = Convert.ToString(num1+Convert .Todouble(num));//重点算法3 num2 = Convert.Todouble(textBox .Text); break; case 2: textBox.Text = Convert.ToString(num1 - Convert.Todouble(num)); num2 = Convert.Todouble(textBox.Text); break; case 3: textBox.Text = Convert.ToString(num1 * Convert.Todouble(num)); num2 = Convert.Todouble(textBox.Text); break; case 4: textBox.Text = Convert.ToString(num1 / Convert.Todouble(num)); num2 = Convert.Todouble(textBox.Text); break; } } private void re_button_Click(object sender,EventArgs e) { num = ""; textBox.Text = "0"; } } }
PS:这里再为大家推荐几款计算工具供大家进一步参考借鉴:
在线一元函数(方程)求解计算工具:
http://tools.jb51.net/jisuanqi/equ_jisuanqi
科学计算器在线使用_高级计算器在线计算:
http://tools.jb51.net/jisuanqi/jsqkexue
在线计算器_标准计算器:
http://tools.jb51.net/jisuanqi/jsq
更多关于C#相关内容感兴趣的读者可查看本站专题:《C#数据结构与算法教程》、《C#程序设计之线程使用技巧总结》、《C#常见控件用法教程》、《WinForm控件用法总结》、《C#数组操作技巧总结》及《C#面向对象程序设计入门教程》
希望本文所述对大家C#程序设计有所帮助。
C++实现能四则运算计算器
#include <iostream>
#include <string>
#include <cmath>
#include <deque>
using namespace std;
#define LENGTH 61440 //60KB
bool isNo(char c) //is Number
{
return c >= ''0'' && c <= ''9'' || c == ''.'';
}
bool isSyb(const char* c)//is Symbol
{
return (*c == ''+'' || *c == ''-'' || *c == ''*'' || *c == ''/'') && strlen(c) == 1; //ver1.2
}
bool isSyb(char c)//is Symbol
{
return c == ''+'' || c == ''-'' || c == ''*'' || c == ''/'';
}
bool isIlg(char c) //is illegal
{
return !isNo(c) && !isSyb(c) && !(c == ''('' || c == '')'' || c == '' '');
}
const char* GetSubtext(const char* S,size_t bgn,size_t end) //follow "left-inclusive interval"
{
char* subtext = new char[end - bgn + 1];
subtext[end - bgn] = ''\0'';
for (size_t i = bgn; i != end; i++)
subtext[i - bgn] = S[i];
return subtext;
}
const char* calc(const char* S,size_t len)
{
deque<string> words;
bool inNo = false; //door for isNo
//bool inSyb = false; //door for isSyb
size_t NoPos = 0;
//size_t SybPos = 0;
size_t ParPos = 0, ParDep = 0;
for (size_t i = 0; i <= len; i++) //build standard formula
{
if(isIlg(S[i]) && i != len) //formula illegal checking
{
return "The formula is illegal!";
//exit(1);
}
if (isNo(S[i]) && !inNo) //Number postion begin
{
inNo = true;
NoPos = i;
}
if (!isNo(S[i]) && inNo) //Number postion end
{
inNo = false;
words.push_back(GetSubtext(S,NoPos,i));
}
if (isSyb(S[i])/* && !inSyb*/)
{
/*
inSyb = true;
SybPos = i;
*/
words.push_back(GetSubtext(S,i,i + 1));
}
/*
if (!isSyb(S[i]) && inSyb)
{
inSyb = false;
words.push_back(GetSubtext(S,SybPos,i));
}*/
if (S[i] == ''('')
{
//inPar = true;
ParDep++;
ParPos = i + 1; //left-inclusive interval
size_t j;
for (j= i + 1; ParDep && j <= len; j++)
{
if (S[j] == ''('') ParDep++;
if (S[j] == '')'') ParDep--;
}
if (j <= len)
{
string recResult(calc(GetSubtext(S,ParPos,j - 1),strlen(GetSubtext(S,ParPos,j - 1))));
if (recResult == "The formula is illegal!")
return "The formula is illegal!";
else if (recResult == "Parentheses is not match!")
return "Parentheses is not match!";
else
words.push_back(recResult);
}
else
{
//parentheses is not match
return "Parentheses is not match!";
}
i = j; //jump over subtext
}
if (S[i] == '')'')
return "Parentheses is not match!";
} //end for
long double tempResult = 0;
static char CtmpResult[50];
//check formula
if (words.size() == 0) return "0."; // 0 element
if (words.size() == 1 ) //1 element
if( !isSyb(words.front().c_str()))
{
strcpy_s(CtmpResult,words.front().c_str());
return CtmpResult;
}
else
return "The formula is illegal!";
if (words.front() == "*" || words.front() == "/") //front is symble
return "The formula is illegal!";
if (words.front() == "+" || words.front() == "-")
{
if (!isSyb((words.begin() + 1) -> c_str()))
{
words.front() += *(words.begin() + 1);
words.erase(words.begin() + 1); //erase second one
}
else
return "The formula is illegal!";
}
if (isSyb(words.back().c_str()))
return "The formula is illegal!";
for (deque<string>::iterator i = words.begin() + 1; i < words.end(); i++)
{
if ((*i == "*" || *i == "/") && (isSyb((i-1) -> c_str())) && strlen((i-1) -> c_str()))
return "The formula is illegal!";
if ((*i == "+" || *i == "-") && (isSyb((i-1) -> c_str())) && strlen((i-1) -> c_str()))
if(!isSyb(*((i+1) -> c_str())))
{
*(i + 1) = *i + *(i + 1);
i = words.erase(i);
}
else
return "The formula is illegal!";
}
//start calculate
for (deque<string>::iterator i = words.begin(); i != words.end(); i++)
{
//calculate * and /
if (*i == "*")
{
tempResult = atof((i-1) -> c_str()) * atof((i+1) -> c_str());
_gcvt_s(CtmpResult,tempResult,47);//double to string
i = words.erase(i - 1);
i = words.erase(i);
*i = CtmpResult;
}
if (*i == "/")
{
tempResult = atof((i-1) -> c_str()) / atof((i+1) -> c_str());
_gcvt_s(CtmpResult,tempResult,47); //double to string
i = words.erase(i - 1);
i = words.erase(i);
*i = CtmpResult;
}
}
for (deque<string>::iterator i = words.begin(); i != words.end(); i++)
{
//calculate + and -
if (*i == "+")
{
tempResult = atof((i-1) -> c_str()) + atof((i+1) -> c_str());
_gcvt_s(CtmpResult,tempResult,47); //double to string
i = words.erase(i - 1);
i = words.erase(i);
*i = CtmpResult;
}
if (*i == "-")
{
tempResult = atof((i-1) -> c_str()) - atof((i+1) -> c_str());
_gcvt_s(CtmpResult,tempResult,47);//double to string
i = words.erase(i - 1);
i = words.erase(i);
*i = CtmpResult;
}
}
strcpy_s( CtmpResult, words.front().c_str());
return CtmpResult;
}
void main(int argc,char* argv[])
{
if (argc > 1)
{
cout<<argv[1]<<ends<<''=''<<ends<<calc(argv[1],strlen(argv[1]))<<endl;
}
else
{
cout<<"请输入公式,如需退出请按CTRL + C。\nVER1.3 design by zuozhiwen.\n";
char S[LENGTH];
while(1)
{
cin.getline(S,LENGTH);
cout<<calc(S,strlen(S))<<endl;
}
}
}
golang 四则运算计算器yacc归约手写实现
缘起
最近拜读前桥和弥[日]的<<自制编程语言>>
开头一章便是教读者使用lex/yacc工具
制作四则运算器
其中yacc的移进/归约/梯度下降的思想很有启发
于是使用golang练习之
目标
- 制作一个四则运算器, 从os.Stdin读入一行表达式, 然后输出计算过程和结果
- 支持+ - * /
- 支持左右括号
- 支持负数
难点
记号扫描(lexer)
- 逐字符扫描记号
- 单字符记号可直接识别, + - * / ( )
多字符记号, 此处只有浮点数, 通过有限状态的转换进行识别
<INITIAL> + ''-'' = INT_STATUS
<INITIAL> + ''d'' = INT_STATUS
<INT_STATUS> + ''.'' = DOT_STATUS
<INT_STATUS> + ''SPACE | + | - | * | / | ( | )'' = INITIAL
<DOT_STATUS> + ''d'' = FRAG_STATUS
<FRAG_STATUS> + ''SPACE | + | - | * | / | ( | )'' = INITIAL
运算优先级
- /优先级最高, 可以立即归约计算
- 括号次之, 遇到右括号, 应当触发+ -归约
- 程序末尾, 没有新的记号剩余, 对+ -进行归约
识别负数
- 简单起见, 本程序总是使用浮点数作为基本计算单位
- 把负号识别为浮点数的可选部分: 浮点数 = -?d+(.d+)?
总体流程
- 从os.Stdin读入一行表达式字符串
- 逐字符扫描记号流, 放入记号队列
- 逐记号出队, 置入计算栈
- 判断栈顶是否符合归约条件, 是则进行计算
- 记号队列空, 对计算栈进行最终计算
- 输出结果
main.go
从os.Stdin循环读入行
调用lexer.Parse获得记号流
调用parser.Parse进行计算
func main() { reader := bufio.NewReader(os.Stdin) for { fmt.Printf("=> ") arrBytes, _, err := reader.ReadLine() if err != nil { panic(err.Error()) } line := strings.TrimSpace(string(arrBytes)) expression := line tokens, e := lexer.Parse(expression) if e != nil { println(e.Error()) } else { e,v := parser.Parse(tokens) if e != nil { println(e.Error()) } fmt.Println(strconv.FormatFloat(v, ''f'', 10, 64)) } } }
tokens/tokens.go
定义记号
package tokens type TOKENS string const IntLiteral TOKENS = "INT" const DoubleLiteral TOKENS = "DBL" const ADD TOKENS = "ADD" const SUB TOKENS = "SUB" const MUL TOKENS = "MUL" const DIV TOKENS = "DIV" const LB TOKENS = "LB" const RB TOKENS = "RB" const UNKNOWN TOKENS = "UNKNOWN" type Token struct { Token TOKENS Value string Position int } func OfRune(t TOKENS, r rune, from int) *Token { return &Token { Token: t, Value : string(r), Position: from, } } func OfString(t TOKENS, s string, from int) *Token { return &Token { Token: t, Value : s, Position: from, } }
states/states.go
定义lexer的状态
type STATES int const INITIAL STATES = 1 const INT_STATUS STATES = 11 const DOT_STATUS STATES = 12 const FRAG_STATUS STATES = 13
lexer/lexer.go
记号扫描
type tLexerState struct { state states.STATES tokens []*tokens.Token buffer []rune i0 int i1 int d0 int d1 int } func (me *tLexerState) AppendToken(t *tokens.Token) { me.tokens = append(me.tokens, t) } func (me *tLexerState) AppendChar(it rune) { me.buffer = append(me.buffer, it) } func (me *tLexerState) BufferSize() int { return len(me.buffer) } func (me *tLexerState) IntSize() int { return me.i1 - me.i0 + 1 } func (me *tLexerState) FragSize() int { return me.d1 - me.d0 + 1 } func Parse(line string) ([]*tokens.Token, error) { var state = &(tLexerState{ state: states.INITIAL, tokens: make([]*tokens.Token, 0), buffer: make([]rune, 0), i0 : 0, i1 : 0, d0: 0, d1: 0, }) for i, it := range line + "\n" { e := parseChar(state, i, it) if e != nil { return nil, e } } return state.tokens, nil } func parseChar(state *tLexerState, i int, it rune) error { var e error = nil switch state.state { case states.INITIAL: e = parseCharWhenInitial(state, i, it) break case states.INT_STATUS: e = parseCharWhenInt(state, i, it) break case states.DOT_STATUS: e = parseCharWhenDot(state, i, it) break case states.FRAG_STATUS: e = parseCharWhenFrag(state, i, it) break } return e } func parseCharWhenInitial(state *tLexerState, i int, it rune) error { if is_minus(it) || is_0_to_9(it) { state.state = states.INT_STATUS state.buffer = make([]rune, 0) state.buffer = append(state.buffer, it) state.i0 = i state.i1 = i } else if is_space(it){ return nil } else if is_add(it) { state.AppendToken(tokens.OfRune(tokens.ADD, it, i)) } else if is_sub(it) { state.AppendToken(tokens.OfRune(tokens.SUB, it, i)) } else if is_mul(it) { state.AppendToken(tokens.OfRune(tokens.MUL, it, i)) } else if is_div(it) { state.AppendToken(tokens.OfRune(tokens.DIV, it, i)) } else if is_lb(it) { state.AppendToken(tokens.OfRune(tokens.LB, it, i)) } else if is_rb(it) { state.AppendToken(tokens.OfRune(tokens.RB, it, i)) } else { return errors.New(fmt.Sprintf("parseCharWhenInitial, invalid char %c at %d", it, i)) } return nil } func parseCharWhenInt(state *tLexerState, i int, it rune) error { if is_0_to_9(it) { if state.BufferSize() >= 10 { return errors.New(fmt.Sprintf("too large int number at %v", i)) } else { state.AppendChar(it) state.i1 = i } } else if is_dot(it) { state.AppendChar(it) state.state = states.DOT_STATUS } else if is_space(it) { state.AppendToken(tokens.OfString(tokens.IntLiteral, string(state.buffer), state.i1)) state.state = states.INITIAL } else if is_rb(it) { state.AppendToken(tokens.OfString(tokens.IntLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.RB, it, i)) state.state = states.INITIAL } else if is_add(it) { state.AppendToken(tokens.OfString(tokens.IntLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.ADD, it, i)) state.state = states.INITIAL } else if is_sub(it) { state.AppendToken(tokens.OfString(tokens.IntLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.SUB, it, i)) state.state = states.INITIAL } else if is_mul(it) { state.AppendToken(tokens.OfString(tokens.IntLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.MUL, it, i)) state.state = states.INITIAL } else if is_div(it) { state.AppendToken(tokens.OfString(tokens.IntLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.DIV, it, i)) state.state = states.INITIAL } else { return errors.New(fmt.Sprintf("parseCharWhenInt, invalid char %c at %d", it, i)) } return nil } func parseCharWhenDot(state *tLexerState, i int, it rune) error { if is_0_to_9(it) { state.state = states.FRAG_STATUS state.AppendChar(it) state.d0 = i state.d1 = i } else { return errors.New(fmt.Sprintf("parseCharWhenDot, invalid char %c at %d", it, i)) } return nil } func parseCharWhenFrag(state *tLexerState, i int, it rune) error { if is_0_to_9(it) { if state.FragSize() >= 10 { return errors.New(fmt.Sprintf("too many chars for a double value at %d", i)) } else { state.AppendChar(it) state.d1 = i } } else if is_space(it) { state.AppendToken(tokens.OfString(tokens.DoubleLiteral, string(state.buffer), state.i1)) state.state = states.INITIAL } else if is_add(it) { state.AppendToken(tokens.OfString(tokens.DoubleLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.ADD, it, i)) state.state = states.INITIAL } else if is_sub(it) { state.AppendToken(tokens.OfString(tokens.DoubleLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.SUB, it, i)) state.state = states.INITIAL } else if is_mul(it) { state.AppendToken(tokens.OfString(tokens.DoubleLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.MUL, it, i)) state.state = states.INITIAL } else if is_div(it) { state.AppendToken(tokens.OfString(tokens.DoubleLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.DIV, it, i)) state.state = states.INITIAL } else if is_rb(it) { state.AppendToken(tokens.OfString(tokens.DoubleLiteral, string(state.buffer), state.i1)) state.AppendToken(tokens.OfRune(tokens.RB, it, i)) state.state = states.INITIAL } else { return errors.New(fmt.Sprintf("parseCharWhenFrag, invalid char %c at %d", it, i)) } return nil }
parser/tStackNode.go
定义计算栈的一个节点. 计算栈中有两种节点: 已归约的值节点, 和尚未计算的记号节点
type tStackNodeType int const NODE_VALUE tStackNodeType = 1 const NODE_TOKEN tStackNodeType = 2 type tStackNode struct { flag tStackNodeType token *tokens.Token value float64 } func newValueNode(value float64) *tStackNode { return &tStackNode{ flag: NODE_VALUE, value: value, token: nil, } } func newTokenNode(token *tokens.Token) *tStackNode { return &tStackNode{ flag: NODE_TOKEN, token: token, value: 0, } } func (me *tStackNode) getTokenType() tokens.TOKENS { switch me.flag { case NODE_VALUE: return tokens.DoubleLiteral case NODE_TOKEN: switch me.token.Token { case tokens.IntLiteral: fallthrough case tokens.DoubleLiteral: return tokens.DoubleLiteral default: return me.token.Token } } return tokens.UNKNOWN } func (me *tStackNode) getDoubleValue() float64 { switch me.flag { case NODE_VALUE: return me.value case NODE_TOKEN: switch me.token.Token { case tokens.IntLiteral: fallthrough case tokens.DoubleLiteral: v1,e1 := strconv.ParseFloat(me.token.Value, 64) if e1 != nil { panic(e1) } return v1 } } panic("value not avaiable") }
parser/parser.go
type tParser struct { tokens []*tokens.Token stack []*tStackNode total int position int } func newParser(tokens []*tokens.Token) *tParser { return &tParser{ tokens: tokens, stack: make([]*tStackNode, 0), total : len(tokens), position: -1, } } func (me *tParser) showStack() string { lst := make([]string, 0) for _,it := range me.stack { switch it.flag { case NODE_VALUE: lst = append(lst, strconv.FormatFloat(it.value, ''f'', 10, 64)) break case NODE_TOKEN: switch it.token.Token { case tokens.DoubleLiteral: fallthrough case tokens.IntLiteral: lst = append(lst, it.token.Value) break default: lst = append(lst, it.token.Value) break } } } return strings.Join(lst, " ") } func (me *tParser) moreToken() bool { return me.position < me.total - 1 } func (me *tParser) nextToken() *tokens.Token { if !me.moreToken() { return nil } me.position++ return me.currentToken() } func (me *tParser) currentToken() *tokens.Token { if me.position >= me.total { return nil } return me.tokens[me.position] } func (me *tParser) reduce() { sCurrentStack := "" var fnCheckState = func() { sStackState := me.showStack() if sStackState != sCurrentStack { sCurrentStack = sStackState fmt.Printf("stack => %s\n", sStackState) } } for { fnCheckState() if me.reduceMulOrDiv() { continue } if me.reduceBrackets() { continue } if !me.moreToken() { if me.reduceAddOrSub() { break } } fnCheckState() //time.Sleep(1*time.Second) break } } func (me *tParser) stackPop() *tStackNode { if me.isStackEmpty() { return nil } var iStackSize = len(me.stack) var last = me.stack[iStackSize - 1] me.stack = me.stack[:(iStackSize-1)] return last } func (me *tParser) stackPopN(n int) []*tStackNode { if me.isStackEmpty() { return nil } var iStackSize = len(me.stack) if iStackSize < n { return nil } var lstTailItems = me.stack[(iStackSize - n):] me.stack = me.stack[:(iStackSize-n)] return lstTailItems } func (me *tParser) stackTakeN(n int) []*tStackNode { if me.isStackEmpty() { return nil } var iStackSize = len(me.stack) if iStackSize < n { return nil } var lstHeadItems = me.stack[:n] me.stack = me.stack[n+1:] return lstHeadItems } func (me *tParser) stackPush(it *tStackNode) { me.stack = append(me.stack, it) } func (me *tParser) reduceMulOrDiv() bool { if me.isStackEmpty() { return false } if me.isStackRMatch(tokens.DoubleLiteral, tokens.MUL, tokens.DoubleLiteral) { var lstTailNodes = me.stackPopN(3) v1 := lstTailNodes[0].getDoubleValue() v2 := lstTailNodes[2].getDoubleValue() var v = v1*v2 me.stackPush(newValueNode(v)) return true } else if me.isStackRMatch(tokens.DoubleLiteral, tokens.DIV, tokens.DoubleLiteral) { var lstTailNodes = me.stackPopN(3) v1 := lstTailNodes[0].getDoubleValue() v2 := lstTailNodes[2].getDoubleValue() if v2 == 0 { panic(fmt.Sprintf("div by zero, %v / %v", v1, v2)) } var v = v1/v2 me.stackPush(newValueNode(v)) return true } return false } func (me *tParser) reduceBrackets() bool { if me.isStackEmpty() { return false } if me.isStackRMatch(tokens.RB) { rb := me.stackPop() var v float64 = 0 for { if me.isStackRMatch(tokens.LB, tokens.DoubleLiteral) { var lstTailNodes = me.stackPopN(2) v += lstTailNodes[1].getDoubleValue() me.stackPush(newValueNode(v)) return true } else if me.isStackRMatch(tokens.ADD, tokens.DoubleLiteral) { var lstTailNodes = me.stackPopN(2) v1 := lstTailNodes[1].getDoubleValue() v = v + v1 } else if me.isStackRMatch(tokens.SUB, tokens.DoubleLiteral) { var lstTailNodes = me.stackPopN(2) v1 := lstTailNodes[1].getDoubleValue() v = v - v1 } else { panic(fmt.Sprintf("LB not found at %v", rb.token.Position)) } } } return false } func (me *tParser) reduceAddOrSub() bool { var v float64 = 0 for { if me.isStackEmpty() { break } if me.isStackRMatch(tokens.ADD, tokens.DoubleLiteral) { var lstTailNodes = me.stackPopN(2) v1 := lstTailNodes[1].getDoubleValue() v = v + v1 } else if me.isStackRMatch(tokens.SUB, tokens.DoubleLiteral) { var lstTailNodes = me.stackPopN(2) v1 := lstTailNodes[1].getDoubleValue() v = v - v1 } else if len(me.stack)==1 && me.isStackRMatch(tokens.DoubleLiteral) { it := me.stackPop() v += it.getDoubleValue() me.stackPush(newValueNode(v)) return true } else { panic("invalid expression") } } return false } func (me *tParser) isStackEmpty() bool { return len(me.stack) == 0 } func (me *tParser) isStackRMatch(args...tokens.TOKENS) bool { var iArgsSize = len(args) if iArgsSize <= 0 { return false } var iStackSize = len(me.stack) if iStackSize < iArgsSize { return false } for i,it := range args { var n = iStackSize - iArgsSize + i var xStackNode = me.stack[n] if it != xStackNode.getTokenType() { return false } } return true } func (me *tParser) isStackLMatch(args...tokens.TOKENS) bool { var iArgsSize = len(args) if iArgsSize <= 0 { return false } var iStackSize = len(me.stack) if iStackSize < iArgsSize { return false } for i,it := range args { var xStackNode = me.stack[i] if it != xStackNode.getTokenType() { return false } } return true } func (me *tParser) parse() (error, float64) { for { t := me.nextToken() if t == nil { break } me.stackPush(newTokenNode(t)) me.reduce() } var iStackSize = len(me.stack) if iStackSize == 1 && me.stack[0].getTokenType() == tokens.DoubleLiteral { return nil, me.stack[0].getDoubleValue() } panic(fmt.Sprintf("failed parsing expression %s", me.showStack())) } func Parse(tokens []*tokens.Token) (error, float64) { parser := newParser(tokens) return parser.parse() }
输出
=> 1+2*(3-4*(5/6+(7-8*9)))
stack => 1
stack => 1 +
stack => 1 + 2
stack => 1 + 2 *
stack => 1 + 2 * (
stack => 1 + 2 * ( 3
stack => 1 + 2 * ( 3 -
stack => 1 + 2 * ( 3 - 4
stack => 1 + 2 * ( 3 - 4 *
stack => 1 + 2 * ( 3 - 4 * (
stack => 1 + 2 * ( 3 - 4 * ( 5
stack => 1 + 2 * ( 3 - 4 * ( 5 /
stack => 1 + 2 * ( 3 - 4 * ( 5 / 6
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 +
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + (
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + ( 7
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + ( 7 -
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + ( 7 - 8
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + ( 7 - 8 *
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + ( 7 - 8 * 9
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + ( 7 - 72.0000000000
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + ( 7 - 72.0000000000 )
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + -65.0000000000
stack => 1 + 2 * ( 3 - 4 * ( 0.8333333333 + -65.0000000000 )
stack => 1 + 2 * ( 3 - 4 * -64.1666666667
stack => 1 + 2 * ( 3 - -256.6666666667
stack => 1 + 2 * ( 3 - -256.6666666667 )
stack => 1 + 2 * 259.6666666667
stack => 1 + 519.3333333333
520.3333333333
=>
以上就是golang 四则运算计算器 yacc 归约手写实现的详细内容,更多关于golang四则运算计算器yacc归约的资料请关注其它相关文章!
- golang实现ftp实时传输文件的案例
- golang http 连接超时和传输超时的例子
- Golang栈结构和后缀表达式实现计算器示例
- golang架构设计开闭原则手写实现
- golang 随机数的两种方式
- Golang切片删除指定元素的三种方法对比
- Golang 实现 RTP音视频传输示例详解
我们今天的关于PHP实现的简单四则运算计算器功能示例和php实现的简单四则运算计算器功能示例图的分享就到这里,谢谢您的阅读,如果想了解更多关于C#基于简单工厂模式实现的计算器功能示例、C#实现的简单整数四则运算计算器功能示例、C++实现能四则运算计算器、golang 四则运算计算器yacc归约手写实现的相关信息,可以在本站进行搜索。
本文标签: