1 Star 1 Fork 1

U语言组织 / U语言

forked from 秋来冬风 / U语言 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
expr.go 12.10 KB
一键复制 编辑 原始数据 按行查看 历史
package ast
import (
"fmt"
"sync"
"gitee.com/u-language/u-language/ucom/enum"
"gitee.com/u-language/u-language/ucom/errcode"
"gitee.com/u-language/u-language/ucom/lex"
)
// found 是find的过去式
const opexpr_found_assign = "opexpr_found_assign"
const call_parser_fail = "call_parser_fail"
const op_bug = "op_bug"
const parserobj_nil = "parserobj_nil"
type stack struct {
opStack []enum.OPSymbol
valueStack []Expr
FuncInfo *FuncInfo
opIndex int
valueIndex int
err errcode.ErrCode
inAutoFree bool
BeforeOp bool //Before operator
}
const (
equal int8 = 0 //等于
less_than int8 = -1 //小于
greater_than int8 = 1 //大于
)
// 操作的优先级枚举值,值越小,优先级越低
const (
logicOr = iota + 1 // ||
logicAND // &&
or // |
xor // ^
and // and
judgeEqual // == !=
compareSize // < >
addAndSub // + -
mulAndDlvAndRemain // * / %
paren // parentheses (
)
var stackpool = sync.Pool{
New: func() interface{} {
return &stack{
valueIndex: -1,
opIndex: -1,
valueStack: make([]Expr, 0, 2),
opStack: make([]enum.OPSymbol, 0, 1),
}
},
}
func newstack(FuncInfo *FuncInfo, inAutoFree bool) (s *stack) {
s = stackpool.Get().(*stack)
s.FuncInfo, s.inAutoFree = FuncInfo, inAutoFree
return
}
// PushOp 将一个运算符放入运算符栈栈顶
func (s *stack) PushOp(op enum.OPSymbol, t *Tree, line *lex.Line) {
if s.BeforeOp {
s.Panic(t, line, nil, errcode.AdjacentOp)
}
s.opIndex++
s.opStack = append(s.opStack[0:s.opIndex], op)
s.BeforeOp = true
}
// PushValue 将一个值放入值栈栈顶
func (s *stack) PushValue(v Expr) {
s.valueIndex++
s.valueStack = append(s.valueStack[0:s.valueIndex], v)
s.BeforeOp = false
}
// PopOp 将一个运算符从运算符栈栈顶弹出
func (s *stack) PopOp() (op enum.OPSymbol) {
op = s.opStack[s.opIndex]
s.opIndex--
return
}
// PopValue 将一个值从值栈栈顶弹出
func (s *stack) PopValue() (n Expr) {
n = s.valueStack[s.valueIndex]
s.valueIndex--
return
}
// OpStackEmpty 判断运算符栈是否为空
func (s *stack) OpStackEmpty() bool {
return s.opIndex == -1
}
// CmpOp 比较运算符与栈顶运算符的优先级
//
// 对于不能处理的,将panic
func (s *stack) CmpOp(op enum.OPSymbol) int8 {
op2 := s.opStack[s.opIndex]
if op2 == enum.LPARENOP || op2 == enum.CommaOP {
return greater_than
}
openum := opPriorityEnum(op)
op2enum := opPriorityEnum(op2)
if openum > op2enum {
return greater_than
} else if openum < op2enum {
return less_than
}
if openum == op2enum { //如果优先级相同,右边的比左边小
return less_than
}
return 0
}
// opPriorityEnum 返回操作的优先级枚举值
func opPriorityEnum(op enum.OPSymbol) int8 {
switch op {
case enum.NoEqualOP, enum.EqualOP:
return judgeEqual
case enum.LessOP, enum.GreaterOP:
return compareSize
case enum.ADDOP, enum.SUBOP:
return addAndSub
case enum.MULOP, enum.DIVOP, enum.RemainOP:
return mulAndDlvAndRemain
case enum.AndOP:
return and
case enum.OrOP:
return or
case enum.XorOp:
return xor
case enum.LogicAndOP:
return logicAND
case enum.LogicOrOP:
return logicOr
case enum.LPARENOP:
return paren
default:
panic(fmt.Errorf("不能处理的 op:%+v", op))
}
}
// AutoPush 自动将一个 [lex.Token] 推入值栈或运算符栈
func (s *stack) AutoPush(t *Tree, tk *lex.Token, line *lex.Line) {
switch tk.TYPE {
case lex.ADD: //是加号
s.AutoCmpAndPush(enum.ADDOP, t, line)
case lex.SUB: //是减号
s.AutoCmpAndPush(enum.SUBOP, t, line)
case lex.MUL: //是乘号
s.AutoCmpAndPush(enum.MULOP, t, line)
case lex.DIV: //是除号
s.AutoCmpAndPush(enum.DIVOP, t, line)
case lex.Equal: //比较是否相等
s.AutoCmpAndPush(enum.EqualOP, t, line)
case lex.NoEqual: //比较是否不相等
s.AutoCmpAndPush(enum.NoEqualOP, t, line)
case lex.Less: //比较是否小于
s.AutoCmpAndPush(enum.LessOP, t, line)
case lex.Greater: //比较是否大于
s.AutoCmpAndPush(enum.GreaterOP, t, line)
case lex.Remain: //是取余数
s.AutoCmpAndPush(enum.RemainOP, t, line)
case lex.AND: //是位与运算
s.AutoCmpAndPush(enum.AndOP, t, line)
case lex.Or: //是位或运算
s.AutoCmpAndPush(enum.OrOP, t, line)
case lex.Xor: //是异或运算
s.AutoCmpAndPush(enum.XorOp, t, line)
case lex.LogicAND: //是逻辑与运算
s.AutoCmpAndPush(enum.LogicAndOP, t, line)
case lex.LogicOr: //是逻辑或运算
s.AutoCmpAndPush(enum.LogicOrOP, t, line)
case lex.NUMBER, lex.NAME, lex.FLOAT, lex.String, lex.TRUE, lex.FALSE, lex.LEA, lex.Deref, lex.Nil: //可能是值
obj := parserObject(t, tk, line, s.FuncInfo)
if obj == nil {
panic(parserobj_nil)
}
s.PushValue(obj)
case lex.ASSIGN: //有赋值时不可能产生运算表达式
s.Panic(t, line, nil, errcode.AFIOE)
panic(opexpr_found_assign)
case lex.LPAREN: //如果是左小括号
s.PushOp(enum.LPARENOP, t, line)
case lex.RPAREN: //如果是右小括号
for !s.OpStackEmpty() {
op := s.PopOp() //弹出一个运算符
if op == enum.LPARENOP || op == enum.CommaOP {
break
}
src2 := s.PopValue() //弹出右边操作数
src1 := s.PopValue() //弹出左边操作数
expr := NewOpExpr(op, src1, src2) //将运算后的值压入值栈栈顶
expr.Inparen = true
s.PushValue(expr)
}
case lex.OnlyDeref: //如果是解引用
s.AutoCmpAndPush(enum.DerefOP, t, line)
case lex.Comma: //如果是逗号
s.PushOp(enum.CommaOP, t, line)
case lex.MoreThanJustTokensWithBrackts: //如果是不止中括号的token,视为索引表达式
l := *tk.PtrMoreThanJustTokensWithBracktsS().Ptr
i := parserIndexExpr(t, line, &l[0], &l[1], s.FuncInfo)
if i == nil {
s.Panic(t, line, nil, errcode.OPbug)
panic(op_bug)
}
s.PushValue(i)
default:
err := token_typ_err[tk.TYPE]
if err != errcode.NoErr {
s.Panic(t, line, nil, err)
} else {
s.Panic(t, line, nil, errcode.OPbug)
}
panic(op_bug)
}
}
func (s *stack) Panic(t *Tree, line *lex.Line, msg errcode.Msg, err ...errcode.ErrCode) {
if s.err != errcode.NoErr {
err_slice := make([]errcode.ErrCode, len(err)+1)
err_slice[0] = s.err
for i, v := range err {
err_slice[i+1] = v
}
t.Panic(line, nil, err_slice...)
} else {
t.Panic(line, nil, err...)
}
}
// AutoCmpAndPush 自动以合适的方式将运算符压入栈中
func (s *stack) AutoCmpAndPush(op enum.OPSymbol, t *Tree, line *lex.Line) {
if s.OpStackEmpty() { //空栈
s.PushOp(op, t, line) //直接压入栈中
} else {
switch s.CmpOp(op) {
case less_than:
s.AutoPopAndCmp(op)
s.PushOp(op, t, line)
case greater_than:
s.PushOp(op, t, line)
}
}
}
// AutoPopAndCmp 自动将运算符栈和值栈做出栈操作,直到运算符优先级大于运算符栈栈顶运算符优先级,或运算符栈为空
func (s *stack) AutoPopAndCmp(op enum.OPSymbol) {
for !s.OpStackEmpty() && s.CmpOp(op) == less_than && len(s.valueStack) >= 2 {
op := s.PopOp() //弹出一个运算符
if op == enum.DerefOP {
s.PushValue(&Dereference{Value: s.PopValue()})
continue
}
src2 := s.PopValue() //弹出右边操作数
src1 := s.PopValue() //弹出左边操作数
s.PushValue(NewOpExpr(op, src1, src2)) //将运算后的值压入值栈栈顶
}
}
// AutoPop 自动将当前的运算符和值转换为一个表达式
func (s *stack) AutoPop(t *Tree, line *lex.Line) (n Expr) {
for !s.OpStackEmpty() && s.valueIndex >= 1 { //还有运算符及至少两个值
op := s.PopOp() //弹出一个运算符
if op == enum.CommaOP { //如果出现意外的逗号
s.Panic(t, line, nil, errcode.UnexpectedComma)
panic(op_bug)
}
src2 := s.PopValue() //弹出右边操作数
src1 := s.PopValue() //弹出左边操作数
s.PushValue(NewOpExpr(op, src1, src2)) //将运算后的值压入值栈栈顶
}
if s.valueIndex != 0 { //不是只有结果一个
return nil
}
return s.PopValue() //弹出转换后的表达式
}
// AutoExpr 自动将一个赋值文本转换为赋值节点
func (s *stack) AutoExpr(t *Tree, line *lex.Line) (ret *ASSIGNNode) {
var dest Expr = parserObject(t, &line.Value[0], line, s.FuncInfo) //解析目的操作数
llen := len(line.Value)
defer func() {
if err := recover(); err != nil {
if predefined_error(err) { //出现预定义的错误
ret = nil
return
}
panic(err)
}
}()
for i := 2; i < llen; i++ {
if s.isCall(t, line, &i) {
continue
}
s.AutoPush(t, &line.Value[i], line) //将源操作数和运算符入栈
}
node := s.AutoPop(t, line) //获取表达式
if node == nil { //没有成功转换为一个表达式
s.Panic(t, line, nil, errcode.OPbug)
return nil
}
ret = NewASSIGNNode(dest, node) //创建赋值节点
return ret
}
// AutoExprNode 自动将一个表达式转换为表达式节点
func (s *stack) AutoExprNode(t *Tree, line *lex.Line) (ret Expr) {
llen := len(line.Value)
defer func() {
if err := recover(); err != nil {
if predefined_error(err) { //出现预定义的错误
ret = nil
return
}
panic(err)
}
}()
for i := 0; i < llen; i++ {
if s.isCall(t, line, &i) {
continue
}
s.AutoPush(t, &line.Value[i], line) //将源操作数和运算符入栈
}
ret1 := s.AutoPop(t, line) //获取表达式
if ret1 == nil && s.valueIndex != -1 && s.opIndex != -1 { //非空行,没有成功转换为一个表达式
s.Panic(t, line, nil, errcode.OPbug)
}
return ret1
}
// AutoExprNode 自动将一个参数列表为表达式节点
func (s *stack) AutoParameList(t *Tree, line *lex.Line) (ret []Expr) {
llen := len(line.Value)
defer func() {
if err := recover(); err != nil {
if predefined_error(err) { //出现预定义的错误
return
}
panic(err)
}
}()
// 对于 name([ParameList]) 是无参函数调用
if llen == 3 {
return nil
}
// 对于 name(ParameList) 从词法分析结果偏移量2开始处理,因为这个函数从parserCall调用,最后面肯定是)
for i := 2; i < llen-1; i++ {
if s.isCall(t, line, &i) {
continue
}
s.AutoPush(t, &line.Value[i], line) //将源操作数和运算符入栈
}
for !s.OpStackEmpty() && s.valueIndex >= 1 { //还有运算符及至少两个值
op := s.PopOp() //弹出一个运算符
if op == enum.CommaOP { //跳过逗号
continue
}
src2 := s.PopValue() //弹出右边操作数
src1 := s.PopValue() //弹出左边操作数
s.PushValue(NewOpExpr(op, src1, src2)) //将运算后的值压入值栈栈顶
}
ret = s.valueStack
s.valueStack = nil
return ret
}
// isCall 判断是否存在函数调用并自动处理
func (s *stack) isCall(t *Tree, line *lex.Line, i *int) bool {
llen := len(line.Value)
match := leftRightMatch{}
if *i+1 != llen && line.Value[*i+1].TYPE == lex.LPAREN { //有左小括号,视为函数调用
old, ok := *i, false
forcheck:
for *i+1 < llen {
*i++
switch line.Value[*i].TYPE {
case lex.RPAREN: //发现右小括号
match.rightNum++
if match.Ok() { //左右小括号数量匹配,视为完整的函数调用
nline := lex.NewLine(line.Linenum, line.Value[old:*i+1])
ret := parserCall(t, &nline, s.inAutoFree, s.FuncInfo)
if ret == nil { //如果解析函数调用失败
panic(call_parser_fail)
}
s.PushValue(ret)
ok = true
break forcheck
}
case lex.LPAREN: //发现左小括号
match.leftNum++
}
}
if !ok { //如果没有右小括号
if s.err != errcode.NoErr {
t.Panic(line, nil, s.err, errcode.CallErr, errcode.EmptyRPAREN)
} else {
t.Panic(line, nil, errcode.CallErr, errcode.EmptyRPAREN)
}
panic(call_parser_fail)
}
return true
}
return false
}
func (s *stack) Close() {
s.opIndex, s.valueIndex, s.opStack, s.err, s.BeforeOp = -1, -1, s.opStack[0:0], errcode.NoErr, false
stackpool.Put(s)
}
func predefined_error(err interface{}) bool {
if str, ok := err.(string); ok && (str == opexpr_found_assign || str == call_parser_fail || str == op_bug || str == parserobj_nil) { //出现预定义的错误
return true
}
return false
}
Go
1
https://gitee.com/u-language/u-language.git
git@gitee.com:u-language/u-language.git
u-language
u-language
U语言
a214d6007862

搜索帮助

53164aa7 5694891 3bd8fe86 5694891