找回密码
 点一下
查看: 2096|回复: 16

表达式求值

[复制链接]
发表于 2009-6-8 16:06:54 | 显示全部楼层 |阅读模式
目前只支持整数的加,减,乘,除,取余,当然还有括号

本来想加上自定义变量的,不过期末太忙估计是没时间了

加了简单的错误提示,但仅仅是提示,不会中止运算.
[jass]
globals   
    constant integer MSG_ERROR = 0
    constant integer MSG_OUTPUT = 1
   
    constant integer TYPE_SYSTEM = 0
    constant integer TYPE_INTEGER = 1
    constant integer TYPE_OPERATOR = 2
   
    constant integer SYSTEM_BEGIN = 0
    constant integer SYSTEM_END = 1
   
    integer array udg_stackOptr
    integer udg_stackOptr_top = -1
    integer array udg_stackOpnd
    integer udg_stackOpnd_top = -1
   
    integer array udg_line_type
    integer array udg_line_index
    integer udg_line_top = 8191
    integer udg_line_bottom = 0
      
    integer udg_TempA
    integer udg_TempB
   
    integer udg_parse_stateA = 0
    integer udg_parse_stateB = 0
endglobals

function Console takes integer msg_type, string msg returns nothing
    if msg_type == MSG_ERROR then
        call BJDebugMsg("|cffff0303错误: "+msg+"|r")
    elseif msg_type == MSG_OUTPUT then
        call BJDebugMsg("|cff0042ff"+msg+"|r")
    endif
endfunction

function stackOptrClear takes nothing returns nothing
    set udg_stackOptr_top = -1
endfunction
function stackOptrPush takes integer value returns nothing
    if udg_stackOptr_top == 8191 then
        return
    endif
   
    set udg_stackOptr_top = udg_stackOptr_top + 1
    set udg_stackOptr[udg_stackOptr_top] = value
endfunction
function stackOptrPop takes nothing returns integer
    if udg_stackOptr_top == -1 then
        return 0
    endif
   
    set udg_stackOptr_top = udg_stackOptr_top - 1
    return udg_stackOptr[udg_stackOptr_top+1]
endfunction
function stackOptrGetTop takes nothing returns integer
    return udg_stackOptr[udg_stackOptr_top]
endfunction

function stackOpndClear takes nothing returns nothing
    set udg_stackOpnd_top = -1
endfunction
function stackOpndPush takes integer value returns nothing
    if udg_stackOpnd_top == 8191 then
        return
    endif
   
    set udg_stackOpnd_top = udg_stackOpnd_top + 1
    set udg_stackOpnd[udg_stackOpnd_top] = value
endfunction
function stackOpndPop takes nothing returns integer
    if udg_stackOpnd_top == -1 then
        return 0
    endif
   
    set udg_stackOpnd_top = udg_stackOpnd_top - 1
    return udg_stackOpnd[udg_stackOpnd_top+1]
endfunction

function isLineEmpty takes nothing returns boolean
    return udg_line_bottom - udg_line_top == 1 or udg_line_top - udg_line_bottom ==8191
endfunction
function linePush takes integer a, integer b returns nothing
    if udg_line_top == 8191 then
        set udg_line_top = 0
    else
        set udg_line_top = udg_line_top + 1
    endif
   
    set udg_line_type[udg_line_top] = a
    set udg_line_index[udg_line_top] = b
endfunction
function linePop takes nothing returns nothing   
    set udg_TempA = udg_line_type[udg_line_bottom]
    set udg_TempB = udg_line_index[udg_line_bottom]
   
    if udg_line_bottom == 8191 then
        set udg_line_bottom = 0
    else
        set udg_line_bottom = udg_line_bottom + 1
    endif
endfunction

function isSpace takes string s returns boolean
    return SubString(s, 0, 1)==" "
endfunction
function isDigit takes string s returns boolean
    return S2I(s) > 0 or SubString(s, 0, 1)=="0"
endfunction
function parseInteger takes string s, integer index returns integer
    local integer i = index
    local integer len = StringLength(s)
   
    loop
        exitwhen i >= len
        if not isDigit(SubString(s, i, i+1)) then
            return i
        endif
        set i = i + 1
    endloop
   
    return len
endfunction

function checkStateA takes integer a,integer i returns nothing
    if udg_parse_stateA != a then
        call Console(MSG_ERROR, "语法错误("+I2S(i)+")!")
    endif
endfunction

