[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

【cmd的未来】expr编写的可行性研究

为了让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 编辑 ]

code标签没问题啊
  1. gcd  <integer> <integer> <ret>  //code by plp626
  2. setlocal & if %2 neq 0 (set/a p=%1%%%2) & if %1==0 (endlocal&set %3=%2&exit/b)
  3. endlocal&(if %2==0 (set/a "%3=%1*(%1>>31)*2+%1") else call:gcd %2 %p% %3)&exit/b
复制代码
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

  1. 可能是LZ耍的花样
复制代码

[ 本帖最后由 zjw767676 于 2009-5-30 09:55 编辑 ]
有一种爱叫放弃

TOP

想自写一个system啊,至少得先解剖掉cmd才行吧。。。
expr的难度非常高啊,还能够自定义函数了呢。。。
LZ不等于在做一种以批处理为内核的新语言形式?
第三方命令行工具编程
Http://Hi.Baidu.Com/Console_App

TOP

果真如此的话,绝对支持。
但想想,微软应该可以做到的,只是他们不这样做会不会有一定的原因呢?

TOP

微软似乎有点放弃cmd和vb的迹象,去开发语音和触控的了

TOP

刚刚去看了看上学那会写的词法分析器,500+行C代码而已,语法分析器才400来行。当时确实花了不少精力来写,可惜最后只写完词法分析器和语法分析器就没有再继续下去了。一方面可能是学校教育体制问题,另一面就是自己心不够静,如果能坚持写完编译器就好了......转眼间几年时间过去了,不禁感概岁月蹉跎啊~
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

cmd的源代码应该能搞到,这个对ms并不是特别重要的东西,在google里搜索有不少相关网页,只是我的C语言还不到家。。。。。

我想到perl就可处理循环操作{if ... else ....} 而且也有开源代码,如果大家对linux在行(批处理之家有真的喜欢shell的基本对cmd就没了兴趣)里面那么多的开源代码,只要能想到的,理论上就能做到,如果愿意做,就成了

TOP

我在百度的结果已经基本上全部检索过了,没有cmd的源码。。。

google的结果是全球网页的吧,可能要好久的吧。。。
第三方命令行工具编程
Http://Hi.Baidu.Com/Console_App

TOP

返回列表