|
|
为了让cmd对命令行的解释更加人性化,能处理接近于自然语言的中缀表达式,
expr.exe因此暂时将要诞生了(这个东西最终会越来越强大,强大到要替代cmd)
那么我们要解决那些问题?
我这里有个批处理版的:gcd子过程,以此为表达式要处理的问题作为例子
这个子过程用来求两个整数(包括负整数)最大公约数,用欧几里德算法递归实现, 可读性很差!
:gcd <integer> <integer> <ret> //code by plp626
setlocal & if %2 neq 0 (set/a p=%1%%%2) & if %1==0 (endlocal&set %3=%2&exit/b)
endlocal&(if %2==0 (set/a "%3=%1*(%1>>31)*2+%1") else call:gcd %2 %p% %3)&exit/b
为了便于大家理解,我把这个算法讲一下
关于两个数的最大公约数根据欧几里德辗转相除法,我们得到两个整数最大公约数的定义(递归定义)
设A,B是两个正整数,用(A,B)来表示它们的最大公约数
recursion : (A,B)=(B , A%B); //这里不必强调A,B那个绝对值大,即使B>A经过一次recursion后就变了
base case: (C,0)=|C| ; //C为整数
我们看c语言是怎么写的(可读性强):
int gcd(int a, int b){if (!b) return abs(a); else return (b,a%b);}
如果用expr我们设c为-24与256的最大公约数即c=gcd(-24,256)
命令行下键入expr c=gcd(-24, 256)搞定,这要们已经有gcd这个函数,如果没有这个函数
我们键入(由于cmd没有便利类型我们不必指定型参数据类型(但这要expr底层判断以便实现))
expr -def gcd(a, b){ if (!b) ret abs(a)) else ret gcd(b,a%b) } ;c=gcd(-24,256) ; //-def 开关表示我们要定义函数了
同gcc把那串C代码搞成汇编然后生成目标代码一样,我们要expr 去处理我们那串p语言,现在我们看看上面的
代码怎么一步一步分解,红色的字符就是我们的关键字,是expr要特别处理的字符
我们知道引号与空格的在命令行下的优先级仅次于%(cmd在处理时先把%预处理,然后再进行命令行操作)
引号与空格的优先级相同,那个在前面那个优先级高,当第一个双引号出现时,
为了匹配第二个引号,它不管后面的空格,当找到了第二个引号时,再找紧接着后面的参数
分隔符(“空格,;=”其中之一),找到后就是一个完整的参数(还有许多东西待研究,
我研究的方法就是printf("%s",argv[1]);printf("%c",argv[1][?]);来验证我的想法);
如果我们用纯p处理来写注意到p对参数空格的处理,想到加空格法,为了显示出空格字符我把上面的改写以便突出空格
expr -def gcd ( a , b ) { if ( ! b ) ret abs ( a ) else ret gcd ( b , a % b ) } ; c = gcd ( - 24 , 256 ) ;
"标准写法" expr 共接受到42个参数(expr 就是%0,cmd有shift可以处理任意多个参数),
所以需要有个预处理过程,来加上空格,我们用set %var:str1= str2 %来做,这里的
特殊字符有{} () % ,;= 我们用(这里我们还得要对,;=做特殊处理,因为cmd把它当作了参数分割符)
set s=%* & for %a in ({; }; ^(; ^); )do set s=!s:%a= %a !
可以做到,所以总的思路是:
加空格 》循环开始标志 》对%1的判断&shift 为空时endlocal &set .... 》分析优先级 》压栈 》出栈运算赋值》判断,执行命令》goto:循环
我们可以设定两个变量模拟栈空间,入栈,出栈,用set var=%s:~0,?%,
最后把我们要执行的操作命令存放在commond变量里,再设定一个临时变量储存运算的中间结果
对值得传递我们用endlocal & set %?=%返回值%
这中间有许多工作要做,对二元运算符,一元运算符优先级的处理,由于p处理没有数据类型+有可能也是变量,
如二元运算符-与命令行开关-混淆,许多,我想为了解决这些问题我们对变量的命名得有一地定的限制了
最后我们要面对的还有cmd最大递归层数1024,这严重影响了我们的信心
如果我们用C来写就要干脆些(现在又一次体会到C系统语言的称呼了),可是发现cmd对?的处理后
expr接收到的?后"失真"了(但这不是大问题),不管怎样方法还是得先把括号,关键字用
空格分开,以便分开参数,大家参考编译原理的词法分析器源代码,最后们还是
回避不开值的传递问题,我们遇到的障碍归根接地就是对system函数的问题,
那我们不用他了,自己写个试试
//题外话用free按钮也挺好的,便于大家阅读
[ 本帖最后由 plp626 于 2009-5-30 03:08 编辑 ] |
|