- 浏览: 49820 次
- 性别:
- 来自: 北京
最新评论
-
yunlong167167:
1234567890
XlightWeb 的使用 -
403259982:
hanwesley 写道兄弟你的get,post方法上为什么返 ...
使用Netty 构造一个异步的httpclient -
hanwesley:
兄弟你的get,post方法上为什么返回ChannelPipl ...
使用Netty 构造一个异步的httpclient -
jd2bs:
翻译的不错 跟原文对照看 有收获 呵呵
XlightWeb 的使用 -
lucane:
我也觉得这样分开,js重绘页面比较好,而且如果做控件的话,看起 ...
为什么不用js去渲染页面?
动态语言大行其道 ,不过还有不少公司在用着java 。 很大部分人也会java 。
所以用java 来开发自己的一个动态语言 不错 。反正总是要东西打发内心的无聊, 治疗枯燥的工作对人心理的创伤。
搞这么大个题目 ,招来不少人 。高手也会来吧? 本人编译原理原来上学就没学好 ,这也算是初学乍练 ,您看得高兴捧个人场 ,看得不高兴 多多指教 ,以免我误导了群众。
首先 我必须承认我这话说大了。 我目前只是写到了 词法分析器 和 一个表达式计算。距离动态语言 还差的远。 我也很怀疑我有时间真的写完这些 。今天有空就写点 。 本文的宗旨 就是简单。主要是复杂的东东 我也说不出来 。
编译原理 上过这课的都知道 很无聊。 工作两年基本忘掉 残留下来的概念看到了热泪盈眶的 想不起来。 咱就再回忆一遍吧。
第一个 DFA 确定状态机。
先不说这是啥。 看一个例子, 为了说明状态机的作用和能力 得绕点路先撇开编译原理 抛开概念看看怎么一步步发现这个DFA。 如很解析xml html?
这是我在做一个手机浏览器的时候遇到的问题,虽然有很多库,但是手机上没有或者有不适合,于是自己搞一个 。这里就不争论 “轮子” 的问题了。
<p> xxxxx </p>
这是典型的一段xml 。 注意看, 主要分两部分 ‘<’ 和 ‘>’ 括住的部分,和之外的东西 也就是 ‘>’ 和 ‘<’ 括住的部分。 其实就是把tag 和 内容 区分开。分出如下:
p xxxxx /p 3块
于是写代码如下
state = 初始状态 for char in htmlstr{ if 初始状态{ if(char == '<'){ state = tag状态 } }else if tag状态{ if(char == '>'){ state = 内容状态 }else{ tagstr += char; } }else if 内容状态{ if(char == '<'){ state = tag状态 }else{ contentstr += char; } }
呵呵 第一步 把tag 和 内容分开了 。 有同学问 < > 不会乱出现么? 规则上规定xml 中< >必须是tag 的 遇到和要转义 就是用 < 这种东东代表一下。 但是也会遇到不转义的写错的 这个只要加上写判断 容错即可 这里不做详述。
tag 里边还有东东啊
<img src="url" alt="xxxx">
同理可以分状态 处理之。 找到tag名字img之前叫做状态1 ,然后遇到空格 变为状态2, 然后遇到=号变为状态3 ..... 当然这里的逻辑比上边复杂一些 ,其实也就是又臭又长些 。
上边说的就是一个 原始的用 if else 构成的状态机。 状态机 就是根据输入 改变到不同的状态 然后做不同的处理 。简单的通俗的说 状态机 == 装逼的switch
这里
http://code.google.com/p/tagparser/
有源码 python 和 java 的 。写的都比较乱 凑合着看吧 ,不大 也就是200行左右解析html xml 之流。
python 版本的还有一个抓取tianya 论坛的一个例子 不知道现在还能用吗 很长时间了
今天就到这吧 。
明天继续....
接昨天
if else 或者 switch 构成的 状态机 非常简陋。 状态越来越多的时候变得乱七八糟 。 所以要分解包装一下。
状态机行为就是 :
----输入---->switch----改变状态--->
在游戏编程 Ai设计中经常用到 ,不过我们这里只主要是谈编译 ,所以输入就变成了 一个字符 输出为一个状态。 一直说“状态” 这个东西 那就把它搞成一个类吧
- class State{
- StateType type = StateType.BEGIN;
- public State nextState(char i){
- return null;
- }
nextState 就是主要部分了 输入为一个字符串 输出也就是返回值 为一个State。 看看如何用这个State来识别一个 整型数字 例如 1000 100 99 .....
建立一个IntState 然后重载 State:
- class IntState extends State{
- public State nextState(char c){
- if(c >= '0' && c <= '9'){
- return this;
- }else{
- return null;
- }
- }
- }
这个比较简单 可以生成一个 IntSate intState = new IntState() 看看它如何工作
- String prostr = "192321 2312 3243";
- String buff = "";
- for(int i=0 ; i<prostr.length() ; i++){
- char c = prostr.charAt(i);
- State st = intStat.nextSate(c);
- buff += c;
- if(st == null){
- print buff;
- }
其结果就是把字符串中的整型数字给 挑出来了。 这看起来很容易不是么? 等等如果它没有split 强大费这种力气干么? 实际上程序文件包含的字符串比这复杂的多,有int float string 变量 关键字 各种符号.... ....................木有关系 统统没有关系 每一个建立一个state即可
如 floatState stringState 看看如何编写 ,这里只写出nextState 函数 它们都是继承自State类
- floatSate:
- public State nextState(char i){
- if(isDigit(i)){
- return floatSt;
- }else if(i == '.' || isAlpha(i)){ // 浮点数状态下 输入“.” 和字符 返回deny状态 说明词法错误,这里也可以做成抛异常
- return deny;
- }else{
- return null; //如遇到空格 或者其他的字符 则说明词法完成 顺利通过
- }
- spaceState 识别空白的字符
- public State nextState(char i){
- if(isSpace(i)){
- return spaceSt;
- }else{
- return null;
- }
常用的函数
- public static boolean isAlpha(char i){
- return (i>='a' && i<='z') || (i>='A' && i<='Z');
- }
- public static boolean isDigit(char i){
- return (i>='0' && i<='9') ;
- }
- public static boolean isSpace(char i){
- return (i==' ' || i=='\r' || i=='\n' || i=='\t') ;
- }
识别 单个的符号 更简单了 直接用State 生成一个不用继承,然后把它放入到一个字典里 在扫描程序字符串的时候可以快速查到。如下
- map.put("(", new State(StateType.LPARENT));
这里还需要一个开始的状态 ,编译开始时 从一个字符开始扫描 。第一个字符有可能是 整型数字 也可能是字母 也可能 变量。 可以如下编写
- public State nextState(char i){
- if(isAlpha(i) || i == '_'){ //如第一个字符遇见字母 ,那么接下来就返回 identState ,它用来识别变量和关键字这类的。
- return identSt;
- }else if(isDigit(i)){ //如是数字 看开头是0打头的 有可能是0x 也可是8位的 ,如果不是0 那就是整型的。当然整型半截可能遇见“.”
- if(i == '0'){ //在整型状态下遇见"." 就返回floatState 当作float识别。 这里用了子状态 。其实可以多生成些状态不要子
- intSt.subtype = 8160; //状态
- }else{
- intSt.subtype = 10;
- }
- return intSt;
- }else if(i == '\"'){ // 引号出现说明后边是 字符串
- return strSt;
- }else if(isSpace(i)){
- return spaceSt;
- }else { // 如果是其他符号 看看是不是单个的 {} []: ,. 之类的
- return smap.get(String.valueOf(i));
- }
- }
一旦一个状态识别完 就会返回null 说明一个词义被确认 而且这个词是整型 还是浮点型 还是字符串 ... 都是最后的那个状态类型。 这时候可以根据类型 把字符串转化为java 的类型了。
其中遇到的一些 小问题 。如 第一个字符是 0 ,就有几种可能 十六进制0x7873 浮点数0.423 八进制0632,如何确定 用intSate 还是用floatState ?
这里我程序里是假定是整型先 如遇到“.” 状态机返回floatSate这样就跳到了浮点型识别, 在区分 八进制还是十六进制的时候 用了子状态 。其实这么做不好。最好引入中间状态 如叫做 zeroState .在这个状态里就可以区分到底是用那个状态机去识别。 因为再往后一个字符就可以确定是什么类型 如果是‘x’就是十六位整型。
这种情况很常见,就是一个字符出现不能确定状态该怎么走 ,方法就是引入中间状态。 最后实现了 每个状态输入一个字符 就可以确定下一个状态,这也是为什么叫做有限确定状态机 DFA 。一个输入可能对应多个状态的叫做非确定状态机 NFA 。很恶心的书上把简单的概念都写得抽象的吓人,真不知道为啥?为了严谨? 写书给人看的 搞的跟给机器写书一样 。 隐隐约约记得书上像些咒语一样 写着如何把NFA 转为DFA ..... 压根我看不明白。
状态机的应用还很多 。其实正则就是状态机实现的 。有的是用NFA 有的是用DFA规则。 表现的区别 如匹配 (aaa|bbb|cdd) 。
- 字符串 : abcd
- DFA 过程: 先看和 aaa 匹配么再和bbb匹配 在和ccc匹配
- NFA过程: 先看abcd的第一个字符 和 aaa bbb ccc 那个匹配 。然后在看第二个字符b ...
- 有点类似一个深度优先 一个是广度优先。
今天到这里 待续
大家过年好,春节快乐。
给出词法分析的代码
- tagparser.rar (1.9 KB)
- 下载次数: 52
- expression.rar (4 KB)
- 下载次数: 13
评论
下面是我写的解析JSON语法的代码:http://johnson-lee.iteye.com/blog/586686
望各位拍砖......
大牛出现 呵呵 。 前一阵子就参看过你的程序了
你是说你用java实现了一个词法分析器吧,词法分析貌似比较简单啊
当运算量大的时候,用正则会有效率问题吧
<p> </p>
<p>到目前为止 已经有了一个词法分析的东东。 还不完善 不过已经可以把大部分程序里出现的有意义的字符识别出来了。例如:</p>
<p> </p>
<p> </p>
<pre name="code" class="java"> test = "int a = 5.234; float b = 3;<\n"
+ "! <= += >= !=8377243.324324 () 3244\r\n"
+ " 432 rewrew- \"fdsfdfds\"\n"
+ " 09\n"
+ "//fdafdfd 843728 fdfdfd \n"
+ "fdfdsfd ffff";</pre>
<p> </p>
<p> 被分解后输出为:</p>
<p> </p>
<pre name="code" class="java">int INTEGER_TYPE
a IDENT
= ASSIGN
5.234 FLOAT
; SEMI
float FLOAT_TYPE
b IDENT
= ASSIGN
3 INTEGER
; SEMI
< LT
! NOT
<= LE
+= PLUS_A
>= GE
!= NE
8377243.324324 FLOAT
( LPARENT
) RPARENT
3244 INTEGER
432 INTEGER
rewrew IDENT
- MINUS
fdsfdfds STR
------------------err----------------------- //有了一点词法分析报错的 功能。 显示什么位置出现了错误
unexpect char "9"
at line : 4 col :3
------------------errend--------------------
0 INTEGER
//fdafdfd 843728 fdfdfd SKIP
fdfdsfd IDENT
ffff IDENT
</pre>
<p> </p>
<p> </p>
<p> </p>
<p>尽管上边的字符串不是合法的语句 ,但是词法分析不关系语句是否合法 ,只是把相应的有意义的字符串分解出来即可。 </p>
<p> </p>
<p> </p>
<p> </p>
<p>语法分析比较难点 ,我也刚看不久。 表述不清楚的地方 大家查查资料吧。</p>
<p> </p>
<p>首先 我们看看如何解析 数学表达式。 这是最简单的 也是最复杂的一种语法了。 简单的 如 2+4 4-2 .... 等等 </p>
<p> </p>
<p>好现在可以写一个简单的程序处理这些了。</p>
<p> </p>
<p> </p>
<pre name="code" class="java"> express(){
int left ,right , result;
Token tk = getNextToken();
if(tk.type == INT){
left = tk.value;
}
tk = getNextToken();
if(tk.type == ADD){
tk = getNextToken();
right = tk.value;
result = left + right;
}else if(tk.type == MINUS){
tk = getNextToken();
right = tk.value;
result = left - right;
}
}</pre>
<p> </p>
<p>很简单 出来了 计算 加减的表达式。 可是这个表达式比较弱 只能计算 两个数的加法减法。 改进一下。</p>
<p> </p>
<p> </p>
<pre name="code" class="java"> express(){
int left ,right , result;
Token tk = getNextToken();
if(tk.type == INT){
left = tk.value;
}
while(tk = getNextToken() != null){ //这里加入个循环 ,即让后边在出现 + - 的运算都进行下去
if(tk.type == ADD){
tk = getNextToken();
right = tk.value;
result = left + right;
}else if(tk.type == MINUS){
tk = getNextToken();
right = tk.value;
result = left - right;
}
}
}</pre>
<p> </p>
<p>加入了循环处理 这就让 他可以处理 4+3-32+23-0 .... 的运算。</p>
<p> </p>
<p>下一步加入 × / 运算。 这个比较麻烦的地方就是 。如何才能是乘除先运算 加减后运算? </p>
<p> </p>
<p>看这个 例子: a + c*d</p>
<p> </p>
<p>可以把 c*d 看作是一个整体 ,原来的表达式 ====》 a + b ; b ====> c*d </p>
<p> </p>
<p>上边那个express() 函数 只能计算加减 。 可以计算 a +b 这部分。 但现在b 不是一个具体的数字了 ,而是一个 需要求解的未知值。</p>
<p> </p>
<p>我们可以把b当作一个函数 ,这样表达式就变为了 a + b() .在计算这个表达式之前 就得先计算b这个函数值 。 这样就体现了 × / 优先于 +- 计算了。 </p>
<p> </p>
<p>糊涂了? 还是看代码吧 ,文字还是不如代码容易理解。</p>
<p> </p>
<p> </p>
<pre name="code" class="java">express(){
int left ,right , result;
Token tk = getNextToken();
if(tk.type == INT){
left = tk.value;
}
while(tk = getNextToken() != null){ //这里加入个循环 ,即让后边在出现 + - 的运算都进行下去
if(tk.type == ADD){
right = b(); //注意这里的变化
result = left + right;
}else if(tk.type == MINUS){
right = b(); //注意这里的变化
result = left - right;
}
}
}</pre>
<p> </p>
<p>原来的right的值 直接取一个token就得到了 。这里变为了 调用一个叫做b函数。 现在我们假定了 后边跟着一个 c *d 运算 。那么b 函数这么写</p>
<p> </p>
<p> </p>
<p> <span style="white-space: pre;"> </span></p>
<pre name="code" class="java">int b(){
int left ,right , result;
Token tk = getNextToken();
if(tk.type == INT){
left = tk.value;
}
while(tk = getNextToken() != null){
if(tk.type == MULTIPLY){
right = getNextToken().value;
result = left * right;
}else if(tk.type == DIVIDE){
right = getNextToken().value;
result = left /right;
}
}</pre>
<p>这个上边算加减的函数差不多 。到这里虽然可以计算 想 a + c *d 这类的表达式 可是现在也只能计算这样的表达式 。换一种写法就不行了。写成 c*d +a 就歇菜了。</p>
<p> </p>
<p>想来想去 发现这么着是不行的。 继续顺着上边的思路走。 a + c*d ==> a + b ; b ==> c*d 你会发现 。a 也可能是一个表达式啊。 a 可能是 a ==> e + f 。那</p>
<p> </p>
<p>e 呢? f呢 都可能是表达式, 感觉很混乱 ,还好 有人帮你整理了这中混乱, 于是就有了BNF 这种东西 . 先看看 BNF 是如何处理这中问题的。 </p>
<p> </p>
<p> </p>
<p>BNF 的思路和上边的思考过程 很像 不过更科学 。看看bnf 怎么描述 表达式的。</p>
<p> </p>
<p>express === > A + express | A - express | A</p>
<p> </p>
<p>| 代表 或者的关系 。 A 可以理解为一个返回确切数字的函数 。 汉语意思可以说 表达式 是一个数字 + 或者 - 一个表达式 或者 就一个确切数字组成的。</p>
<p> </p>
<p>这是个递归的说法 ,似乎看不到底 但是有一点很重要 它已经表达了有加 减。</p>
<p> </p>
<p>现在开始定义 A 了 ,这里把A改名 叫做 term 因为这是通常都这么叫</p>
<p> </p>
<p>express === > term + express | term - express | term</p>
<p> </p>
<p>把这个翻译成程序就是 </p>
<p> </p>
<p> </p>
<pre name="code" class="java"> int express () {
int left = term();
Token tk = getNextToken();
//express ==> term + express | term - express
if(tk.type == PLUS || tk.type == MINUS){
int right = express();
return left + - right;
}else { putBack (tk )} //上边测试是不是×/ 不是的话吧这个token放回去 。这里很重要。 也很难说清楚流程 开代码 或者跟代码更容易明白
// express == > term(); 因为上边已经求出 left = term(); 所以直接返回left
return left
}</pre>
<p> </p>
<p> 现在定义 term ==> factor * term | factor / term | factor</p>
<p> </p>
<p>简直跟express 一模一样的定义 ,这次定义了 乘除的运算。 可以看到 问题变得月来越小了</p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<pre name="code" class="java"> int term () {
int left = factor();
Token tk = getNextToken();
//term ==> factor * term | factor / term
if(tk.type == MULTIPLY || tk.type == DIVIDE){
int right = factor();
return left * / right;
}else { putBack (tk )} //上边测试是不是×/ 不是的话吧这个token放回去 。这里很重要。 也很难说清楚流程 开代码 或者跟代码更容易明白
// express == > term(); 因为上边已经求出 left = term(); 所以直接返回left
return left
}</pre>
<p> </p>
<p> </p>
<p>这次出现了 factor 。 factor 如何定义? 再往下分解 就是 数字了 factor ==> num | - num</p>
<p> </p>
<p>
</p>
<pre name="code" class="java">int factor(){
Token tk = getNextToken();
if(tk.type == MINUS){
return - tk.value
}
return tk.value;
}</pre>
<p> </p>
<p>BNF主要是用了递归的方式 分解问题 。 </p>
<p> </p>
<p> </p>
<p>写了这么多 发现 还是看程序更容易理解 还是上程序吧 。。。 下边的程序计算一个 表达式 ,包括 括号 和 正负号 求模 功能。</p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> if else 或者 switch 构成的 状态机 非常简陋。 状态越来越多的时候变得乱七八糟 。 所以要分解包装一下。</p>
<p> </p>
<p> 状态机行为就是 :</p>
<p> </p>
<p> ----输入---->switch----改变状态---></p>
<p> </p>
<p> 在游戏编程 Ai设计中经常用到 ,不过我们这里只主要是谈编译 ,所以输入就变成了 一个字符 输出为一个状态。 一直说“状态” 这个东西 那就把它搞成一个类吧</p>
<p> </p>
<p> </p>
<pre name="code" class="java"> class State{
StateType type = StateType.BEGIN;
public State nextState(char i){
return null;
}
}</pre>
<p> </p>
<p>nextState 就是主要部分了 输入为一个字符串 输出也就是返回值 为一个State。 看看如何用这个State来识别一个 整型数字 例如 1000 100 99 .....</p>
<p> </p>
<p>建立一个IntState 然后重载 State:</p>
<p> </p>
<p> </p>
<p> </p>
<pre name="code" class="java"> class IntState extends State{
public State nextState(char c){
if(c >= '0' && c <= '9'){
return this;
}else{
return null;
}
}
}</pre>
<p> </p>
<p> </p>
<p>这个比较简单 可以生成一个 IntSate intState = new IntState() 看看它如何工作</p>
<p> </p>
<p> </p>
<pre name="code" class="java"> String prostr = "192321 2312 3243";
String buff = "";
for(int i=0 ; i<prostr.length() ; i++){
char c = prostr.charAt(i);
State st = intStat.nextSate(c);
buff += c;
if(st == null){
print buff;
}
}</pre>
<p> </p>
<p> </p>
<p>其结果就是把字符串中的整型数字给 挑出来了。 这看起来很容易不是么? 等等如果它没有split 强大费这种力气干么? 实际上程序文件包含的字符串比这复杂的多,有int float string 变量 关键字 各种符号.... ....................木有关系 统统没有关系 每一个建立一个state即可</p>
<p> </p>
<p>如 floatState stringState 看看如何编写 ,这里只写出nextState 函数 它们都是继承自State类</p>
<p> </p>
<p> </p>
<pre name="code" class="java">
floatSate:
public State nextState(char i){
if(isDigit(i)){
return floatSt;
}else if(i == '.' || isAlpha(i)){ // 浮点数状态下 输入“.” 和字符 返回deny状态 说明词法错误,这里也可以做成抛异常
return deny;
}else{
return null; //如遇到空格 或者其他的字符 则说明词法完成 顺利通过
}
}
spaceState 识别空白的字符
public State nextState(char i){
if(isSpace(i)){
return spaceSt;
}else{
return null;
}
}</pre>
<p> </p>
<p> 常用的函数 </p>
<p> </p>
<pre name="code" class="java"> public static boolean isAlpha(char i){
return (i>='a' && i<='z') || (i>='A' && i<='Z');
}
public static boolean isDigit(char i){
return (i>='0' && i<='9') ;
}
public static boolean isSpace(char i){
return (i==' ' || i=='\r' || i=='\n' || i=='\t') ;
}</pre>
<p> </p>
<p> 识别 单个的符号 更简单了 直接用State 生成一个不用继承,然后把它放入到一个字典里 在扫描程序字符串的时候可以快速查到。如下</p>
<p> </p>
<p> </p>
<pre name="code" class="java">map.put("(", new State(StateType.LPARENT));</pre>
<p> </p>
<p> </p>
<p>这里还需要一个开始的状态 ,编译开始时 从一个字符开始扫描 。第一个字符有可能是 整型数字 也可能是字母 也可能 变量。 可以如下编写</p>
<p> </p>
<pre name="code" class="java">
public State nextState(char i){
if(isAlpha(i) || i == '_'){ //如第一个字符遇见字母 ,那么接下来就返回 identState ,它用来识别变量和关键字这类的。
return identSt;
}else if(isDigit(i)){ //如是数字 看开头是0打头的 有可能是0x 也可是8位的 ,如果不是0 那就是整型的。当然整型半截可能遇见“.”
if(i == '0'){ //在整型状态下遇见"." 就返回floatState 当作float识别。 这里用了子状态 。其实可以多生成些状态不要子
intSt.subtype = 8160; //状态
}else{
intSt.subtype = 10;
}
return intSt;
}else if(i == '\"'){ // 引号出现说明后边是 字符串
return strSt;
}else if(isSpace(i)){
return spaceSt;
}else { // 如果是其他符号 看看是不是单个的 {} []: ,. 之类的
return smap.get(String.valueOf(i));
}
}</pre>
<p> </p>
<p> </p>
<p> </p>
<p> 一旦一个状态识别完 就会返回null 说明一个词义被确认 而且这个词是整型 还是浮点型 还是字符串 ... 都是最后的那个状态类型。 这时候可以根据类型 把字符串转化为java 的类型了。 </p>
<p> </p>
<p> 其中遇到的一些 小问题 。如 第一个字符是 0 ,就有几种可能 十六进制0x7873 浮点数0.423 八进制0632,如何确定 用intSate 还是用floatState ?</p>
<p>这里我程序里是假定是整型先 如遇到“.” 状态机返回floatSate这样就跳到了浮点型识别, 在区分 八进制还是十六进制的时候 用了子状态 。其实这么做不好。最好引入中间状态 如叫做 zeroState .在这个状态里就可以区分到底是用那个状态机去识别。 因为再往后一个字符就可以确定是什么类型 如果是‘x’就是十六位整型。 </p>
<p> </p>
<p><span style="font-size: small;"> 这种情况很常见,就是一个字符出现不能确定状态该怎么走 ,方法就是引入中间状态。 </span><strong><span style="color: #ff0000;"><span style="font-size: small;">最后实现了 每个状态输入一个字符 就可以确定下一个状态,这也是为什么叫做有限确定状态机 DFA 。一个输入可能对应多个状态的叫做非确定状态机 NFA 。</span><span style="font-weight: normal;"><span style="color: #000000;"><span style="font-size: small;">很恶心的书上把简单的概念都写得抽象的吓人,真不知道为啥?为了严谨? 写书给人看的 搞的跟给机器写书一样 。 隐隐约约记得书上像些咒语一样 写着如何把NFA 转为DFA ..... 压根我看不明白。</span></span></span></span></strong></p>
<p> </p>
<p> 状态机的应用还很多 。其实正则就是状态机实现的 。有的是用NFA 有的是用DFA规则。 表现的区别 如匹配 (aaa|bbb|cdd) 。</p>
<p> </p>
<p>
</p>
<pre name="code" class="java">字符串 : abcd
DFA 过程: 先看和 aaa 匹配么再和bbb匹配 在和ccc匹配
NFA过程: 先看abcd的第一个字符 和 aaa bbb ccc 那个匹配 。然后在看第二个字符b ...
有点类似一个深度优先 一个是广度优先。
</pre>
<p> </p>
<p> 今天到这里 待续 </p>
<p> 大家过年好,春节快乐。</p>
<p> </p>
<p> 给出词法分析的代码</p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
PS: JAVAEYE越来越无趣了,这样的贴也放首页。。。
不过DFA在有递归的文法上貌似没什么好的办法处理,LZ能帮忙解答下吗
DFA 用来做词法分析还不错 。文法的话 还是递归的处理比较好 ,这方面我也正在学习 以后会写 。
写这个的目的是为了 手动构造这些东东 。学习的。 如果使用antlr 之类的就没必要看这个了。 喜欢使用工具 就去使用吧。可以不care这些 呵呵
不过DFA在有递归的文法上貌似没什么好的办法处理,LZ能帮忙解答下吗
这也算?!
相关推荐
用c#写一个简单的记事本,初学者可以当作项目实训一下,或者作为自己的学校的项目实训,总体上还是比较简单。适合熟悉自己所学的知识。 用c#写一个简单的记事本,初学者可以当作项目实训一下,或者作为自己的学校的...
Python写的学生信息管理系统,适合初学python练手用
本书从初学者的立场出发,为广大初学者提供了一个FPGS入门学习平台,以深入浅出的方式介绍FPGA的基本原理、Verilog语言和应用设计。但作为一个FPGA的初学者必须先了解以下几个问题:何为FPGA?为什么要学习FPGA?...
任意输入两个数,能完成加,减,乘,除运算。其中输入1实行加法功能,输入2实行减法功能,输入3实行乘法功能,输入4实行除法功能,输入5退出。...我也是一个初学者。网上有的都是一些难看懂的。对大家绝对有用。
特别适合初学者适应html、js语言
本人为c#初学者,无其他语言基础,这个计算器是自己独立写的第一个小东西。 内容只有一个窗口文件,注释写的也算详细了,希望与其他初学者一起学习进步 ps:变量命,控件名,都是中文 嘿嘿 看不习惯请替换 环境为vs...
初学c++一个月后写的RPG文字游戏,自己感觉还算可以
这表明该资源是一个针对编程初学者的教程,使用Eclipse集成开发环境(IDE)来创建一个简单的Android应用程序,即一个记事本程序。对于初学者而言,这个实例能够帮助他们入门Android应用开发,了解Eclipse在Android...
C#人事管理系统是一个为初学者设计的简单应用,旨在帮助学习者理解和掌握C#编程语言以及.NET框架的基本应用。这个系统包含了完整的源代码,设计文档,以及详细的使用说明,是进行课程设计或个人实践的理想选择。 一...
通过分析这款源代码,初学者可以了解到Java编程语言在游戏开发中的应用,以及如何构建一个简单但功能完整的交互式程序。 首先,我们要了解Java语言的基础特性。Java是一种面向对象的编程语言,以其跨平台性和强大的...
对于初学者来说,Java提供了一个良好的学习平台,因为它的语法清晰,易于理解。"java小项目 适合初学者"这样的资源集合是入门Java编程的理想起点。 这个标题表明,你将接触到一系列小型的Java项目,这些项目通常是...
汇编语言源程序代码可以做简易数码管动态显示,适合初学者学习显示电路程序
Selenium是一个开源的、跨平台的自动化测试框架,支持多种编程语言如Java、Python、C#等。它允许开发者模拟用户在浏览器中的行为,进行网页应用的功能性测试。Selenium分为多个组件,包括Selenium WebDriver、...
这个“VB源代码大全”集合显然为初学者提供了一个良好的学习平台,通过实际的代码示例,如计算器和摇奖机,帮助他们快速理解和掌握VB编程基础。 首先,让我们深入了解一下VB的基础知识。VB是一种事件驱动的编程语言...
这份初学指南源码涵盖了这三个重要技术的基础知识,为初学者提供了一个良好的学习起点。 Servlet是Java平台上的一个标准,用于扩展服务器的功能。它是一个Java类,用于接收和响应来自Web客户端的请求。Servlet生命...
Python编程初学者指南.pdf
很简单的一个用汇编语言编写的程序 很适合刚学汇编语言的初学者 虽然程序简单却用到很多汇编的知识
小到一个上机实 验,大至一项工程案例,皆为刊物的灵魂。 黎明前,一群群GIS初学者在探路。 尽管网络试图把目光织向远方,可是缺乏社会的历练,象牙塔里的认识毕竟肤浅。 我们在黑暗中奋勇挣扎! 希望它能拭...
这种程序在许多网站中都常见,为用户提供了一个验证身份的入口,允许他们访问受保护的页面和服务。在这个项目中,开发者使用了Visual Studio 2010这一强大的开发环境,它提供了对.NET Framework的良好支持,使得创建...