精华内容
下载资源
问答
  • lex&yacc说到编译器(5.实用javacc)
    2021-03-09 23:10:45

    前言

    本系列的文章的宗旨是让大家能够写出自己的编译器,解释器或者脚本引擎,所以每到理论介绍到一个程度后,我都会来讨论实践问题.理论方面,编译原理的教材已经是够多了,而实践的问题却很少讨论.

    前几节文章只讨论到了词法分析和LL文法分析,关键的LR文法分析这里却还没有讲,我们先不要管复杂的LR文法和算法,让我们使用LL算法来实际做一些东西后再说.本文将介绍一个在JAVA上广泛使用的LL算法分析工具Javacc.(这是我唯一能找到的使用LL算法的语法分析器构造工具).这一节的文章并非只针对JAVA开发者,如果你是C/C++开发者,那么也请你来看看这个JAVA下的优秀工具,或许你将来也用得着它.

    Lex和yacc这两个工具是经典的词法分析和语法分析工具,但是它们都是基于C语言下面的工具,而使用JAVA的朋友们就用不上了.但是JAVA下已经有了lex和yacc的替代品javacc(

    Java Compiler Compiler )

    .同时javacc也是使用LL算法的工具,我们也可以实践一下前面学的LL算法.

    首先声明我不是一个JAVA专家,我也是刚刚才接触JAVA.Java里面或许有很多类似javacc一样的工具,但是据我所知,javacc还是最广泛,最标准的JAVA下的词法语法分析器.

    Javacc的获取

    同lex和yacc一样,javacc也是一个免费可以获取的通用工具,它可以在很多JAVA相关的工具下载网站下载,当然,javacc所占的磁盘空间比起lex和yacc更大一些,里面有标准的文档和examples.相对lex和yacc来说,javacc做得更人性化,更容易一些.如果你实在找不到javacc,还是可以联系我,我这里有.现在最新的就是javacc 3.2版本.

    Javacc的原理

    Javacc可以同时完成对text的词法分析和语法分析的工作,使用起来相当方便.同样,它和lex和yacc一样,先输入一个按照它规定的格式的文件,然后javacc根据你输入的文件来生成相应的词法分析于语法分析程序.同时,新版本的Javacc除了常规的词法分析和语法分析以外,还提供JJTree等工具来帮助我们建立语法树.总之,Javacc在很多地方做得都比lex和yacc要人性化,这个在后面的输入文件格式中也能体现出来.

    Javacc的输入文件

    Javacc的输入文件格式做得比较简单.每个非终结符产生式对应一个Class中的函数,函数中可以嵌入相应的识别出该终结符文法时候的处理代码(也叫动作).这个与YACC中是一致的.

    Javacc的输入文件中,有一系列的系统参数,比如其中lookahead可以设置成大于1的整数,那么就是说,它可以为我们生成LL(k)算法(k>=1),而不是简单的递归下降那样的LL(1)算法了.要知道,LL(2)文法比起前面讨论的LL(1)文法判断每个非终结符时候需要看前面两个记号而不是一个,那么对于文法形式的限制就更少.不过LL(2)的算法当然也比LL(1)算法慢了不少.作为一般的计算机程序设计语言,LL(1)算法已经是足够了.就算不是LL(1)算法,我们也可以通过前面讲的左提公因式把它变成一个LL(1)文法来处理.不过既然javacc都把lookahead选择做出来了,那么在某些特定的情况下,我们可以直接调整一个lookahead的参数就可以,而不必纠正我们的文法.

    下面我们来看看Javacc中自带的example中的例子.

    例5.1

    这个例子可以在javacc-3.2/doc/examples/SimpleExamples/Simple1.jj看到

    PARSER_BEGIN(Simple1)

    public class Simple1 {

    public static void main(String args[]) throws ParseException {

    Simple1 parser = new Simple1(System.in);

    parser.Input();

    }

    }

    PARSER_END(Simple1)

    void Input() :

    {}

    {

    MatchedBraces() ("\n"|"\r")*

    }

    void MatchedBraces() :

    {}

    {

    "{" [ MatchedBraces() ] "}"

    }

    设置好javacc的bin目录后,在命令提示符下输入

    javacc Simple1.jj

    然后

    javacc

    就会为你生成下面几个

    java

    源代码文件

    Simple1.java

    Simple1TokenManager.java

    Simple1Constants.java

    SimpleCharStream.java

    Token.java

    TokenMgrError.java

    其中Simple1就是你的语法分析器的对象,它的构造函数参数就是要分析的输入流,这里的是System.in.

    class Simple1就定义在标记

    PARSER_BEGIN(Simple1)

    PARSER_END(Simple1)之间.

    但是必须清楚的是,PARSER_BEGIN和PARSER_END中的名字必须是词法分析器的名字(这里是Simple1).

    PARSER_END下面的定义就是文法非终结符号的定义了.

    Simple1的文法基本就是:

    Input ->

    MatchedBraces ("\n"|"\r")*

    MatchedBraces ->

    {

    MatchedBraces

    }

    从它的定义我们可以看到

    ,

    每个非终结符号对于一个过程

    .

    比如

    Input

    的过程

    void Input() :

    {}

    {

    MatchedBraces() ("\n"|"\r")*

    }

    在定义

    void Input

    后面记住需要加上一个冒号

    ”:”,

    然后接下来是两个块

    {}

    的定义

    .

    第一个

    {}

    中的代码是定义数据

    ,

    初试化数据的代码

    .

    第二个

    {}

    中的部分就是真正定义

    Input

    的产生式了

    .

    每个产生式之间用

    ”|”

    符号连接

    .

    注意

    :

    这里的产生式并非需要严格

    BNF

    范式文法

    ,

    它的文法既可以是

    BNF,

    同时还可以是混合了正则表达式中的定义方法

    .

    比如上面的

    Input ->

    MatchedBraces ("\n"|"\r")*

    (“\n”|”\r”)*

    就是个正则表达式

    ,

    表示的是

    \n

    或者

    \r

    0

    个到无限个的重复的记号

    .

    javacc

    系统定义的记号

    (TOKEN),

    表示文件结束符号

    .

    除了

    ,

    无论是系统定义的

    TOKEN,

    还是自定义的

    TOKEN,

    里面的

    TOKEN

    都是以

    的方式表示

    .

    每个非终结符号

    (Input

    MatchedBraces)

    都会在

    javacc

    生成的

    Simple1.java

    中形成

    Class Simple1

    的成员函数

    .

    当你在外部调用

    Simple1

    Input,

    那么语法分析器就会开始进行语法分析了

    .

    5.2

    javacc

    提供的

    example

    里面没有

    .javacc

    提供的

    example

    里面提供的例子中

    SimpleExamples

    过于简单

    ,

    而其它例子又过于庞大

    .

    下面我以我们最常见的数学四则混合运算的文法来构造一个

    javacc

    的文法识别器

    .

    这个例子是我自己写的

    ,

    十分简单

    ,.

    其中还包括了文法识别同时嵌入的构建语法树

    Parse-Tree

    的代码

    .

    不过由于篇幅的原因

    ,

    我并没有给出全部的代码

    ,

    这里只给了

    javacc

    输入部分相关的代码

    .

    Parse-tree

    就是一个普通的

    4

    叉树

    ,3

    child,1

    next(

    平行结点

    ),

    相信大家在学习数据结构的时候应该都是学过的

    .

    所以这里就省略过去了

    .

    在大家看这些输入代码之前

    ,

    我先给出它所使用的文法定义

    ,

    好让大家有个清楚的框架

    .

    Expression

    -> Term{ Addop Term }

    Addop -> "+" | "-"

    Term->Factor { Mulop Factor }

    Mulop -> "*" | "/"

    Factor -> ID | NUM | "("Expression")"

    这里的文法可能和BNF范式有点不同.{}的意思就是0次到无限次重复,它跟我们在学习正则表达式的时候的”*”符号相同,所以,在Javacc中的文法表示的时候,{…}部分的就是用(…)*来表示.

    为了让词法分析做得更简单

    ,

    我们通常都不会在文法分析的时候

    ,

    使用

    ”(”,”)“

    等字符号串来表示终结符号

    ,

    而需要转而使用

    LPAREN

    ,

    RPAREN

    这样的整型符号来表示

    .

    PARSER_BEGIN(Grammar)

    public class Grammar implements NodeType {

    public ParseTreeNode GetParseTree(InputStream in) throws ParseException

    {

    Grammar parser =new Grammar(in);

    return parser.Expression();

    }

    }

    PARSER_END(Grammar)

    SKIP :

    {

    " " | "\t" | "\n" | "\r"

    }

    TOKEN :

    {

    < ID: ["a"-"z","A"-"Z","_"] ( ["a"-"z","A"-"Z","_","0"-"9"] )* >

    |< NUM: ( ["0"-"9"] )+ >

    | < PLUS:"+" >

    | < MINUS:"-" >

    | < TIMERS: "*" >

    | < OVER:"/" >

    | < LPAREN: "(" >

    | < RPAREN: ")" >

    }

    ParseTreeNode Expression() :

    {

    ParseTreeNode ParseTree = null;

    ParseTreeNode node;

    }

    {

    ( node=Simple_Expression()

    {

    if(ParseTree == null)

    ParseTree =node;

    else

    {

    ParseTreeNode t;

    t= ParseTree;

    while(t.next != null)

    t=t.next;

    t.next = node;

    }

    }

    )*

    { return ParseTree;}

    }

    ParseTreeNode Simple_Expression() :

    {

    ParseTreeNode node;

    ParseTreeNode t;

    int op;

    }

    {

    node=Term(){}

    (

    op=addop() t=Term()

    {

    ParseTreeNode newNode = new ParseTreeNode();

    newNode.nodetype = op;

    newNode.child[0] = node;

    newNode.child[1] = t;

    switch(op)

    更多相关内容
  • PRECISE自然语言的Java实现与SQL数据库的接口。 v0.1 安装: 下载在lib /目录中 下载 运行测试GUI: TestGUI path_to_wordnet_database path_to_lexicon 可以在lex /中找到的词典 改善 单词索引 基于: Popescu...
  • 它的基本原理就是使用正则表达式扫描匹配文本,并为每一个匹配模式定义一些操作,当用C语言作宿主语言时,这些操作都由C语言实现。一种匹配的正则表达式可能会包含相关的动作。这一动作可能还包括返回一个标记。当 ...

    展开全部

    Lex是美国Bell实验室用C语言研制的一个词法分析程序自生成工具62616964757a686964616fe78988e69d8331333361303131

    。它的基本原理就是使用正则表达式扫描匹配文本,并为每一个匹配模式定义一些操作,当用C语言作宿主语言时,这些操作都由C语言实现。

    一种匹配的正则表达式可能会包含相关的动作。这一动作可能还包括返回一个标记。当 Lex 接收到文件或文本形式的输入时,它试图将文本与正则表达式进行匹配。它一次读入一个输入字符,直到找到一个匹配的模式。如果能够找到一个匹配的模式,Lex 就执行相关的动作(可能包括返回一个标记)。另一方面,如果没有可以匹配的正则表达式,将会停止进一步的处理,Lex 将显示一个错误消息。

    Lex 和 C 是强耦合的。一个 .l 文件(Lex 文件具有 .l 的扩展名)通过 lex 公用程序来传递,并生成 C 的输出文件。这些文件被编译为词法分析器的可执行版本。

    本程序对java源程序进行分析,主要实现以下两个功能:

    (1)、清除注释。java源程序有三种注释方法:1、单行注释,以//开头直到行结束;2、多行注释,以/*为开始,*/为结束,可以注释多行;3、java文档注释,这也是一种多行注释,但它可以通过java文档生成工具写入java程序文档中。它以/**为开始,*/为结束。

    (2)、通过程序行数计算工作量。

    (3)、计算程序中类的个数,并判断有没有两个public类,如果存在则报错:There is an error:One java file cannot includes two public class。

    单行注释的清除。由于单行注释以//开头直到行结束,首先要匹配的就是//,然后清除从匹配处到行结束的所有字符。具体实现如下:

    "//" {

    int c;

    while ( (c = input()) != '/n' &&

    c != EOF )

    {

    ;

    }

    code = add(code,'/n');

    }

    多行注释的清除。多行注释有两种,一种是普通多行注释,另一种是java文档注释。这两种注释都以*/结束,普通多行注释以/*开始,java文档注释以/**开始。可以先匹配/*,然后向后搜索*/。要区别这两种注释就要看/*后面是否紧跟一个*字符,如果不是则为普通多行注释;如果是还要看下一字符是否为/字符,如果是也为普通注释,如果不是则为java文档注释。具体lex程序实现如下:

    "/*" {

    int c,ct=0;

    char * javadoc = "/*there is a Java Doc Comment*/";

    for ( ; ; )

    {

    while ( (c = input()) != '*' &&

    c != EOF )

    {

    ct++;

    }

    if ( c == '*' )

    {

    c = input();

    if ( c == '/' )

    {

    ct = 0;

    break; /* found the end */

    }

    else

    {

    if(ct==0)

    code = strcat(code,javadoc);

    }

    }

    if ( c == EOF )

    {

    printf( "EOF in comment" );

    break;

    }

    }

    }

    my.l即为lex程序。输入一段带有注释的java源程序,然后打入结束标志$号,回车就可以看到在输出的程序中所有注释都已经删除,在含有java文档注释的地方加上了一句注释:/*there is a Java Doc Comment*/。

    经过仔细研究发现,上面的实现过程还是过分依赖C语言,没有真正发挥Lex模式匹配的强大功能。单行注释、普通多行注释、Java文档注释可分别由下列模式匹配:

    .*/n

    ///*[^/*//]*/*//

    ///*/*[^/*//]*/*//

    本程序还提供了识别类定义的功能,匹配模式如下:

    public[ /n/t]+class[ /n/t]+[a-zA-Z][_a-zA-z0-9]*/[ /n/t]*/{[^/]}*/}

    (public|protected|private)[ /n/t]+class[ /n/t]+[a-zA-Z][_a-zA-z0-9]*/[ /n/t]*/{[^/]}*/}

    [ /n/t]*class[ /n/t]+[a-zA-Z][_a-zA-z0-9]*/[ /n/t]*/{[^/]}*/}

    经完善后的lex程序如下所示:

    %{

    #include

    char * code = "";

    int codelines = 0;

    int classnum = 0;

    int pubclass = 0;

    char * classes[4]={"","","",""};

    /*add a char c to the string code*/

    char * add(char * code,char c)

    {

    char * temp;

    if(code==NULL)

    return "";

    temp = (char*)malloc(sizeof(char)*2);

    temp[0] = c;

    temp[1] = '/0';

    temp = strcat(code,temp);

    return temp;

    }

    %}

    %%

    ///*[^/*//]*/*// code = add(code,'');

    ///*/*[^/*//]*/*// code = strcat(code,"/*there is a Java Doc Comment*//n");

    .*/n code = add(code,'/n');

    public[ /n/t]+class[ /n/t]+[a-zA-Z][_a-zA-z0-9]*/[ /n/t]*/{[^/}]*/} {

    classes[classnum] = (char*)malloc(100);

    classes[classnum] = strcpy(classes[classnum],yytext);

    classnum++;

    code = strcat(code,yytext);

    pubclass++;

    }

    (public|protected|private)[ /n/t]+class[ /n/t]+[a-zA-Z][_a-zA-z0-9]*/[ /n/t]*/{[^/}]*/} {

    classes[classnum] = (char*)malloc(100);

    classes[classnum] = strcpy(classes[classnum],yytext);

    classnum++;

    code = strcat(code,yytext);

    }

    [ /n/t]*class[ /n/t]+[a-zA-Z][_a-zA-z0-9]*/[ /n/t]*/{[^/}]*/} {

    classes[classnum] = (char*)malloc(100);

    classes[classnum] = strcpy(classes[classnum],yytext);

    classnum++;

    code = strcat(code,yytext);

    }

    /n code = add(code,'/n');

    . {

    if(yytext[0] == ';')

    codelines++;

    code = add(code,yytext[0]);

    }

    %%

    yywrap()

    {

    int i=0;

    printf("/nBelow is the code without comment:/n/n");

    printf(code);

    printf("/n/nConclude:/nThis code weights %d lines/n",codelines);

    printf("This code includes %d classes/n",classnum);

    printf("classes:/n");

    for(i=0;i

    {

    printf(classes[i]);

    printf("/n");

    }

    if(pubclass>1)

    printf("/nThere is an error: a java file cannot have two public class/n");

    code = (char*)malloc(1);

    code[0]='/0';

    }

    main()

    {

    yylex();

    system("pause");

    return 1;

    }

    这个程序还有另外两个其他功能:1、根据程序的行数来确定程序工作量,行数等于分号的个数。在结果的末尾将会显示行数;2、我们知道一个java文件中不能存在两个public类,本程序可以检查一个文件中存在几个类,并判断是否存在两个或两个以上的public类,如果存在就报错。

    注:my.l文件是改进前的lex程序,改进后的程序保存在my1.l文件中,Java.txt内含有一个java源程序可以用来测试。运行lexyy.exe,复制java.txt里面的内容粘贴到程序里,加上输入结束符Ctrl+z,然后回车即可看到结果;或者在dos下把java.txt作为lexyy.exe的参数运行lexyy.exe也可。

    2Q==

    已赞过

    已踩过<

    你对这个回答的评价是?

    评论

    收起

    展开全文
  • 这是一个编译原理lex工具,具备词法分析器的功能,方便了解编译原理词法分析器的功能
  • java实现的词法分析和语法分析的小程序 :carp_streamer: 个人博客网站: : :heart_with_ribbon: :television:结果图 词法分析 语法分析 判断是否是LL(1)文法 概述 词法分析:根据输入的字符序列,将字符序列...
  • 编译原理-词法分析器1(lex实现)-附件资源
  • 编译原理-词法分析器1(lex实现)

    千次阅读 2018-11-05 16:10:26
    编译原理课实验一是词法分析器,但是在网上查了很多资料,发现用lex实现还要用Linux,Windows可以用对应的flex实现,但是网上的资料很零散,所以整理了一下从安装到配置,到实现一个词法分析器的过程 一、 安装 ...

    编译原理课实验一是词法分析器,但是在网上查了很多资料,发现用lex实现还要用Linux,Windows可以用对应的flex实现,但是网上的资料很零散,所以整理了一下从安装到配置,到实现一个词法分析器的过程

    一、 安装

    1. 下载flex和bison
      UnxUtils: http://pan.baidu.com/s/1o6NY1E6
      Updates:http://pan.baidu.com/s/1o6NY1E6
      保存在E:\lex\cywin
    2. 使用的flex和bison都是GNU的工具,GCC既采用C/C++的编译器也采用GNU的编译器,Windows平台的GCC主要是MinGW编译器,下载地址:
      https://sourceforge.net/projects/mingw/files/Installer/mingw-get/catalogue/msys-package-list.xml.lzma/download
      或者
      http://www.mingw-w64.org/doku.php
      保存在E:\lex\GnuWin32
    3. 下载Parser Generator
      http://www.bumblebeesoftware.com/downloads.htm
      二、 配置环境变量
      下载UnxUtils以及UnxUpdates之后,解压到自己的文件夹,把/usr/local/wbin文件夹的绝对地址加到
      我的电脑(右键)->属性->高级->环境变量->系统变量->path值
      三、 安装MinGW
    4. 安装过程简图
      点击mingw-get-setup.exe

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    1. 打开安装好的软件,选Basic Setup,在右侧选择mingw32-gcc-g++,鼠标右键点击Mark for Installation,然后点击左上角的Installation按钮,选择Apply Changes,弹出对话框点击Apply,安装对应的编辑器
    2. 设置环境变量
      进入MinGW的安装路径E:\lex\GnuWin32,将bin的绝对路径添加到path中(E:\lex\GnuWin32\bin)
      我的电脑(右键)->属性->高级->环境变量->系统变量->path值
    3. 检查安装完成
      打开cmd,输入gcc -v,显示如下即为安装成功
      在这里插入图片描述
      四、 Parser Generator的配置
    4. 打开Parser Generator
    5. 菜单project->LibBuilder选第一个

    在这里插入图片描述
    在这里插入图片描述
    3. 配置好后点击built
    在这里插入图片描述
    4. 建立一个project
    <1>project->ParserWizard
    <2>工程设定(语言可选C/C++/JAVA)
    <3>工程设定(是否带main函数的YACC文件或LEX文件)
    <4>YACC文件设定
    <5>LEX文件设定
    <6>编辑好代码后project->Rebuild All
    上图:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    五、 配置VC6.0

    1. 打开cmd,一直到1.l存在的文件夹的目录下
      在这里插入图片描述
    2. Flex 1.l,此时再打开1.l的文件夹会发现出现lex.yy.c文件
      在这里插入图片描述
    3. 那么现在开始配置VC,首先导入Parser Generator的库文件和源文件
      Tools->Options,设置Iuclude files,library files,Source files

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    4. project->Settings
    Win32 Debug
    C/C++ -> preprocessor definitions添加宏定义,YYDEBUG
    Link -> Object/Library Modules 加yld,lib
    Win32 Release
    Link -> Object/Library Modules 加yld,lib

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    1. 将lex.yy.c添加到Source Files
      将1.h添加到Header Files
      在这里插入图片描述
    2. 编译运行就OK啦
    3. 或者在DOS下运行
      在这里插入图片描述
    展开全文
  • 首先看下我们要分析的代码段如下:输出结果如下:输出结果(a).PNG输出结果(b).PNG输出结果(c).PNG括号里是一个二元...import java.io.*;/** 主程序*/public class Main {public static void main(String[] args) th...

    首先看下我们要分析的代码段如下:

    1093ac79578b73bc1b4809d3b0d3a883.png

    输出结果如下:

    103d8262da2de394610c01d9d891fd59.png

    输出结果(a).PNG

    d232711211f5e801dbdcc8b563fe665e.png

    输出结果(b).PNG

    402b3dd49e2b868d0e2792b63c090ccf.png

    输出结果(c).PNG

    括号里是一个二元式:(单词类别编码,单词位置编号)

    代码如下:

    package Yue.LexicalAnalyzer;

    import java.io.*;

    /*

    * 主程序

    */

    public class Main {

    public static void main(String[] args) throws IOException {

    Lexer lexer = new Lexer();

    lexer.printToken();

    lexer.printSymbolsTable();

    }

    }

    package Yue.LexicalAnalyzer;

    import java.io.*;

    import java.util.*;

    /*

    * 词法分析并输出

    */

    public class Lexer {

    /*记录行号*/

    public static int line = 1;

    /*存放最新读入的字符*/

    char character = ' ';

    /*保留字*/

    Hashtable keywords = new Hashtable();

    /*token序列*/

    private ArrayList tokens = new ArrayList();

    /*符号表*/

    private ArrayList symtable = new ArrayList();

    /*读取文件变量*/

    BufferedReader reader = null;

    /*保存当前是否读取到了文件的结尾*/

    private Boolean isEnd = false;

    /* 是否读取到文件的结尾 */

    public Boolean getReaderState() {

    return this.isEnd;

    }

    /*打印tokens序列*/

    public void printToken() throws IOException {

    FileWriter writer = new FileWriter("E:\\lex.txt");

    System.out.println("词法分析结果如下:");

    System.out.print("杜悦-2015220201031\r\n\n");

    writer.write("杜悦-2015220201031\r\n\r\n");

    while (getReaderState() == false) {

    Token tok = scan();

    String str = "line " + tok.line + "\t(" + tok.tag + "," + tok.pos + ")\t\t"

    + tok.name + ": " + tok.toString() + "\r\n";

    writer.write(str);

    System.out.print(str);

    }

    writer.flush();

    }

    /*打印符号表*/

    public void printSymbolsTable() throws IOException {

    FileWriter writer = new FileWriter("E:\\symtab1.txt");

    System.out.print("\r\n\r\n符号表\r\n");

    System.out.print("编号\t行号\t名称\r\n");

    writer.write("符号表\r\n");

    writer.write("编号 " + "\t行号 " + "\t名称 \r\n");

    Iterator e = symtable.iterator();

    while (e.hasNext()) {

    Symbol symbol = e.next();

    String desc = symbol.pos + "\t" + symbol.line + "\t" + symbol.toString();

    System.out.print(desc + "\r\n");

    writer.write(desc + "\r\n");

    }

    writer.flush();

    }

    /*打印错误*/

    public void printError(Token tok) throws IOException{

    FileWriter writer = new FileWriter("E:\\error.txt");

    System.out.print("\r\n\r\n错误词法如下:\r\n");

    writer.write("错误词法如下:\r\n");

    String str = "line " + tok.line + "\t(" + tok.tag + "," + tok.pos + ")\t\t"

    + tok.name + ": " + tok.toString() + "\r\n";

    writer.write(str);

    }

    /*添加保留字*/

    void reserve(KeyWord w) {

    keywords.put(w.lexme, w);

    }

    public Lexer() {

    /*初始化读取文件变量*/

    try {

    reader = new BufferedReader(new FileReader("E:\\输入.txt"));

    } catch (IOException e) {

    System.out.print(e);

    }

    /*添加保留字*/

    this.reserve(KeyWord.begin);

    this.reserve(KeyWord.end);

    this.reserve(KeyWord.integer);

    this.reserve(KeyWord.function);

    this.reserve(KeyWord.read);

    this.reserve(KeyWord.write);

    this.reserve(KeyWord.aIf);

    this.reserve(KeyWord.aThen);

    this.reserve(KeyWord.aElse);

    }

    /*按字符读*/

    public void readch() throws IOException {

    character = (char) reader.read();

    if ((int) character == 0xffff) {

    this.isEnd = true;

    }

    }

    /*判断是否匹配*/

    public Boolean readch(char ch) throws IOException {

    readch();

    if (this.character != ch) {

    return false;

    }

    this.character = ' ';

    return true;

    }

    /*数字的识别*/

    public Boolean isDigit() throws IOException {

    if (Character.isDigit(character)) {

    int value = 0;

    while (Character.isDigit(character)) {

    value = 10 * value + Character.digit(character, 10);

    readch();

    }

    Num n = new Num(value);

    n.line = line;

    tokens.add(n);

    return true;

    } else

    return false;

    }

    /*保留字、标识符的识别*/

    public Boolean isLetter() throws IOException {

    if (Character.isLetter(character)) {

    StringBuffer sb = new StringBuffer();

    /*首先得到整个的一个分割*/

    while (Character.isLetterOrDigit(character)) {

    sb.append(character);

    readch();

    }

    /*判断是保留字还是标识符*/

    String s = sb.toString();

    KeyWord w = keywords.get(s);

    /*如果是保留字的话,w不应该是空的*/

    if (w != null) {

    w.line = line;

    tokens.add(w);

    } else {

    /*否则就是标识符,此处多出记录标识符编号的语句*/

    Symbol sy = new Symbol(s);

    Symbol mark = sy; //用于标记已存在标识符

    Boolean isRepeat = false;

    sy.line = line;

    for (Symbol i : symtable) {

    if (sy.toString().equals(i.toString())) {

    mark = i;

    isRepeat = true;

    }

    }

    if (!isRepeat) {

    sy.pos = symtable.size() + 1;

    symtable.add(sy);

    } else if (isRepeat) {

    sy.pos = mark.pos;

    }

    tokens.add(sy);

    }

    return true;

    } else

    return false;

    }

    /*符号的识别*/

    public Boolean isSign() throws IOException {

    switch (character) {

    case '#':

    readch();

    AllEnd.allEnd.line = line;

    tokens.add(AllEnd.allEnd);

    return true;

    case '\r':

    if (readch('\n')) {

    readch();

    LineEnd.lineEnd.line = line;

    tokens.add(LineEnd.lineEnd);

    line++;

    return true;

    }

    case '(':

    readch();

    Delimiter.lpar.line = line;

    tokens.add(Delimiter.lpar);

    return true;

    case ')':

    readch();

    Delimiter.rpar.line = line;

    tokens.add(Delimiter.rpar);

    return true;

    case ';':

    readch();

    Delimiter.sem.line = line;

    tokens.add(Delimiter.sem);

    return true;

    case '+':

    readch();

    CalcWord.add.line = line;

    tokens.add(CalcWord.add);

    return true;

    case '-':

    readch();

    CalcWord.sub.line = line;

    tokens.add(CalcWord.sub);

    return true;

    case '*':

    readch();

    CalcWord.mul.line = line;

    tokens.add(CalcWord.mul);

    return true;

    case '/':

    readch();

    CalcWord.div.line = line;

    tokens.add(CalcWord.div);

    return true;

    case ':':

    if (readch('=')) {

    readch();

    CalcWord.assign.line = line;

    tokens.add(CalcWord.assign);

    return true;

    }

    break;

    case '>':

    if (readch('=')) {

    readch();

    CalcWord.ge.line = line;

    tokens.add(CalcWord.ge);

    return true;

    }

    break;

    case '

    if (readch('=')) {

    readch();

    CalcWord.le.line = line;

    tokens.add(CalcWord.le);

    return true;

    }

    break;

    case '!':

    if (readch('=')) {

    readch();

    CalcWord.ne.line = line;

    tokens.add(CalcWord.ne);

    return true;

    }

    break;

    }

    return false;

    }

    /*下面开始分割关键字,标识符等信息*/

    public Token scan() throws IOException {

    Token tok;

    while (character == ' ')

    readch();

    if (isDigit() || isSign() || isLetter()) {

    tok = tokens.get(tokens.size() - 1);

    } else {

    tok = new Token(character);

    printError(tok);

    }

    return tok;

    }

    }

    package Yue.LexicalAnalyzer;

    /*

    * Token父类

    */

    public class Token {

    public final int tag;

    public int line = 1;

    public String name = "";

    public int pos = 0;

    public Token(int t) {

    this.tag = t;

    }

    public String toString() {

    return "" + (char) tag;

    }

    }

    package Yue.LexicalAnalyzer;

    /*

    * 单词类别赋值

    */

    public class Tag {

    public final static int

    BEGIN = 1, //保留字

    END = 2, //保留字

    INTEGER = 3, //保留字

    FUNCTION = 4, //保留字

    READ = 5, //保留字

    WRITE = 6, //保留字

    IF = 7, //保留字

    THEN = 8, //保留字

    ELSE = 9, //保留字

    SYMBOL = 11, //标识符

    CONSTANT = 12, //常数

    ADD = 13, //运算符 "+"

    SUB = 14, //运算符 "-"

    MUL = 15, //运算符 "*"

    DIV = 16, //运算符 "/"

    LE = 18, //运算符 "<="

    GE = 19, //运算符 ">="

    NE = 20, //运算符 "!="

    ASSIGN = 23, //运算符 ":="

    LPAR = 24, //界符 "("

    RPAR = 25, //界符 ")"

    SEM = 26, //界符 ";"

    LINE_END = 27, //行尾符

    ALL_END = 28; //结尾符 "#"

    }

    package Yue.LexicalAnalyzer;

    /**

    * 保留字

    */

    public class KeyWord extends Token {

    public String lexme = "";

    public KeyWord(String s, int t) {

    super(t);

    this.lexme = s;

    this.name = "保留字";

    }

    public String toString() {

    return this.lexme;

    }

    public static final KeyWord

    begin = new KeyWord("begin", Tag.BEGIN),

    end = new KeyWord("end", Tag.END),

    integer = new KeyWord("integer", Tag.INTEGER),

    function = new KeyWord("function", Tag.FUNCTION),

    read = new KeyWord("read", Tag.READ),

    write = new KeyWord("write", Tag.WRITE),

    aIf = new KeyWord("if", Tag.IF),

    aThen = new KeyWord("then", Tag.THEN),

    aElse = new KeyWord("else", Tag.ELSE);

    }

    package Yue.LexicalAnalyzer;

    /*

    * 标识符

    */

    public class Symbol extends Token {

    public String lexme = "";

    public Symbol(String s) {

    super(Tag.SYMBOL);

    this.lexme = s;

    this.name = "标识符";

    }

    public String toString() {

    return this.lexme;

    }

    }

    package Yue.LexicalAnalyzer;

    /**

    * 运算符

    */

    public class CalcWord extends Token {

    public String lexme = "";

    public CalcWord(String s, int t) {

    super(t);

    this.lexme = s;

    this.name = "运算符";

    }

    public String toString() {

    return this.lexme;

    }

    public static final CalcWord

    add = new CalcWord("+", Tag.ADD),

    sub = new CalcWord("-", Tag.SUB),

    mul = new CalcWord("*", Tag.MUL),

    div = new CalcWord("/", Tag.DIV),

    le = new CalcWord("<=", Tag.LE),

    ge = new CalcWord(">=", Tag.GE),

    ne = new CalcWord("!=", Tag.NE),

    assign = new CalcWord(":=", Tag.ASSIGN);

    }

    package Yue.LexicalAnalyzer;

    /**

    * 界符

    */

    public class Delimiter extends Token {

    public String lexme = "";

    public Delimiter(String s, int t) {

    super(t);

    this.lexme = s;

    this.name = "界符";

    }

    public String toString() {

    return this.lexme;

    }

    public static final Delimiter

    lpar = new Delimiter("(", Tag.LPAR),

    rpar = new Delimiter(")", Tag.RPAR),

    sem = new Delimiter(";", Tag.SEM);

    }

    package Yue.LexicalAnalyzer;

    /*

    * 常数

    */

    public class Num extends Token {

    public final int value;

    public Num(int v) {

    super(Tag.CONSTANT);

    this.value = v;

    this.name = "常数";

    }

    public String toString() {

    return "" + value;

    }

    }

    package Yue.LexicalAnalyzer;

    /**

    * 行尾符

    */

    public class LineEnd extends Token {

    public String lexme = "";

    public LineEnd(String s) {

    super(Tag.LINE_END);

    this.lexme = s;

    this.name = "行尾符";

    }

    public String toString() {

    return this.lexme;

    }

    public static final LineEnd lineEnd = new LineEnd("\r\n");

    }

    package Yue.LexicalAnalyzer;

    /**

    * 结尾符

    */

    public class AllEnd extends Token {

    public String lexme = "";

    public AllEnd(String s) {

    super(Tag.ALL_END);

    this.lexme = s;

    this.name = "结尾符";

    }

    public String toString() {

    return this.lexme;

    }

    public static final AllEnd allEnd = new AllEnd("#");

    }

    总结

    以上就睡这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

    您可能感兴趣的文章:

    展开全文
  • 最近做的项目有将Markdown语法转换成HTML语法的这么一个...然鹅 自己写个Utils太麻烦了 为此找到了个很实用的转换工具包:flexmark 第一步:引入flexmark的依赖: ... flexmark-all 0.50.42 第二步:直接使用即可: ...
  • 通过一张照片来进行GPS定位,java实现起来就这么简单
  • 主要针对的是编译原理程序设计这门课的大作业所做的小项目,里边有完整的代码,以及使用说明,包括bnf范式。
  • Java实现Json解析器

    千次阅读 2019-02-17 12:59:09
    在开始正文之前,先啰嗦几...虽然他是用C语言写的,哈哈~就这样我跟着大牛的文档和代码写了一边C语言的JSON后,对JSON的语法以及实现有了一个初级的了解,然后,我就开始着手写Java版的Json,emmm…在写之前,为了看...
  • 一个用Python编写的Java源代码的词法分析器 例子 代码 from jlex . lexer import lex_source_file from jlex . type import Type tokens = lex_source_file ( 'Example.java' ) for token in tokens : if ...
  • IK Analyzer是基于lucene实现的分词开源框架,下载路径:http://code.google.com/p/ik-analyzer/downloads/list 需要在项目中引入: IKAnalyzer.cfg.xml IKAnalyzer2012.jar lucene-core-3.6.0.jar ...
  • 文件名称: compiler下载 收藏√ [5 4 3 2 1]开发工具: Java文件大小: 596 KB上传时间: 2013-05-04下载次数: 0详细说明:Java实现的编译器前端(一直到中间代码生成)其中使用了JFLEX及CUP做Lex-Compiler by Java文件...
  • Java这些东西

    2021-03-09 23:10:15
    FOP, Kindle, Velocity, Clojure, JNDI, Clover,Hadoop, JSF, Jackrabbit, Livescribe pen, Commons, Hibernate, EJB, Tobago, IntelliJ, Jersey,Scalaz, HornetQ, JAX-RS, Lift, Derby, JUnit, Freemarker, JavaME,...
  • lex-main.lex

    2013-09-15 19:06:40
    分词算法源文件(lex-main,java中的用于写分词算法的词库)
  • lexer and parser 的java简单实现

    千次阅读 2019-03-11 19:45:14
    java实现一个词法分析器,参考link可以识别加法与乘法中的token。 token 种别码 EOI 0 SEMI(;) 1 PLUS(+) 2 TIMES(*) 3 LP( ( ) 4 RP( ) ) 5 NUM 6 ...
  • 三种flex4与Java顺利通信的方式是: ... *第一种 功能描述:该类用来实现flex与普通java类中的方法通信 * @author Administrator */ //以上是打头的功能描述,可以不写。 <!–flex 与普通java类通信–
  • 本文本着动手实操(念第一声)的原则,用java实现一个简单的编译器,让读者朋友能一感编译原理的实质,我秉持一个原则,没有代码可实践的计算机理论,都是耍流氓。 编译器作用就是将一种计算机无法理解的文本,转译成...
  • IK Analyzer是基于lucene实现的分词开源框架;需要在项目中引入:IKAnalyzer.cfg.xml 、IKAnalyzer2012.jar 、lucene-core-3.6.0.jar 、stopword.dicIK Analyzer示例代码如下:package com.haha.test;import java.io...
  • 本来我的计划是简单把lex和yacc介绍完后就直接进入编译器的构造的技术细节问题讨论,但是最近看了一些国外经典教材后,发现文法的识别问题在编译原理和技术中是个绝不能忽视的问题.即使现在有了yacc工具来帮助我来识别...
  • atitit.java解析sql语言解析器解释器的实现1.解析sql的本质:实现一个4gldsl编程语言的编译器Sql走十一个4gldsl,..SQL解析器基本上走十一个编译器实现2.解析sql的基本的流程,词法分析,而后进行语法分析,语义分析,...
  • 在基于Java的软件系统的构建过程中,开发人员经常会遇到词法解析、语法解析等问题,比如:在报表系统的中一般需要支持单元格计算公式(类似于Excel的公式),在某些系统的数据转换过程要实现自定义的转换规则脚本。...
  • 初级java笔试题nand2tetris 从第一性原理构建计算机; 从与非门开始,一直到构建可以玩俄罗斯方块的通用计算机。 硬件 该部分项目已完成。...Lex 和 Yacc 这样的工具来简化这个过程。 操作系统 我计划为通用计算机编
  • 需要在项目中引入:IKAnalyzer.cfg.xmlIKAnalyzer2012.jarlucene-core-3.6.0.jarstopword.dic什么都不用改示例代码如下(使用IK ...import java.io.IOException;import java.io.StringReader;import org.apache...
  • Matlab代码解释器请参阅有关此出色语言的更多信息。 是的,我知道您在想什么。...另外,我不能保证会不断更新该实现,但是,如果您真的想要,只要您问得好并且我有空闲时间(根据一年中的时间,这可能会很困难
  • 为了开发 Squirrel,我们分别使用了和 ,分别是 YACC 和 Lex实现。 “手工”编译 要生成编译器可执行文件,可以直接使用 flex 和 bison(以及一些 C 编译器)。 然而,推荐的方法是使用 waf(见下文)。 生成...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,572
精华内容 1,428
关键字:

java实现lex

java 订阅