function parseMain takes string s returns nothing
    local integer i = 0
    local integer j
    local integer len = StringLength(s)
    local string c
   
    call linePush(TYPE_SYSTEM, SYSTEM_BEGIN)
    set udg_parse_stateA = 0
    set udg_parse_stateB = 0
        
    loop
        exitwhen i >= len
        set c = SubString(s, i, i+1)
        if isSpace(c) then
        elseif isDigit(c) then
            call checkStateA(0, i)
            set udg_parse_stateA = 1
            set j = parseInteger(s, i)
            call linePush(TYPE_INTEGER, S2I(SubString(s, i, j)))
            set i = j - 1
        elseif c=="+" then
            call checkStateA(1, i)
            set udg_parse_stateA = 0
            call linePush(TYPE_OPERATOR, '+')
        elseif c=="-" then
            call checkStateA(1, i)
            set udg_parse_stateA = 0
            call linePush(TYPE_OPERATOR, '-')
        elseif c=="*" then
            call checkStateA(1, i)
            set udg_parse_stateA = 0
            call linePush(TYPE_OPERATOR, '*')
        elseif c=="/" then
            call checkStateA(1, i)
            set udg_parse_stateA = 0
            call linePush(TYPE_OPERATOR, '/')
        elseif c=="%" then
            call checkStateA(1, i)
            set udg_parse_stateA = 0
            call linePush(TYPE_OPERATOR, '%')
        elseif c=="(" then
            call checkStateA(0, i)
            set udg_parse_stateB = udg_parse_stateB + 1
            call linePush(TYPE_OPERATOR, '(')
        elseif c==")" then
            call checkStateA(1, i)
            set udg_parse_stateB = udg_parse_stateB - 1
            call linePush(TYPE_OPERATOR, ')')
        else
            call Console(MSG_ERROR, "不合法的字符("+c+")")
        endif
        set i = i + 1
    endloop
   
    if udg_parse_stateB != 0 then
        call Console(MSG_ERROR, "括号不匹配!")
    endif
    call linePush(TYPE_SYSTEM, SYSTEM_END)
endfunction

function Precede takes integer a, integer b returns boolean
    local integer alv = 0
    local integer blv = 0
   
    if a=='#' then
        return true
    elseif a=='(' then
        return true
    elseif b=='(' then
        return true
    elseif b==')' then
        return false
    endif
   
    if a=='+' or a=='-' then
        set alv = 1
    elseif a=='*' or a=='/' or a=='%' then
        set alv = 2
    endif
   
    if b=='+' or b=='-' then
        set blv = 1
    elseif b=='*' or b=='/' or b=='%' then
        set blv = 2
    endif
   
    return alv < blv
endfunction

function Operate takes integer a, integer b, integer op returns integer
    if op=='+' then
        return a+b
    elseif op=='-' then
        return a-b
    elseif op=='*' then
        return a*b
    elseif op=='/' then
        if b == 0 then
            call Console(MSG_ERROR, "除数为零!")
        endif
        return a/b
    elseif op=='%' then
        if b == 0 then
            call Console(MSG_ERROR, "除数为零!")
        endif
        return a-a/b*b
    endif
    return 0
endfunction

function runMain takes nothing returns nothing
    local integer count = 0
    local integer a
    local integer b
    loop
        exitwhen count == 10 or isLineEmpty()
        set count = count + 1
        call linePop()
        if udg_TempA == TYPE_SYSTEM then
            if udg_TempB == SYSTEM_BEGIN then
                call stackOptrClear()
                call stackOpndClear()
                call stackOptrPush('#')
            elseif udg_TempB == SYSTEM_END then
                loop
                    exitwhen stackOptrGetTop()=='#'
                    set a = stackOpndPop()
                    set b = stackOpndPop()
                    call stackOpndPush(Operate(b, a, stackOptrPop()))
                endloop
            
                call Console(MSG_OUTPUT, I2S(stackOpndPop()))
               
                call stackOptrClear()
                call stackOpndClear()               
            endif
        elseif udg_TempA == TYPE_INTEGER then
            call stackOpndPush(udg_TempB)
        elseif udg_TempA == TYPE_OPERATOR then
            loop
                if Precede(stackOptrGetTop(), udg_TempB) then
                    if stackOptrGetTop()=='(' and udg_TempB==')' then
                        call stackOptrPop()
                    else   
                        call stackOptrPush(udg_TempB)
                    endif
                    exitwhen true
                else
                    set a = stackOpndPop()
                    set b = stackOpndPop()
                    call stackOpndPush(Operate(b, a, stackOptrPop()))
                endif
            endloop
        endif
    endloop
endfunction

function Trig_test_Action takes nothing returns nothing
    call parseMain(GetEventPlayerChatString())
endfunction

