新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论Semantic Web(语义Web,语义网或语义万维网, Web 3.0)及相关理论,如:Ontology(本体,本体论), OWL(Web Ontology Langauge,Web本体语言), Description Logic(DL, 描述逻辑),RDFa,Ontology Engineering等。
    [返回] 中文XML论坛 - 专业的XML技术讨论区W3CHINA.ORG讨论区 - Web新技术讨论『 Semantic Web(语义Web)/描述逻辑/本体 』 → [推荐]使用antlr建立词法分析器 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 5463 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: [推荐]使用antlr建立词法分析器 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     timothy 帅哥哟,离线,有人找我吗?巨蟹座1982-7-21
      
      
      威望:1
      等级:大四下学期(考上研究生啦!)
      文章:237
      积分:1701
      门派:XML.ORG.CN
      注册:2006/4/4

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给timothy发送一个短消息 把timothy加入好友 查看timothy的个人资料 搜索timothy在『 Semantic Web(语义Web)/描述逻辑/本体 』的所有贴子 点击这里发送电邮给timothy 引用回复这个贴子 回复这个贴子 查看timothy的博客楼主
    发贴心情 [推荐]使用antlr建立词法分析器

    本转贴综合了两个方面的内容,也是本文的两大部分,一个为antlr的安装,另一部分为antlr的使用实例

    一.下载和安装
         1 下载antlr的二进制包
    http://www.antlr.org/download/antlr-2.7.6.tar.gz
    解压到一个文件夹,比如f:\antlr-2.7.6,在该目录下面,可以看到antlr.jar。这个正是antlr的工具包。

    2 设置环境变量
    我的电脑-> 属性->高级-> 环境变量, 确保PATH里面含有jdk的bin路径,如”C:\Program Files\Java\j2sdk1.5.0\bin;”,  否则会提示找不到”java”命令

    环境变量CLASSPATH指明了java执行时,搜索class库文件的路径。如果CLASSPATH变量不存在,就需要自己新建一下了。在变量值里面添加  .;F:\antlr-2.7.6\antlr.jar
    各个路径以’;'分割, 第一个’.'表示总是先在当前目录寻找,第二个指明了antlr包的所在”F:\antlr-2.7.6\antlr.jar”。

    3 这样就可以工作了。写一个简单的语法描述文件test.g, 运行命令
    java antlr.Tool test.g

    antlr就会为你自动生成lexer,parser,你只需要写一个test.java调用这些分析类–一个简单的分析器就完成了。

    二.实例
       1、请在Eclipse中建立一个新的项目,名叫Simple2,在classpath中,要加入antlr.jar

    2、再下载一个文件:simple2.g,放在这个项目的路径下

    3、在DOS窗口下,输入antlr simple2.g

    4、回到eclispe,按F5刷新,会看到多出不少文件来。

    5、再新建一个类Main,输入以下代码: import java.io.*;
    public class Main {
        public static void main(String args[]) {
            FileInputStream f = null;
            try {
                f = new FileInputStream("......\\test.txt");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            DataInputStream input = new DataInputStream(f);
            SimpleLexer lexer = new SimpleLexer(input);
            SimpleParser parser = new SimpleParser(lexer);
            try {
                parser.entry();
            } catch(Exception e) {}
        }
    }


    6、新建一个文本文件test.txt,输入内容:

    06/06/82 Peter 20;
    03/04/83 Rosie 19;
    04/05/81 Mikey 21;


    7、运行Mainm,就能看到输出结果:

    Name: Peter, Age: 20, DOB: 06/06/82
    Name: Rosie, Age: 19, DOB: 03/04/83
    Name: Mikey, Age: 21, DOB: 04/05/81


    下面来解释一下,这里面的原理。先来看simple2.g的内容: class SimpleParser extends Parser;

    entry : (d:DOB n:NAME a:AGE(SEMI)
          {
            System.out.println(
              "Name: "    +
              n.getText() +
              ", Age: "   +
              a.getText() +
              ", DOB: "   +
              d.getText()
            );
          })*
          ;

    class SimpleLexer extends Lexer;

    NAME : ('a'..'z'|'A'..'Z')+;

    DOB  : ('0'..'9' '0'..'9' '/')=>
           (('0'..'9')('0'..'9')'/')(('0'..'9')('0'..'9')'/')('0'..'9')('0'..'9') //{ $setType(DOB); }
         | ('0'..'9')+  { $setType(AGE); } ;

    WS     :
        (' '
        | '\t'
        | '\r' '\n' { newline(); }
        | '\n'      { newline(); }
        )
        { $setType(Token.SKIP); }
      ;

    SEMI : ';' ;

    要理解这个文件,我们得从下往上读,才能渐入佳境


    最简单的是:  

    SEMI : ';';

    SEMI是一种符号,对于词法分析器来说,只要它读到一个字符是“;”,它就认为自己是读到了一个SEMI


    第二简单的是:

    NAME : ('a'..'z'|'A'..'Z')+;

    当词法分析器读取一个一个的字符的时候,当他读到一个以上的字母(无论大小写),它都把它们连在一起,作为一个NAME。()+,就是出现一次以上的意思。()*,就是出现0次以上的意思。


    第三简单的是:

    WS  :
        (' '
        | '\t'
        | '\r' '\n' { newline(); }
        | '\n'      { newline(); }
        )
        { $setType(Token.SKIP); }
      ;

    任何一个词法分析中定义的词,都有这样的格式:

    [名称] : [定义] ;

    定义的格式,又可以是一个或多个定义,';'就是一个定义,' '|'\t'就是两个定义。

    每个定义之后,都可以跟一段代码,在

    其中处理程序部分是可以省略的。

    对于WS的定义,就是(' '|'\t'|'\r''\n'|'\n') 。但是,我们在这个定义之中,发现了三个嵌有代码的地方:'\r''\n'和'\n'后面,都有一句话,newline(),这是告诉词法分析器,行号计数器加一。这样在出现词法、语法错误时,就能报告一个准确的行号了。

    在整个定义完成之后,还有一行代码$setType(Token.SKIP);,这是代码调用一个antlr的内置函数,告诉词法分析器,以上遇到的这四种字符情况,都请一律跳过。


    最难的一种:

    DOB  : ('0'..'9' '0'..'9' '/')=>
           (('0'..'9')('0'..'9')'/')(('0'..'9')('0'..'9')'/')('0'..'9')('0'..'9') //{ $setType(DOB); }
         | ('0'..'9')+  { $setType(AGE); } ;

    为什么说这个是最难的一种,因为这篇blog我本来按照每天一篇的进度,是该在昨天发出来的,结果我想了一天,才终于想通这个语法的意义。

    DOB,是一种单词,但是这个单词不是一次分析出来的,而是有一个试错的过程。

    DOB的格式是00/00/00,而AGE的格式是00。这样要区分两个单词,就相当困难。

    而现在的这个定义,则分为三个部分 (...)=>(...)|(...)。这相当于一般语言中的三元表达式:

    (1)?(2):(3)。如果式1为真,则返回式2的值,否则返回式3的值。

    DOB与AGE的区别在于第三个字符,如果('0'..'9' '0'..'9' '/')的尝试判断无误,则进一步分析这剩下的字符,是否符合DOB的格式。那//注释后面的代码,之所以被注释起来,就是因为他其实不用执行,也是DOB类型了。而如果('0'..'9' '0'..'9' '/')的尝试判断出错,则只能按照 ('0'..'9')+的判断来分析试一试,如果成立,就手工赋予一个类型AGE。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    时间永远是向前的!

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/5/14 15:31:00
     
     GoogleAdSense巨蟹座1982-7-21
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 Semantic Web(语义Web)/描述逻辑/本体 』的所有贴子 点击这里发送电邮给Google AdSense 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/6/2 18:37:56

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    5,429.688ms