我的第一个编译器之词法分析器

用Java写java的编译器和jvm

为什么用java,java的结构最便于理解,其丰富的设计模式能使编译器的结构十分鲜明

一个编译器的前端模型

源代码–词法分析器-(词法单元)-语法分析器-(语法分析树)-中间代码生成器–三地址代码

再加上一个符号表连接所有的结构

文法定义

一个上下文无关方法由四个元素组成
1.一个终结符号集合,也就是“词法单元”终结符号是该文法定义的语言的基本符号的集合
2.一个非终结符号集合,“语法变量”每个非终结符号表示一个终结符号串的集合
3.一个产生式集合,其中每个产生式包括 一个称为产生式左头或左部的非终结符号一个箭头,和一个称为产生式体或右部的由终结符号及非终结符号组成的序列。
4.指定一个非终结符号的开始符号

词法单元由两部分组成:名字和属性值。

语法分析树

1.根结点的标号为文法的开始符号
2.每个叶子结点的标号为一个终结符号或ε
3.每个内部结点的标号为一个非终结符号
4.如果非终结符号A是某个内部结点的符号,并且它的子结点的标号从左至右分别为X1,x2,x3..,那么必然存在产生式A→X1,X2..Xn,其中X1,X2,..Xn既可以是终结符号,也可以是非终结符号,作为一种特殊情况 ,如果A→ε是一个产生式,那么一个标号为A的结点可以只有 一个标号为ε的子结点。

那么基本概念就说完了,直接上代码,因为代码比较直观

词法分析

先说一个Code类,为什么有它,我是为了更好的进行测试。同时以后也可以直接把代码赋值给它,只要可以做到一个一个的读入字符就可以,同学们可以另想办法。

public class Code {
    public static String content="int a=9;";
    private static int index=0;
    public static char read(){
        return content.charAt(index++);
    }

}

剔除空白和注释

for (;; peek = (char) Code.read()) {
            if (peek == ' ' || peek == '\t')
                continue;
            else if (peek == '\n')
                line++;
            else
                break;
        }

预读

例如,我们需要在1后面预读一个字符来区分1和10,t预读一个来区分 t和true,当然像*这种是不需要预读的

常量

if (Character.isDigit(peek)) {
            int v = 0;
            do {
                v = 10 * v + Character.digit(peek, 10);
                peek = (char) Code.read();
            } while (Character.isDigit(peek));
            return new Num(v);
        }

我们在输入 1+2+3时就会转成序列

<num,1><+><num,2><+><num,3>

+就是终结符号,没有属性,所以它的元组就是<+>

识别关键字和标识符

for do if
如果 输入
a=a+b
终结符号 就是id=id+id

  <id,"a"><+><id,"a"><+><id,"b">

关键字是不能用于标识符的,所以我们要识别关键字和标识符
这就用到了一个符号表,我们用一个hashtable来存储关键字

private Hashtable words = new Hashtable();

    @SuppressWarnings({ "unchecked" })
    private void reserve(Word t) {
        words.put(t.lexeme, t);
    }

    public Lexer() {
        reserve(new Word(Tag.TRUE, "true"));
        reserve(new Word(Tag.FALSE, "false"));
    }
    if (Character.isLetter(peek)) {
            StringBuffer b = new StringBuffer();
            do {
                b.append(peek);
                peek = (char) Code.read();
            } while (Character.isLetterOrDigit(peek));
            String s = b.toString();
            Word w = (Word) words.get(s);
            if (w != null)
                return w;
            w = new Word(Tag.ID, s);
            words.put(s, w);
            return w;
        }

词法分析器

package com.bigbear.lexer;

public class Tag {
    public final static int NUM=256,ID=257,TRUE=258,FALSE=259;

}
package com.bigbear.lexer;

public class Token {
    public final int tag;
    public Token(int tag) {
        this.tag = tag;
    }
}
package com.bigbear.lexer;

public class Num extends Token {
    public final int value;
    public Num(int v) {
        // TODO Auto-generated constructor stub
        super(Tag.NUM);
        this.value=v;
    }

}
package com.bigbear.lexer;

public class Word extends Token {
    public final String lexeme;
    public Word(int t,String s) {
        super(t);
        this.lexeme=new String(s);
    }
}
package com.bigbear.lexer;

import java.io.IOException;
import java.util.Hashtable;

import com.bigbear.main.Code;

/**
 * @author winney 词法分析器
 *
 */
public class Lexer {
    public int line = 1;
    private char peek = ' ';
    @SuppressWarnings("rawtypes")
    private Hashtable words = new Hashtable();

    @SuppressWarnings({ "unchecked" })
    private void reserve(Word t) {
        words.put(t.lexeme, t);
    }

    public Lexer() {
        reserve(new Word(Tag.TRUE, "true"));
        reserve(new Word(Tag.FALSE, "false"));
    }

    @SuppressWarnings("unchecked")
    public Token scan() throws IOException {
        for (;; peek = (char) Code.read()) {
            if (peek == ' ' || peek == '\t')
                continue;
            else if (peek == '\n')
                line++;
            else
                break;
        }
        if (Character.isDigit(peek)) {
            int v = 0;
            do {
                v = 10 * v + Character.digit(peek, 10);
                peek = (char) Code.read();
            } while (Character.isDigit(peek));
            return new Num(v);
        }
        if (Character.isLetter(peek)) {
            StringBuffer b = new StringBuffer();
            do {
                b.append(peek);
                peek = (char) Code.read();
            } while (Character.isLetterOrDigit(peek));
            String s = b.toString();
            Word w = (Word) words.get(s);
            if (w != null)
                return w;
            w = new Word(Tag.ID, s);
            words.put(s, w);
            return w;
        }
        Token t = new Token(peek);
        peek = ' ';
        return t;
    }

    public static void main(String[] args) {
        try {
            Lexer lx = new Lexer();
            for (int i = 0; i <5; i++) {
                System.out.println(lx.scan().tag);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值