function InitTrig_test takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterPlayerChatEvent(t, Player(0), "", false)
    call TriggerAddAction(t, function Trig_test_Action)
    call TimerStart(CreateTimer(), 0.01, TRUE, function runMain)
    set t = null
endfunction
[/jass]

在WE里弄全局变量太麻烦,所以我是用mpq工具导入j文件的,要看代码就用mpq导出j文件吧,we里看不到的......
counter.w3x (24 KB, 下载次数: 22)

评分

参与人数 1威望 +21 收起 理由
血戮魔动冰 + 21

查看全部评分

发表于 2009-6-8 16:39:22 | 显示全部楼层
沙发。

楼主要看看我现在的japi的样子吗。。
回复

使用道具 举报

发表于 2009-6-9 13:19:35 | 显示全部楼层
这东西……………………跟魔兽无关吧…………
回复

使用道具 举报

发表于 2009-6-9 15:13:29 | 显示全部楼层
魔兽计算机……
话说Jass还真是强大
回复

使用道具 举报

发表于 2009-6-9 15:48:02 | 显示全部楼层
为什么我想到的是yacc和lex………………
回复

使用道具 举报

 楼主| 发表于 2009-6-10 02:52:23 | 显示全部楼层
引用第1楼thewisp1于2009-06-08 16:39发表的  :
沙发。

楼主要看看我现在的japi的样子吗。。

等考完试吧
引用第4楼zhuzeitou于2009-06-09 15:48发表的  :
为什么我想到的是yacc和lex………………

这个还没这么高级.......
回复

使用道具 举报

发表于 2009-6-10 06:37:10 | 显示全部楼层
自定义变量
是啥?

n次元方程求解?
回复

使用道具 举报

发表于 2009-6-10 06:49:09 | 显示全部楼层
简单的中缀表达式求值。

话说对于括号,我一直是喜欢使用递归的方法求解。虽说效率低了些,但是非常自然(将括号中的内容看作子表达式)。属递归下降分析法。

愿意的话 完全可以在Jass的基础上做成一个虚拟机(解释型的或者编译解释型的都可以),执行自己定义的语言,不过有什么用呢~~~~

lex和yacc是历史悠久的经典工具,不过我更喜欢ANTLR和Spirit。
回复

使用道具 举报

发表于 2009-6-10 07:25:34 | 显示全部楼层
靠,意义不明...

话说你期末还有功夫做这样的东西...

现在卡位,发布命令,不影响UI的选择,欺骗平台检测都做好了

就差怎样用war3.org登录BN了
回复

使用道具 举报

发表于 2009-6-10 14:24:03 | 显示全部楼层
不能说完全没用吧,如果一个地图分开多个人做的话,可以让不太懂JASS的人也能实现想要的表达式求值而不是修改代码。

比如类似图中的物品合成的设置就比较直观。
QQ截图未命名.jpg
回复

使用道具 举报

发表于 2009-6-11 20:08:04 | 显示全部楼层
那还不如用分割字符串的方法
回复

使用道具 举报

发表于 2009-6-11 21:57:45 | 显示全部楼层
于是,偶想起了N年前初学编程老师给的题目:编写一个解析字符串的计算器。

用字符串做合成条件么。。。直观是直观。。

其实应该弄个自定义函数,从字符串读取合成信息
回复

使用道具 举报

发表于 2009-6-11 22:19:20 | 显示全部楼层
我这个周的VB作业是一个计算器
改一改交上去

回复

使用道具 举报

发表于 2009-6-11 22:28:30 | 显示全部楼层
引用第11楼eff于2009-06-11 21:57发表的  :
于是,偶想起了N年前初学编程老师给的题目:编写一个解析字符串的计算器。

用字符串做合成条件么。。。直观是直观。。

其实应该弄个自定义函数,从字符串读取合成信息

刚开始血戮说要做全体技能模板
我就想用字符串来呢
通过几个变量组作为输入的数据
然后以一个用某个规则编写的字符串作为参数
根据不同的字符串的内容来确定效果
回复

使用道具 举报

发表于 2009-6-12 11:54:48 | 显示全部楼层
按说从字符串读取的话其实和脚本的作用类似了。
回复

使用道具 举报

发表于 2009-6-12 17:45:17 | 显示全部楼层
这个无聊东东做出来了~
QQ截图未命名.jpg
QQ截图未命名2.jpg

calc.w3x

46 KB, 下载次数: 8

回复

使用道具 举报

发表于 2009-6-12 18:03:27 | 显示全部楼层
太强大了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-4-25 21:23 , Processed in 0.469102 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表