GVKun编程网logo

PHP实现的简单四则运算计算器功能示例(php实现的简单四则运算计算器功能示例图)

15

在本文中,我们将详细介绍PHP实现的简单四则运算计算器功能示例的各个方面,并为您提供关于php实现的简单四则运算计算器功能示例图的相关解答,同时,我们也将为您带来关于C#基于简单工厂模式实现的计算器功

在本文中,我们将详细介绍PHP实现的简单四则运算计算器功能示例的各个方面,并为您提供关于php实现的简单四则运算计算器功能示例图的相关解答,同时,我们也将为您带来关于C#基于简单工厂模式实现的计算器功能示例、C#实现的简单整数四则运算计算器功能示例、C++实现能四则运算计算器、golang 四则运算计算器yacc归约手写实现的有用知识。

本文目录一览:

PHP实现的简单四则运算计算器功能示例(php实现的简单四则运算计算器功能示例图)

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#基于简单工厂模式实现的计算器功能示例

本文实例讲述了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#实现的简单整数四则运算计算器功能示例

本文实例讲述了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++实现能四则运算计算器

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归约手写实现

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()
}

输出

=&gt; 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归约手写实现的相关信息,可以在本站进行搜索。

本文标签: