// EvaluateExpression evaluates a arithmetic expression and returns the result value.
func EvaluateExpression(e string) (int, error) {
	e += "#" // used as terminated symbol
	operator := list.NewStack(false, false, true)
	operator.Push("#")
	operand := list.NewStack(false, false, true)

	for !operator.Empty() {
		c := ""
		if len(e) != 0 {
			c = string(e[0])
		}
		if c != "+" && c != "-" && c != "*" && c != "/" && c != "(" && c != ")" && c != "#" && c != "" {
			operand.Push(c)
		} else {
			opt, _ := operator.Top()
			switch operandPrecede(opt.(string), c) {
			case 1:
				operator.Pop()
				b, _ := operand.Top()
				operand.Pop()
				a, _ := operand.Top()
				operand.Pop()
				r, err := operate(a.(string), opt.(string), b.(string))
				if err != nil {
					return 0, err
				}
				operand.Push(r)
				continue
			case 0:
				operator.Pop()
			case -1:
				operator.Push(c)
			}
		}
		if len(e) >= 2 {
			e = e[1:len(e)]
		}
	}
	r, err := operand.Top()
	if err != nil {
		return 0, err
	}
	r, err = strconv.Atoi(r.(string))
	if err != nil {
		return 0, err
	}
	return r.(int), err
}
// MatchQuotationMark checks whether input quotation marks is pair-matched.
func MatchQuotationMark(q string) bool {
	s := list.NewStack(false, false, true)
	for len(q) != 0 {
		m := string(q[0])
		t, err := s.Top()
		if err != nil {
			s.Push(m)
		} else {
			if t == "[" && m == "]" {
				s.Pop()
			} else if t == "(" && m == ")" {
				s.Pop()
			} else if t == "{" && m == "}" {
				s.Pop()
			} else {
				s.Push(m)
			}
		}
		q = q[1:len(q)]
	}
	if !s.Empty() {
		return false
	}
	return true
}
// NumeralConversion converts i (positive) from one numeral base to another.
func NumeralConversion(fromBase, toBase int, i string) (string, error) {
	s := list.NewStack(false, false, true)
	pow := 1
	iTenBase := 0
	for len(i) != 0 {
		num, err := strconv.Atoi(i[len(i)-1 : len(i)])
		if err != nil {
			return "", err
		}
		iTenBase += (num * pow)
		pow *= fromBase
		i = i[0 : len(i)-1]
	}
	for iTenBase != 0 {
		s.Push(iTenBase % toBase)
		iTenBase /= toBase
	}
	var buffer bytes.Buffer
	for !s.Empty() {
		v, _ := s.Top()
		buffer.WriteString(strconv.Itoa(v.(int)))
		s.Pop()
	}
	return buffer.String(), nil
}