`
fengshihao
  • 浏览: 49984 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

写一个自己的动态语言吧。 初学乍练的。

阅读更多

动态语言大行其道 ,不过还有不少公司在用着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 的 遇到和要转义 就是用 &lt 这种东东代表一下。 但是也会遇到不转义的写错的 这个只要加上写判断 容错即可 这里不做详述。

 

 

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设计中经常用到 ,不过我们这里只主要是谈编译 ,所以输入就变成了 一个字符  输出为一个状态。 一直说“状态” 这个东西 那就把它搞成一个类吧

 

 

Java代码 
  1.        class State{  
  2.        StateType type = StateType.BEGIN;  
  3.   
  4. public State nextState(char i){  
  5.     return null;  
  6. }  

 

nextState 就是主要部分了 输入为一个字符串 输出也就是返回值 为一个State。 看看如何用这个State来识别一个 整型数字 例如 1000 100 99 .....

 

建立一个IntState 然后重载 State:

 

 

 

Java代码 
  1.   class IntState extends State{  
  2.       public State nextState(char c){  
  3.             if(c >= '0' && c <= '9'){  
  4.                   return this;  
  5.             }else{  
  6.                   return null;  
  7.             }  
  8.       }  
  9. }  
 

 

 

这个比较简单 可以生成一个 IntSate  intState =  new IntState()  看看它如何工作

 

 

Java代码 
  1.  String prostr  = "192321 2312 3243";  
  2.  String buff = "";  
  3. for(int i=0 ; i<prostr.length() ; i++){  
  4.        char c = prostr.charAt(i);  
  5.        State st = intStat.nextSate(c);  
  6.         buff += c;  
  7.        if(st == null){  
  8.             print buff;  
  9.        }  

 

 

其结果就是把字符串中的整型数字给 挑出来了。 这看起来很容易不是么? 等等如果它没有split 强大费这种力气干么? 实际上程序文件包含的字符串比这复杂的多,有int  float string 变量 关键字 各种符号.... ....................木有关系 统统没有关系 每一个建立一个state即可

 

如 floatState stringState  看看如何编写 ,这里只写出nextState 函数 它们都是继承自State类

 

 

Java代码 
  1.  floatSate:  
  2.                   public State nextState(char i){  
  3. if(isDigit(i)){  
  4.     return floatSt;  
  5. }else if(i == '.' || isAlpha(i)){  // 浮点数状态下 输入“.”  和字符 返回deny状态 说明词法错误,这里也可以做成抛异常  
  6.     return deny;  
  7. }else{  
  8.     return null;  //如遇到空格 或者其他的字符 则说明词法完成 顺利通过  
  9. }  
  10.   
  11.  spaceState     识别空白的字符  
  12.   
  13.                   public State nextState(char i){  
  14. if(isSpace(i)){  
  15.     return spaceSt;  
  16. }else{  
  17.     return null;  
  18. }  

 

 常用的函数 

 

Java代码 
  1. public static boolean isAlpha(char i){  
  2.     return (i>='a' &&  i<='z') || (i>='A' && i<='Z');  
  3.     }  
  4.       
  5. public static boolean isDigit(char i){  
  6.     return (i>='0' &&  i<='9') ;  
  7.     }  
  8.       
  9. public static boolean isSpace(char i){  
  10.     return (i==' ' || i=='\r' || i=='\n' || i=='\t') ;  
  11.     }  

 

 识别 单个的符号 更简单了 直接用State 生成一个不用继承,然后把它放入到一个字典里 在扫描程序字符串的时候可以快速查到。如下

 

 

Java代码 
  1. map.put("("new State(StateType.LPARENT));  

 

 

这里还需要一个开始的状态 ,编译开始时 从一个字符开始扫描 。第一个字符有可能是 整型数字 也可能是字母 也可能 变量。 可以如下编写

 

Java代码 
  1.    
  2.   
  3. public State nextState(char i){  
  4.                 if(isAlpha(i) || i == '_'){    //如第一个字符遇见字母 ,那么接下来就返回 identState ,它用来识别变量和关键字这类的。  
  5.                     return identSt;  
  6.                 }else if(isDigit(i)){           //如是数字 看开头是0打头的 有可能是0x 也可是8位的 ,如果不是0 那就是整型的。当然整型半截可能遇见“.”  
  7.                     if(i == '0'){              //在整型状态下遇见"." 就返回floatState 当作float识别。 这里用了子状态 。其实可以多生成些状态不要子  
  8.                         intSt.subtype = 8160;  //状态  
  9.                     }else{  
  10.                         intSt.subtype = 10;  
  11.                     }  
  12.                     return intSt;  
  13.                 }else if(i == '\"'){  // 引号出现说明后边是 字符串  
  14.                     return strSt;  
  15.                 }else if(isSpace(i)){  
  16.                     return spaceSt;  
  17.                 }else {              // 如果是其他符号 看看是不是单个的 {} []: ,. 之类的  
  18.                     return smap.get(String.valueOf(i));  
  19.                 }  
  20.             }  

 

 

 

    一旦一个状态识别完 就会返回null 说明一个词义被确认 而且这个词是整型 还是浮点型 还是字符串 ... 都是最后的那个状态类型。 这时候可以根据类型 把字符串转化为java 的类型了。 

 

   其中遇到的一些 小问题 。如  第一个字符是 0 ,就有几种可能  十六进制0x7873  浮点数0.423  八进制0632,如何确定 用intSate  还是用floatState ?

这里我程序里是假定是整型先 如遇到“.” 状态机返回floatSate这样就跳到了浮点型识别, 在区分 八进制还是十六进制的时候 用了子状态 。其实这么做不好。最好引入中间状态 如叫做 zeroState   .在这个状态里就可以区分到底是用那个状态机去识别。  因为再往后一个字符就可以确定是什么类型 如果是‘x’就是十六位整型。 

 

   这种情况很常见,就是一个字符出现不能确定状态该怎么走 ,方法就是引入中间状态。  最后实现了 每个状态输入一个字符 就可以确定下一个状态,这也是为什么叫做有限确定状态机 DFA 。一个输入可能对应多个状态的叫做非确定状态机 NFA 。很恶心的书上把简单的概念都写得抽象的吓人,真不知道为啥?为了严谨? 写书给人看的 搞的跟给机器写书一样 。 隐隐约约记得书上像些咒语一样 写着如何把NFA 转为DFA .....  压根我看不明白。

 

   状态机的应用还很多 。其实正则就是状态机实现的 。有的是用NFA 有的是用DFA规则。 表现的区别 如匹配 (aaa|bbb|cdd)  。

 

 

Java代码 
  1. 字符串 : abcd  
  2.   
  3. DFA 过程:  先看和 aaa 匹配么再和bbb匹配 在和ccc匹配  
  4.   
  5. NFA过程: 先看abcd的第一个字符 和 aaa bbb ccc 那个匹配 。然后在看第二个字符b ...  
  6.   
  7. 有点类似一个深度优先 一个是广度优先。  

 

  今天到这里 待续

  大家过年好,春节快乐。

 

  给出词法分析的代码

 

 

 


分享到:
评论
19 楼 johnson.lee 2010-02-25  
我早就有自己写个动态语言的相法,语法规则像JSON那样,灵活又简洁,可编译原理学得不好,还只能写Lexer和Parser。有空的话和LZ切磋切磋,怎么样?QQ:307609641 email:g.johnsonlee@gmail.com.

下面是我写的解析JSON语法的代码:http://johnson-lee.iteye.com/blog/586686
望各位拍砖......
18 楼 fengshihao 2010-02-15  
linliangyi2007 写道
楼主讨论的东西还是有一定价值的,有兴趣可以看看我做的这个东东,然后大家可以交流一下,http://linliangyi2007.iteye.com/blog/337069

大牛出现  呵呵 。 前一阵子就参看过你的程序了
17 楼 linliangyi2007 2010-02-13  
楼主讨论的东西还是有一定价值的,有兴趣可以看看我做的这个东东,然后大家可以交流一下,http://linliangyi2007.iteye.com/blog/337069
16 楼 laitaogood 2010-02-12  
babykaokao 写道
我用java写过一个,很简单,用正则表达式把源码分割,然后就是根据语法规则和运算符的优先级进行运算就好了。

你是说你用java实现了一个词法分析器吧,词法分析貌似比较简单啊
15 楼 fireflyk 2010-02-12  
babykaokao 写道
我用java写过一个,很简单,用正则表达式把源码分割,然后就是根据语法规则和运算符的优先级进行运算就好了。


当运算量大的时候,用正则会有效率问题吧
14 楼 fengshihao 2010-02-11  
<p>接昨天</p>
<p> </p>
<p>到目前为止 已经有了一个词法分析的东东。 还不完善 不过已经可以把大部分程序里出现的有意义的字符识别出来了。例如:</p>
<p> </p>
<p> </p>
<pre name="code" class="java"> test = "int a = 5.234; float b = 3;&lt;\n"
+ "! &lt;= += &gt;= !=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; LT
! NOT
&lt;= LE
+= PLUS_A
&gt;= 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 ====&gt; 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 ==&gt; a + b ; b ==&gt; c*d   你会发现  。a 也可能是一个表达式啊。  a 可能是 a ==&gt; e + f 。那</p>
<p> </p>
<p>e 呢? f呢 都可能是表达式, 感觉很混乱 ,还好 有人帮你整理了这中混乱, 于是就有了BNF 这种东西   .  先看看 BNF 是如何处理这中问题的。 </p>
<p> </p>
<p> </p>
<p>BNF 的思路和上边的思考过程 很像 不过更科学 。看看bnf 怎么描述 表达式的。</p>
<p> </p>
<p>express === &gt;   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 === &gt;   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 ==&gt; term + express | term - express
        if(tk.type == PLUS || tk.type == MINUS){
              int right = express();
              return  left + - right;
        }else { putBack (tk )} //上边测试是不是×/ 不是的话吧这个token放回去 。这里很重要。 也很难说清楚流程 开代码 或者跟代码更容易明白
         // express == &gt; term();  因为上边已经求出 left = term(); 所以直接返回left
         return left

}</pre>
 
<p> </p>
<p>    现在定义 term ==&gt; 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 ==&gt; factor * term | factor / term
        if(tk.type == MULTIPLY || tk.type == DIVIDE){
              int right = factor();
              return  left  * / right;
        }else { putBack (tk )} //上边测试是不是×/ 不是的话吧这个token放回去 。这里很重要。 也很难说清楚流程 开代码 或者跟代码更容易明白
         // express == &gt; term();  因为上边已经求出 left = term(); 所以直接返回left
         return left

}</pre>
<p> </p>
<p> </p>
<p>这次出现了 factor  。 factor 如何定义? 再往下分解 就是 数字了 factor ==&gt; 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>
13 楼 nishizhutoua 2010-02-11  
至少也用用正则吧...
12 楼 sdh5724 2010-02-11  
自定义一些脚本语言很多项目是有好处的. 比如SQL parser及审计工作, 监控的规则编写.  我们用到了很多的自定义的语言, 或者parser脚本的工具.
11 楼 kjj 2010-02-11  
现在的人越来越喜欢作秀了,且不说有啥气候
10 楼 fengshihao 2010-02-10  
<p>接昨天</p>
<p> </p>
<p>     if else  或者 switch 构成的 状态机 非常简陋。  状态越来越多的时候变得乱七八糟 。 所以要分解包装一下。</p>
<p> </p>
<p>     状态机行为就是 :</p>
<p> </p>
<p>                  ----输入----&gt;switch----改变状态---&gt;</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 &gt;= '0' &amp;&amp; c &lt;= '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&lt;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&gt;='a' &amp;&amp;  i&lt;='z') || (i&gt;='A' &amp;&amp; i&lt;='Z');
}

public static boolean isDigit(char i){
return (i&gt;='0' &amp;&amp;  i&lt;='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>
9 楼 babykaokao 2010-02-10  
我用java写过一个,很简单,用正则表达式把源码分割,然后就是根据语法规则和运算符的优先级进行运算就好了。
8 楼 sacred02 2010-02-10  
无语啊。。。 看来真是太无聊了!

PS: JAVAEYE越来越无趣了,这样的贴也放首页。。。
7 楼 fengshihao 2010-02-10  
kdlan 写道
我认为DFA实质上是一个有向拓扑图,状态改变其实可以用图遍历来实现
不过DFA在有递归的文法上貌似没什么好的办法处理,LZ能帮忙解答下吗


DFA 用来做词法分析还不错 。文法的话 还是递归的处理比较好 ,这方面我也正在学习 以后会写 。
6 楼 fengshihao 2010-02-10  
kjj 写道
不想打击你,如果只是写了lexer和parser的话,我建议你啊看俺antlr或者javacc 吧,只需要写自己的文法规则就行了,没必要大费周折,但是如果你要挑战一下自己,写lexer和parser的话,只能为你加油



写这个的目的是为了 手动构造这些东东 。学习的。 如果使用antlr 之类的就没必要看这个了。 喜欢使用工具 就去使用吧。可以不care这些 呵呵
5 楼 kjj 2010-02-10  
不想打击你,如果只是写了lexer和parser的话,我建议你啊看俺antlr或者javacc 吧,只需要写自己的文法规则就行了,没必要大费周折,但是如果你要挑战一下自己,写lexer和parser的话,只能为你加油
4 楼 kdlan 2010-02-10  
我认为DFA实质上是一个有向拓扑图,状态改变其实可以用图遍历来实现
不过DFA在有递归的文法上貌似没什么好的办法处理,LZ能帮忙解答下吗
3 楼 yidao620c 2010-02-10  
無語。。。
2 楼 yanghao0 2010-02-10  
...
这也算?!
1 楼 JetMah 2010-02-10  
太少了,不过瘾

相关推荐

    仿20秒的小游戏

    【描述】提到的"初学乍练,请多关照"表明这可能是编程新手的作品,用于锻炼编程技能和理解游戏逻辑。源码的提供意味着我们可以深入研究游戏的实现细节,这对于学习编程语言、游戏开发和逻辑构建非常有帮助。 【标签...

    my englishbook

    首先,文件的标题"my englishbook" 明确指向一个英语学习的平台或工具。这可能是教材,也可能是一套系统化的学习课程。从传统意义上来说,英语书籍包括了从基础语法、词汇,到实用对话、写作练习等多种学习模块。...

    初中语文文摘人生慢出来的价值

    一个软件项目从无到有,再到成熟稳定,往往需要经历数月甚至数年的时间。以开源项目Linux操作系统为例,它的发展历程已经超过了几十年。尽管如此,正是开发者的耐心与坚持,不断地修复、完善,才使Linux操作系统成为...

    无需编写任何代码即可创建应用程序:Deepseek-R1 和 RooCode AI 编码代理.pdf

    deepseek最新资讯、配置方法、使用技巧,持续更新中

    Heric拓扑并网离网仿真模型:PR单环控制,SogIPLL锁相环及LCL滤波器共模电流抑制技术解析,基于Heric拓扑的离网并网仿真模型研究与应用分析:PR单环控制与Sogipll锁相环的共模电流抑

    Heric拓扑并网离网仿真模型:PR单环控制,SogIPLL锁相环及LCL滤波器共模电流抑制技术解析,基于Heric拓扑的离网并网仿真模型研究与应用分析:PR单环控制与Sogipll锁相环的共模电流抑制效能,#Heric拓扑并离网仿真模型(plecs) 逆变器拓扑为:heric拓扑。 仿真说明: 1.离网时支持非单位功率因数负载。 2.并网时支持功率因数调节。 3.具有共模电流抑制能力(共模电压稳定在Udc 2)。 此外,采用PR单环控制,具有sogipll锁相环,lcl滤波器。 注:(V0004) Plecs版本4.7.3及以上 ,Heric拓扑; 离网仿真; 并网仿真; 非单位功率因数负载; 功率因数调节; 共模电流抑制; 共模电压稳定; PR单环控制; sogipll锁相环; lcl滤波器; Plecs版本4.7.3及以上,Heric拓扑:离网并网仿真模型,支持非单位功率因数与共模电流抑制

    培训机构客户管理系统 2024免费JAVA微信小程序毕设

    2024免费微信小程序毕业设计成品,包括源码+数据库+往届论文资料,附带启动教程和安装包。 启动教程:https://www.bilibili.com/video/BV1BfB2YYEnS 讲解视频:https://www.bilibili.com/video/BV1BVKMeZEYr 技术栈:Uniapp+Vue.js+SpringBoot+MySQL。 开发工具:Idea+VSCode+微信开发者工具。

    基于SMIC 40nm工艺库的先进芯片技术,SMIC 40nm工艺库技术细节揭秘:引领半导体产业新革命,smic40nm工艺库 ,smic40nm; 工艺库; 芯片制造; 纳米技术,SMIC 40nm

    基于SMIC 40nm工艺库的先进芯片技术,SMIC 40nm工艺库技术细节揭秘:引领半导体产业新革命,smic40nm工艺库 ,smic40nm; 工艺库; 芯片制造; 纳米技术,SMIC 40nm工艺库:领先技术驱动的集成电路设计基础

    2013年上半年软件设计师上午题-真题及答案解析

    2013年上半年软件设计师上午题-真题及答案解析

    淮南市乡镇边界,shp格式

    shp格式,可直接导入arcgis使用

    ROS下的移动机器人路径规划算法:基于强化学习算法DQN、DDPG、SAC及TD3的实践与应用,ROS系统中基于强化学习算法的移动机器人路径规划策略研究:应用DQN、DDPG、SAC及TD3算法,RO

    ROS下的移动机器人路径规划算法:基于强化学习算法DQN、DDPG、SAC及TD3的实践与应用,ROS系统中基于强化学习算法的移动机器人路径规划策略研究:应用DQN、DDPG、SAC及TD3算法,ROS下的移动机器人路径规划算法,使用的是 强化学习算法 DQN DDPG SAC TD3等 ,ROS; 移动机器人; 路径规划算法; DQN; DDPG; SAC; TD3,ROS强化学习移动机器人路径规划算法研究

    粒子群优化算法精准辨识锂电池二阶RC模型参数:高仿真精度下的SOC估计铺垫,粒子群优化算法精准辨识锂电池二阶RC模型参数:仿真验证与SOC估计铺垫,使用粒子群优化算法(PSO)辨识锂电池二阶RC模型参

    粒子群优化算法精准辨识锂电池二阶RC模型参数:高仿真精度下的SOC估计铺垫,粒子群优化算法精准辨识锂电池二阶RC模型参数:仿真验证与SOC估计铺垫,使用粒子群优化算法(PSO)辨识锂电池二阶RC模型参数(附MATLAB代码) 使用粒子群优化算法来辨识锂离子电池二阶RC模型的参数。 将粒子群优化算法寻找到的最优参数代入二阶RC模型进行仿真,经过验证,端电压的估计误差小于0.1%,说明粒子群优化算法辨识得到的参数具有较高的精度,为锂离子电池SOC的估计做铺垫。 ,关键词:粒子群优化算法(PSO); 锂电池二阶RC模型参数辨识; MATLAB代码; 端电压估计误差; 锂离子电池SOC估计。,PSO算法优化锂电池二阶RC模型参数:高精度仿真与MATLAB代码实现

    selenium环境搭建-谷歌浏览器驱动

    selenium环境搭建-谷歌浏览器驱动

    35页-华为智慧社区商业解决方案.pdf

    在当今科技日新月异的时代,智慧社区的概念正悄然改变着我们的生活方式。它不仅仅是一个居住的空间,更是一个集成了先进科技、便捷服务与人文关怀的综合性生态系统。以下是对智慧社区整体解决方案的精炼融合,旨在展现其知识性、趣味性与吸引力。 一、智慧社区的科技魅力 智慧社区以智能化设备为核心,通过综合运用物联网、大数据、云计算等技术,实现了社区管理的智能化与高效化。门禁系统采用面部识别技术,让居民无需手动操作即可轻松进出;停车管理智能化,不仅提高了停车效率,还大大减少了找车位的烦恼。同时,安防报警系统能够实时监测家中安全状况,一旦有异常情况,立即联动物业进行处理。此外,智能家居系统更是将便捷性发挥到了极致,通过手机APP即可远程控制家中的灯光、窗帘、空调等设备,让居民随时随地享受舒适生活。 视频监控与可视对讲系统的结合,不仅提升了社区的安全系数,还让居民能够实时查看家中情况,与访客进行视频通话,大大增强了居住的安心感。而电子巡更、公共广播等系统的运用,则进一步保障了社区的治安稳定与信息传递的及时性。这些智能化设备的集成运用,不仅提高了社区的管理效率,更让居民感受到了科技带来的便捷与舒适。 二、智慧社区的增值服务与人文关怀 智慧社区不仅仅关注科技的运用,更注重为居民提供多元化的增值服务与人文关怀。社区内设有互动LED像素灯、顶层花园控制喷泉等创意设施,不仅美化了社区环境,还增强了居民的归属感与幸福感。同时,社区还提供了智能家居的可选追加项,如空气净化器、远程监控摄像机等,让居民能够根据自己的需求进行个性化选择。 智慧社区还充分利用大数据技术,对居民的行为数据进行收集与分析,为居民提供精准化的营销服务。无论是周边的商业信息推送,还是个性化的生活建议,都能让居民感受到社区的智慧与贴心。此外,社区还注重培养居民的环保意识与节能意识,通过智能照明、智能温控等系统的运用,鼓励居民节约资源、保护环境。 三、智慧社区的未来发展与无限可能 智慧社区的未来发展充满了无限可能。随着技术的不断进步与创新,智慧社区将朝着更加智能化、融合化的方向发展。比如,利用人工智能技术进行社区管理与服务,将能够进一步提升社区的智能化水平;而5G、物联网等新技术的运用,则将让智慧社区的连接更加紧密、服务更加高效。 同时,智慧社区还将更加注重居民的体验与需求,通过不断优化智能化设备的功能与服务,让居民享受到更加便捷、舒适的生活。未来,智慧社区将成为人们追求高品质生活的重要选择之一,它不仅是一个居住的空间,更是一个融合了科技、服务、人文关怀的综合性生态系统,让人们的生活更加美好、更加精彩。 综上所述,智慧社区整体解决方案以其科技魅力、增值服务与人文关怀以及未来发展潜力,正吸引着越来越多的关注与认可。它不仅能够提升社区的管理效率与居民的生活品质,更能够为社区的可持续发展注入新的活力与动力。

    PowerSettingsExplorer.rar

    PowerSettingsExplorer.rar 电脑的电源管理软件,明白的不多说。自己搜索即可知道。

    2025年开源人工智能:关键参与者与预测.pdf

    deepseek最新资讯,配置方法,使用技巧,持续更新中

    DeepSeek 发布 Janus Pro AI 图像生成器 – 开源且免费.pdf

    deepseek最新资讯、配置方法、使用技巧,持续更新中

    消息中间件rabbitmq-server

    RabbitMQ 是一个开源的消息代理(Message Broker),实现了 AMQP(Advanced Message Queuing Protocol) 协议,用于在分布式系统中实现高效、可靠的消息传递。

    西门子S7-1200与汇川PLC新通信选择:Ethernet IP通信的突破与优势,功能安全及精准同步的创新实践 ,西门子S7-1200与汇川PLC通信新选择:Ethernet IP通信方案亮相,替代

    西门子S7-1200与汇川PLC新通信选择:Ethernet IP通信的突破与优势,功能安全及精准同步的创新实践。,西门子S7-1200与汇川PLC通信新选择:Ethernet IP通信方案亮相,替代Modbus TCP实现更高级功能与安全控制。,西门子PLC和汇川PLC新通信选择-西门子S7-1200 1500系列PLC也开始支持Ethernet IP通信了。 这为西门子系列的PLC和包括汇川AM400 600等Codesys系PLC的通信提供了新的解决方案。 当前两者之间的通信大多采用ModBus TCP通信。 Modbus TCP和EtherNet IP的区别主要是应用层不相同,ModbusTCP的应用层采用Modbus协议,而EtherNetIP采用CIP协议,这两种工业以太网的数据链路层采用的是CSMACCD,因此是标准的以太网,另外,这两种工业以太网的网络层和传输层采用TCPIP协议族。 还有一个区别是,Modbus协议中迄今没有协议来完成功能安全、高精度同步和运功控制等,而EtherNet IP有CIPSatety、ClIP Sync和ClPMotion来

    自适应无迹卡尔曼滤波AUKF算法:系统估计效果展示与特性分析(含MATLAB代码与Excel数据),自适应无迹卡尔曼滤波AUKF算法:系统估计效果展示与特性分析(含MATLAB代码与Excel数据)

    自适应无迹卡尔曼滤波AUKF算法:系统估计效果展示与特性分析(含MATLAB代码与Excel数据),自适应无迹卡尔曼滤波AUKF算法:系统估计效果展示与特性分析(含MATLAB代码与Excel数据),自适应无迹卡尔曼滤波AUKF算法 配套文件包含MATLAB代码+excel数据+学习资料 估计效果与系统特性有关,图片展示为一复杂系统估计效果 ,AUKF算法; MATLAB代码; excel数据; 学习资料; 估计效果; 系统特性。,自适应无迹卡尔曼滤波AUKF算法:MATLAB代码与学习资料

    基于MATLAB Simscape的IGBT开关特性模型:揭示开关损耗、米勒平台及瞬态行为的分析工具,IGBT开关特性模型与MATLAB Simscape模拟:深入理解开关行为及损耗数据,IGBT开关

    基于MATLAB Simscape的IGBT开关特性模型:揭示开关损耗、米勒平台及瞬态行为的分析工具,IGBT开关特性模型与MATLAB Simscape模拟:深入理解开关行为及损耗数据,IGBT开关特性模型,MATLAB Simscape模型。 该模型展示了IGBT的详细的开关模型,用于创建开关损耗列表数据。 有助于理解IGBT米勒平台、瞬态开关行为。 也可以用于MOOSFET。 ,IGBT开关模型; MATLAB Simscape; 开关损耗; 米勒平台; 瞬态开关行为; MOOSFET。,MATLAB Simscape中IGBT精细开关模型:揭示米勒平台与瞬态行为

Global site tag (gtag.js) - Google Analytics