Java实现的一个编译器源代码(Win11)

本文的源代码摘自编译器龙书《Compilers : principles, techniques, and tools》第二版的附录A“一个完整的前端”(A Complete Front End)。

上述书中的编译器是在Unix系统中,主体代码与书中相同,只是对字符串处理不同;本例中使用Java类将文本文件内容读取到一个字符串中,然后进行语法分析和代码生成。

源语言的产生式

 

 

 

Main.java (主程序)

package main ; // File Main.java

import lexer.*; import parser.*;

import java.io.File;

import java.io.IOException;

import java.util.Scanner;

public class Main

{

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

if(args.length == 0){

System.out.println("need a file name.");

return;

}

 String fileName = args[0];

 Scanner sc = new Scanner(new File(fileName));

 String input;

 StringBuffer sb = new StringBuffer();

 while (sc.hasNextLine()) {

 input = sc.nextLine();

 sb.append(input+'\n');

 }

 //System.out.println("Contents of the file are: "+sb.toString());

System.out.println("create a Lexer");

Lexer lex = new Lexer() ;

lex.setCodes(sb.toString()); // 设置源代码字符串.

System.out.println("create a Parser");

Parser parse = new Parser(lex) ;

System.out.println("run parse.program()\n");

parse.program() ;

System.out.write('\n');

}

}

词法分析器包

词法分析器以源代码作为输入,逐字符(一个字符一个字符地)分析源程序,将源程序转换为记号(token)流(也可成为记号集合、或者记号序列),每一个都应该属于一个类,有一个值(大部分记号都有值,也有部分记号没有值,比如加法或减法等运算符就没有值)。

Tag.java标签类

package lexer ; // File Tag.java

public class Tag {

public final static int

AND = 256 , BASIC = 257, BREAK = 258, DO = 259 , ELSE = 260 ,

EQ = 261 , FALSE = 262, GE = 263 , ID = 264 , IF = 265 ,

INDEX = 266,LE = 267,  MINUS = 268 , NE = 269 , NUM = 270 ,

OR = 271,   REAL = 272,  TEMP = 273 , TRUE = 274 , WHILE = 275 ;

}

Token.java记号类

package lexer ; // File Token.java

public class Token{

public final int tag; // 记号所属类别的编号.

public Token(int t) { tag = t; }

public String toString() {return "" + ( char) tag;}

}

Num.java数字记号类

package lexer; // File Num.java

public class Num extends Token {

public final int value; // 数字记号的值(即token的值).

public Num(int v) { super(Tag.NUM); value = v; }

public String toString() { return "" + value; }

}

Word.java单词记号类

package lexer; // File Word.java

public class Word extends Token {

public String lexeme = ""; // 词素

// s相当于token(记号)的值,tag相当于token所属的类别的编号.

public Word(String s, int tag) { super(tag); lexeme = s; }

public String toString() { return lexeme; }

public static final Word

and = new Word( "&&", Tag.AND ), or = new Word( "||", Tag.OR ),

eq = new Word( "==" , Tag.EQ ),  ne = new Word ( "!=" , Tag.NE ),

le = new Word ( "<=" , Tag.LE ), ge = new Word( ">=" , Tag.GE ),

minus = new Word ( "minus", Tag.MINUS ),

True = new Word ( "true" , Tag.TRUE ),

False = new Word( "false" , Tag.FALSE ),

temp = new Word( "t" , Tag.TEMP );

}

Real.java实数记号类

package lexer ; // File Real.java

public class Real extends Token {

public final float value;

public Real(float v) { super (Tag.REAL); value = v; }

public String toString(){ return "" + value;}

}

Lexer.java词法分析器类

package lexer; // File Lexer.java

import java.io.*;

import java.nio.file.Files;

import java.util.*;

import symbols.*;

public class Lexer {

public static int line = 1;

char peek = ' ';

// (单词)记号表(词法分析器的输出)

Hashtable<String, Word> words = new Hashtable<String, Word>();

// 源代码.

String codes;

int codeIndex = 0;

// 设置源代码字节

public void setCodes(String s){

codes = s+'#'; // 使用‘#’替代文件结束符.

codeIndex = 0;

}

// 向单词记号表中添加一个单词记号. 以单词的词素作为哈希表的键

void reserve (Word w) {words.put(w.lexeme, w) ; }

public Lexer() {

// 初始化时向记号表中添加若干关键字

reserve ( new Word("if" , Tag.IF));

reserve ( new Word("else" , Tag.ELSE));

reserve ( new Word( "while", Tag.WHILE) ) ;

reserve ( new Word ("do", Tag.DO));

reserve ( new Word ("break" , Tag.BREAK));

reserve ( Word.True); reserve ( Word.False ) ;

reserve ( Type.Int);  reserve ( Type.Char);

reserve ( Type.Bool ) ; reserve ( Type.Float);

}

//void readch() throws IOException {peek = (char)System.in.read(); }

void readch() throws IOException {

peek = codes.charAt(codeIndex++);

//System.out.println(codeIndex-1 + ": peek is " + peek);

}

boolean readch( char c) throws IOException {

readch();

if ( peek != c ) return false ;

peek = ' ' ;

return true ;

}

public Token scan() throws IOException {

for( ; ; readch() ){// 处理空白字符

if ( peek == ' ' || peek == '\t' ) continue;

else if ( peek == '\n' ) line = line + 1;

else break;

}

switch ( peek ){// 处理双字符运算符

case '&' :

if (readch('&')) return Word.and ; else return new Token ('&');

case '|':

if (readch('|')) return Word.or;   else return new Token ('|');

case '=' :

if (readch('=')) return Word.eq;   else return new Token ('=');

case '!' :

if (readch('=')) return Word.ne;   else return new Token ('!');

case '<' :

if (readch('=')) return Word.le;   else return new Token ('<');

case '>' :

if (readch('=')) return Word.ge;   else return new Token ('>');

}

if (Character.isDigit(peek)){ // 处理数字

int v = 0;

do{

v = 10*v + Character.digit(peek , 10); readch( );

}while( Character.isDigit(peek));

if ( peek != '.' ) return new Num(v);

float x = v; float d = 10;

for( ; ; ) {

readch();

if ( !Character.isDigit(peek) ) break;

x = x + Character.digit(peek , 10)/d; d = d*10;

}

return new Real(x) ;

}

if(Character.isLetter(peek)){// 处理标识符符(单词)

StringBuffer b = new StringBuffer( );

do{

b.append(peek); readch();

}while ( Character.isLetterOrDigit(peek));

String s = b.toString();

Word w = (Word)words.get(s);// 在哈希表(单词记号表)中查找s对应的单词

if ( w != null ) return w; // 若找到则返回w,否则添加新的单词.

w = new Word(s , Tag.ID) ;

words.put(s, w);

return w;

}

// 剩余的字符作为标记返回.

Token tok = new Token(peek) ; peek = ' ';

return tok;

}

}

将原书中的

Hashtable words = new Hashtable ( ) ;

改为

Hashtable<String, Word> words = new Hashtable<String, Word>();

目的是为了消除Java编译器的警告信息:“警告: [unchecked] 对作为原始类型Hashtable的成员的put(K,V)的调用未经过检查”。

Symbol Tables and Types(符号表与类型包)

Env.java(环境类)

package symbols ; // File Env.java

import java.util.*; import lexer.*; import inter.*;

public class Env {

private Hashtable<Token, Id> table;

protected Env prev;

public Env(Env n) {table = new Hashtable<Token, Id>(); prev = n;}

public void put(Token w, Id i) { table.put(w, i); }

public Id get(Token w){

for(Env e = this ; e != null ; e = e.prev ) {

Id found = (Id)(e.table.get (w));

if ( found != null ) return found;

}

return null ;

}

}

Type.java类型类

package symbols ; // File Type.java

import lexer.*;

 public class Type extends Word{ // 类型类是单词记号类的子类

public int width = 0; // width is used for storage allocation. 类型所占字节数

public Type(String s, int tag , int w) { super(s, tag) ; width = w; }

public static final Type

Int = new Type ( "int", Tag.BASIC , 4 ), // 基本类型

Float = new Type ( "float", Tag.BASIC , 8 ) ,

Char = new Type ( "char" , Tag.BASIC , 1 ),

Bool = new Type ( "bool" , Tag.BASIC , 1 );

public static boolean numeric(Type p){// p是否是数字类型的实例

if(p == Type.Char || p == Type.Int || p == Type.Float) return true;

else return false ;

}

public static Type max(Type p1, Type p2 ){// 占用空间的最大值

if ( !numeric(p1) || !numeric (p2) ) return null;

else if ( p1 == Type.Float || p2 == Type.Float ) return Type.Float;

else if ( p1 == Type.Int || p2 == Type.Int ) return Type.Int;

else return Type.Char ;

}

}

Array.java数组类型

package symbols ; // File Array.java

import lexer.*;

public class Array extends Type{

public Type of; // array *of* type

public int size = 1; // number of elements

public Array(int sz, Type p) {

super ( "[]", Tag.INDEX , sz*p.width) ; size = sz ; of = p;

}

public String toString(){ return "[" + size + "] " + of.toString(); }

}

Intermediate Code for Expressions表达式中间码

Node.java结点类

package inter ; // File Node.java

import lexer.*;

public class Node {

int lexline = 0;

Node() { lexline = Lexer.line; }

void error (String s) { throw new Error("near line " + lexline + ": " + s); }

static int labels = 0;

public int newlabel() { return ++labels; }

public void emitlabel(int i) { System.out.print ( "L" + i + ":" ); }

public void emit (String s) { System.out.println( "\t" + s) ; }

}

Expr.java表达式结点类

package inter ; // File Expr.java

import lexer.*; import symbols.*;

 public class Expr extends Node {

public Token op;

public Type type;

Expr(Token tok , Type p) { op = tok ; type = p; }

public Expr gen(){ return this; }

public Expr reduce() { return this; }

public void jumping(int t, int f){ emitjumps(toString(), t, f ); }

public void emitjumps(String test , int t, int f) {

if( t != 0 && f != 0 ){

emit ("if " + test + " goto L" + t ) ;

emit ("goto L" + f );

}

else if (t != 0 ) emit("if " + test + " goto L" + t ) ;

else if (f != 0 ) emit (" iffalse " + test + " goto L" + f ) ;

else ; // nothing s ince both t and f fall through

}

public String toString() { return op.toString() ; }

}

Id.java标识符结点类

package inter ; // File Id.java

import lexer.*; import symbols.*;

public class Id extends Expr {

public int offset ; // relative address (相对地址,偏移量)

public Id(Word id, Type p, int b) { super ( id, p ) ; offset = b; }

}

Op.java(运算符结点类)

package inter; // File Op.java

import lexer.*; import symbols.*;

public class Op extends Expr{

public Op(Token tok, Type p) { super (tok, p ); }

public Expr reduce(){

Expr x = gen() ;

Temp t = new Temp(type);

emit( t.toString() + " = " + x.toString() );

return t;

}

}

Arith.java

package inter ; // File Arith.java

import lexer.*; import symbols.*;

public class Arith extends Op{

public Expr expr1, expr2;

public Arith(Token tok , Expr xl, Expr x2) {

super(tok , null) ; expr1 = xl ; expr2 = x2 ;

type = Type.max (expr1.type , expr2.type);

if (type == null ) error ( "type error") ;

}

public Expr gen(){

return new Arith(op, expr1.reduce() , expr2.reduce() );

}

public String toString(){

return expr1.toString()+" "+op.toString()+" "+ expr2.toString();

}

}

Temp.java

package inter ; // File Temp.java

import lexer.*; import symbols.*;

public class Temp extends Expr {

static int count = 0 ;

int number = 0;

public Temp(Type p){ super(Word.temp, p ); number = ++count ; }

public String toString(){ return "t" + number ; }

}

Unary.java

package inter ; // File Unary.java

import lexer.*; import symbols.* ;

public class Unary extends Op{

public Expr expr;

public Unary(Token tok , Expr x) { // handles minus , for ! see Not

super(tok , null); expr = x;

type = Type.max(Type.Int, expr.type) ;

if(type == null ) error("type error") ;

}

public Expr gen() { return new Unary(op, expr.reduce()); }

public String toString(){ return op.toString() +" "+expr.toString(); }

 }

Jumping Code for Boolean Expressions布尔表达式的跳转代码

Constant.java常量

package inter ; // File Constant.java

import lexer.*; import symbols .*;

public class Constant extends Expr {

public Constant(Token tok , Type p){ super(tok , p) ; }

public Constant(int i) { super(new Num(i) , Type.Int) ; }

public static final Constant

True = new Constant(Word.True , Type.Bool) ,

False = new Constant(Word.False , Type.Bool) ;

public void jumping( int t, int f) {

if ( this == True && t != 0 ) emit ( "goto L" + t ) ;

else if ( this == False && f != 0) emit ( "goto L" + f ) ;

}

}

Logical.java逻辑表达式

package inter ; // File Logical.java

import lexer.*; import symbols.*;

public class Logical extends Expr {

public Expr expr1 , expr2 ;

Logical (Token tok, Expr x1 , Expr x2) {

super (tok , null ) ; // null type to start

expr1 = x1 ; expr2 = x2 ;

type = check (expr1.type , expr2.type ) ;

if (type == null ) error ( "type error") ;

}

public Type check(Type p1 , Type p2) {

if ( p1 == Type.Bool && p2 == Type.Bool ) return Type.Bool ;

else return null ;

}

public Expr gen() {

int f = newlabel( ) ; int a = newlabel( ) ;

Temp temp = new Temp(type);

this.jumping(0, f ) ;

emit(temp.toString() + " = true") ;

emit ("goto L" + a) ;

emitlabel(f) ; emit(temp.toString() + " = false") ;

emitlabel(a) ;

return temp ;

}

public String toString () {

return expr1.toString()+" " +op.toString()+" "+expr2.toString();

}

}

Or.java或逻辑表达式

package inter ; // File Or.java

import lexer.*; import symbols.*;

public class Or extends Logical {

public Or (Token tok , Expr x1 , Expr x2) { super(tok , x1 , x2) ; }

public void jumping( int t, int f) {

int label = t != 0 ? t : newlabel ( ) ;

expr1.jumping(label , 0 ) ;

expr2.jumping(t , f ) ;

if ( t == 0 ) emitlabel(label ) ;

}

}

And.java与逻辑表达式

package inter ; // File And.java

import lexer.*; import symbols.*;

public class And extends Logical {

public And(Token tok , Expr x1 , Expr x2) { super (tok , x1, x2) ; }

public void jumping( int t, int f){

int label = f !=0 ? f : newlabel ( ) ;

expr1.jumping(0 , label);

expr2.jumping (t,f ) ;

if ( f == 0 ) emitlabel (label) ;

}

}

Not.java非逻辑表达式

package inter ; // File Not.java

import lexer.*; import symbols.*;

public class Not extends Logical {

public Not(Token tok , Expr x2) { super (tok, x2 , x2) ; }

public void jumping( int t, int f) { expr2.jumping (f , t ) ; }

public String toString(){ return op.toString() +" "+expr2.toString() ; }

}

Rel.java关系运算表达式

package inter ; // File Rel.java

import lexer.*; import symbols.*;

public class Rel extends Logical {

public Rel(Token tok , Expr x1, Expr x2) { super(tok , x1 , x2) ; }

public Type check(Type p1 , Type p2) {

if ( p1 instanceof Array || p2 instanceof Array ) return null ;

else if ( p1 == p2 ) return Type.Bool ;

else return null;

}

public void jumping(int t, int f) {

Expr a = expr1.reduce ( ) ;

Expr b = expr2.reduce ( ) ;

String test = a.toString() + " " + op.toString() + " " + b.toString() ;

emitjumps(test , t, f ) ;

}

}

Access.java访问表达式,即运算符“[]”

package inter ; // File Access.java

import lexer.*; import symbols.*;

public class Access extends Op {

public Id array ;

public Expr index ;

public Access( Id a, Expr i, Type p) { // p is element type after

super(new Word("[]", Tag.INDEX), p ) ; // flattening the array

array = a; index = i;

}

public Expr gen() { return new Access(array, index.reduce(), type ); }

public void jumping( int t,int f) { emitjumps(reduce().toString () , t , f ) ; }

public String toString (){

return array.toString() + " [ " + index.toString() + " ] ";

}

}

Intermediate Code for Statements(语句中间码)

Stmt.java语句结点

package inter ; // File Stmt.java

public class Stmt extends Node {

public Stmt () { }

public static Stmt Null = new Stmt() ;

public void gen( int b, int a) {} // called with labels begin and after

int after = 0; // saves label after

public static Stmt Enclosing = Stmt.Null ; // used for break stmts

}

If.javaif语句结点

package inter ; // File If.java

import symbols.*;

public class If extends Stmt {

Expr expr ; Stmt stmt ;

public If (Expr x, Stmt s) {

expr = x; stmt = s;

if ( expr.type != Type.Bool ) expr.error ( "boolean required in if " ) ;

}

public void gen( int b, int a) {

int label = newlabel ( ) ; // label for the code f or stmt

expr.jumping (0, a); // fall through on true , goto a on false

emitlabel(label ); stmt.gen( label, a) ;

}

}

Else.javaelse语句结点

package inter ; // File Else.java

import symbols.*;

public class Else extends Stmt {

Expr expr ; Stmt stmt1, stmt2 ;

public Else (Expr x, Stmt s1 , Stmt s2) {

expr = x; stmt1 = s1 ; stmt2 = s2 ;

if ( expr.type != Type.Bool ) expr.error ( "boolean required in if ") ;

}

public void gen( int b, int a) {

int label1 = newlabel ( ) ; // label1 for stmt1

int label2 = newlabel() ; // label2 for stmt2

expr.jumping(0 , label2) ; // fall through to stmt 1 on true

emitlabel( label1); stmt1.gen( label1 , a) ; emit ( "goto L" + a) ;

emitlabel(label2); stmt2.gen( label2 , a) ;

}

}

While.javawhile语句结点

package inter ; // File While.java

import symbols.*;

public class While extends Stmt {

Expr expr ; Stmt stmt ;

public While () { expr = null ; stmt = null ; }

public void init (Expr x, Stmt s) {

expr = x; stmt = s;

}

public void gen ( int b, int a) {

after = a; // save label a

expr.jumping(0, a) ;

int label = newlabel ( ) ; // label for stmt

emitlabel(label) ; stmt.gen(label , b) ;

emit ( "goto L" + b) ;

}

}

Do.javado语句结点

package inter ; // File Do.java

import symbols.*;

public class Do extends Stmt {

Expr expr ; Stmt stmt ;

public Do () { expr = null ; stmt = null ; }

public void init (Stmt s, Expr x) {

expr = x; stmt = s;

if ( expr.type != Type.Bool) expr.error ("boolean required in do " ) ;

}

public void gen ( int b, int a) {

after = a;

int label = newlabel ( ) ; // label for expr

stmt.gen(b, label ) ;

emitlabel(label) ;

expr.jumping(b,0) ;

}

}

Set.java赋值语句结点

package inter ; // File Set.java

import lexer.*; import symbols.*;

public class Set extends Stmt {

public Id id ; public Expr expr ;

public Set ( Id i, Expr x) {

id = i; expr = x;

if ( check(id.type , expr.type) == null ) error ( "type error") ;

}

public Type check(Type p1 , Type p2) {

if ( Type.numeric(p1) && Type.numeric (p2) ) return p2 ;

else if ( p1 == Type.Bool && p2 == Type.Bool ) return p2 ;

else return null ;

}

public void gen( int b, int a) {

emit ( id.toString() + " = "+ expr.gen().toString() );

}

}

SetElem.java数组元素赋值语句结点

package inter ; // File SetElem.java

import lexer.*; import symbols.*;

public class SetElem extends Stmt {

public Id array ; public Expr index ; public Expr expr ;

public SetElem(Access x, Expr y) {

array = x.array ; index = x.index ; expr = y;

if ( check (x.type , expr.type) == null ) error ( "type error" );

}

public Type check(Type p1 , Type p2) {

if ( p1 instanceof Array || p2 instanceof Array ) return null ;

else if ( p1 == p2 ) return p2 ;

else if ( Type.numeric(p1) && Type.numeric(p2) ) return p2 ;

else return null ;

}

public void gen( int b, int a) {

String s1 = index.reduce( ).toString() ;

String s2 = expr.reduce( ).toString() ;

emit (array.toString() + " [ " + s1 + " ] = " + s2) ;

}

}

Seq.java语句集合结点

package inter ; // File Seq.java

public class Seq extends Stmt {

Stmt stmt1; Stmt stmt2 ;

public Seq(Stmt s1 , Stmt s2) { stmt1 = s1; stmt2 = s2 ; }

public void gen ( int b, int a) {

if ( stmt1 == Stmt.Null ) stmt2.gen(b , a) ;

else if ( stmt2 == Stmt.Null ) stmt1.gen (b , a) ;

else {

int label = newlabel( ) ;

stmt1.gen(b, label ) ;

emitlabel(label) ;

stmt2.gen(label, a) ;

}

}

}

Break.javabreak语句结点

package inter ; // File Break.java

public class Break extends Stmt {

Stmt stmt ;

public Break() {

if ( Stmt.Enclosing == null ) error ( "unenclosed break" );

stmt = Stmt.Enclosing ;

}

public void gen ( int b, int a) {

emit ( "goto L" + stmt.after) ;

}

}

Parser语法解析器

package parser ; // File Parser.java

import java.io.*; import lexer.*; import symbols.*; import inter.*;

public class Parser {

private Lexer lex ; // lexical analyzer for this parser

private Token look ; // lookahead tagen

Env top = null ; // current or top symbol table

int used = 0; // storage used for declarations

public Parser(Lexer l) throws IOException { lex = l; move() ; }

void move() throws IOException { look = lex.scan(); }

void error (String s) { throw new Error( "near line "+lex.line+": " +s ); }

void match( int t) throws IOException {

if ( look.tag == t ) move() ;

else error ( "syntax error") ;

}

public void program() throws IOException { // program -> block

Stmt s = block();

int begin = s.newlabel( ) ; int after = s.newlabel( ) ;

s.emitlabel(begin); s.gen(begin , after ) ; s.emitlabel( after ) ;

}

Stmt block() throws IOException { // block -> { decls stmts }

match('{' ); Env savedEnv = top ; top = new Env (top ) ;

decls ( ) ; Stmt s = stmts() ;

match('}' ); top = savedEnv ;

return s;

}

void decls () throws IOException {

while ( look.tag == Tag.BASIC ) { // D -> type ID ;

Type p = type() ; Token tok = look ; match(Tag.ID ) ; match( ';' );

Id id = new Id((Word)tok, p, used) ;

top.put ( tok , id );

used = used + p.width ;

}

}

Type type() throws IOException {

Type p = (Type) look ; // expect look.tag == Tag.BASIC

match (Tag.BASIC) ;

if ( look.tag != '[') return p; // T -> basic

else return dims (p) ; // return array type

}

Type dims(Type p) throws IOException {

match( '[' ) ; Token tok = look ; match (Tag.NUM) ; match(']');

if ( look.tag == '[' )

p = dims (p) ;

return new Array (((Num)tok).value, p ) ;

}

Stmt stmts() throws IOException {

if ( look.tag == '}' ) return Stmt.Null ;

else return new Seq( stmt () , stmts()) ;

}

Stmt stmt () throws IOException {

Expr x; Stmt s, s1 , s2 ;

Stmt savedStmt ; // save enclosing loop for breaks

switch ( look.tag ) {

case ';':

move();

return Stmt.Null ;

case Tag.IF:

match(Tag.IF) ; match( '('); x = bool() ; match( ')');

s1 = stmt();

if ( look.tag != Tag.ELSE) return new If(x , s1) ;

match(Tag.ELSE) ;

s2 = stmt() ;

return new Else (x , s1 , s2) ;

case Tag.WHILE :

While whilenode = new While () ;

savedStmt = Stmt.Enclosing ; Stmt.Enclosing = whilenode ;

match(Tag.WHILE) ; match( '('); x = bool() ; match( ')');

s1 = stmt() ;

whilenode.init (x , s1) ;

Stmt.Enclosing = savedStmt ; // reset Stmt.Enclosing

return whilenode ;

case Tag.DO:

Do donode = new Do() ;

savedStmt = Stmt.Enclosing ; Stmt.Enclosing = donode ;

match (Tag.DO ) ;

s1 = stmt() ;

match( Tag.WHILE) ; match ('('); x = bool() ; match ( ')'); match(';') ;

donode.init ( s1 , x ) ;

Stmt.Enclosing = savedStmt ; // reset Stmt.Enclosing

return donode ;

case Tag.BREAK :

match(Tag.BREAK) ; match ( ';') ;

return new Break() ;

case '{' :

return block();

default :

return assign() ;

}

}

Stmt assign() throws IOException {

Stmt stmt; Token t = look ;

match(Tag.ID) ;

Id id = top.get(t);

if ( id == null ) error( t.toString() + " undeclared" ) ;

if ( look.tag == '=' ) { // S -> id = E ;

move ( ) ; stmt = new Set ( id, bool ()) ;

}

else { // S -> L = E ;

Access x = offset ( id) ;

match('='); stmt = new SetElem(x , bool()) ;

}

match( ';') ;

return stmt ;

}

Expr bool() throws IOException {

Expr x = join( ) ;

while( look.tag == Tag.OR ) {

Token tok = look ; move(); x = new Or(tok , x, join() );

}

return x;

}

Expr join () throws IOException {

Expr x = equality();

while ( look.tag == Tag.AND ) {

Token tok = look ; move(); x = new And(tok, x, equality()) ;

}

return x;

}

Expr equality() throws IOException {

Expr x = rel();

while ( look.tag == Tag.EQ || look.tag == Tag.NE ) {

Token tok = look; move(); x = new Rel(tok, x, rel()) ;

}

return x;

}

Expr rel() throws IOException {

Expr x = expr();

switch ( look . tag ) {

case '<' : case Tag.LE : case Tag.GE: case '>' :

Token tok = look; move ( ) ; return new Rel (tok , x, expr()) ;

default :

return x;

}

}

Expr expr () throws IOException {

Expr x = term() ;

while ( look.tag == '+' || look. tag == '-' ) {

Token tok = look ; move() ; x = new Arith(tok , x, term()) ;

}

return x;

}

Expr term() throws IOException {

Expr x = unary() ;

while (look.tag == '*' || look.tag == '/' ) {

Token tok = look ; move() ; x = new Arith (tok , x, unary()) ;

}

return x;

}

Expr unary() throws IOException {

if ( look.tag == '-' ) {

move(); return new Unary (Word.minus , unary()) ;

}

else if ( look . tag == '!' ) {

Token tok = look ; move() ; return new Not(tok, unary()) ;

}

else return factor() ;

}

Expr factor () throws IOException {

Expr x = null ;

switch( look.tag ) {

case '(':

move() ; x = bool() ; match( ')');

return x;

case Tag.NUM :

x = new Constant ( look, Type.Int ); move() ; return x;

case Tag.REAL :

x = new Constant ( look, Type.Float ); move() ; return x;

case Tag.TRUE :

x = Constant.True ; move() ; return x;

case Tag.FALSE:

x = Constant.False ; move() ; return x;

default :

error ( "syntax error" );

return x;

case Tag.ID:

String s = look.toString() ;

Id id = top.get ( look) ;

if ( id == null ) error ( look.toString() + " undeclared" ) ;

move();

if ( look.tag != '[' ) return id;

else return offset ( id) ;

}

}

Access offset(Id a) throws IOException{ //I ->[E]|[E] I

Expr i; Expr w; Expr t1,t2; Expr loc; // inherit id

Type type = a.type;

match('['); i = bool(); match(']'); // first index, I -> [E ]

type =((Array)type).of;

w = new Constant(type.width);

t1 = new Arith(new Token('*'), i, w);

loc = t1;

while( look.tag=='['){ //multi-dimensional I->[E] i

match('['); i=bool(); match(']');

type = ((Array)type).of;

w = new Constant(type.width);

t1 = new Arith(new Token('*'), i, w) ;

t2 = new Arith(new Token('+'), loc, t1) ;

loc = t2;

}

return new Access(a,loc, type);

}

}

Creating the Front End(创建前端)

运行如下命令:

javac lexer/*.java

javac symbols/*.java

javac inter/*.java

javac parser/*.java

javac main/*.java

编译成功后,使用下面命令执行:

java main/Main test.txt

其中test.txt的内容如下:

{

int i; int j; float v; float x; float[100]  a;

while ( true ) {

do i = i+1; while ( a [i] < v) ;

do j = j -1 ; while ( a [j] > v) ;

if ( i >= j ) break;

x = a [i] ; a [i] = a [j ] ; a [j] = x;

}

}

运行结果如下图所示:

文件组织如下:

 

D:.

│  test.txt

├─inter

│      Access.class

│      Access.java

│      And.class

│      And.java

│      Arith.class

│      Arith.java

│      Break.class

│      Break.java

│      Constant.class

│      Constant.java

│      Do.class

│      Do.java

│      Else.class

│      Else.java

│      Expr.class

│      Expr.java

│      Id.class

│      Id.java

│      If.class

│      If.java

│      Logical.class

│      Logical.java

│      Node.class

│      Node.java

│      Not.class

│      Not.java

│      Op.class

│      Op.java

│      Or.class

│      Or.java

│      Rel.class

│      Rel.java

│      Seq.class

│      Seq.java

│      Set.class

│      Set.java

│      SetElem.class

│      SetElem.java

│      Stmt.class

│      Stmt.java

│      Temp.class

│      Temp.java

│      Unary.class

│      Unary.java

│      While.class

│      While.java

├─lexer

│      Lexer.class

│      Lexer.java

│      Num.class

│      Num.java

│      Real.class

│      Real.java

│      Tag.class

│      Tag.java

│      Token.class

│      Token.java

│      Word.class

│      Word.java

├─main

│      Main.class

│      Main.java

├─parser

│      Parser.class

│      Parser.java

└─symbols

        Array.class

        Array.java

        Env.class

        Env.java

        Type.class

        Type.java

主要的类之间的关系图

 

 

 

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
编写一个完整的编译器一个非常复杂的任务,需要掌握编译原理、数据结构、算法等知识。以下是一个简单的示例,用于说明编写编译器的基本流程。 1. 词法分析器(Tokenizer):从源代码中读取字符流,将其转换为标记流(Token Stream),并识别出每个标记的类型。例如,标识符、关键字、数字、运算符、界符等。 2. 语法分析器(Parser):将标记流转换为语法树(Syntax Tree),并检查其语法结构是否正确。例如,检查是否缺失分号、是否有未定义的变量、是否存在歧义等。 3. 语义分析器(Semantic Analyzer):对语法树进行语义分析,检查其语义是否正确。例如,检查类型匹配、作用域、函数调用参数正确性等。并对语法树进行变换,消除歧义。 4. 代码生成器(Code Generator):将语法树转换为目标代码。这个过程通常是将语法树转换为中间代码(Intermediate Representation),然后再将中间代码转换为目标代码。中间代码可以是抽象语法树(Abstract Syntax Tree)或三地址码(Three Address Code)。 5. 目标代码优化(Code Optimization):对目标代码进行优化,以提高代码的执行效率。例如,常量折叠、死代码消除、循环不变式外提等。 以下是一个简单的Java编译器示例: ```java public class Compiler { public static void main(String[] args) { String input = "class HelloWorld {\n" + " public static void main(String[] args) {\n" + " System.out.println(\"Hello, World!\");\n" + " }\n" + "}\n"; Tokenizer tokenizer = new Tokenizer(input); Parser parser = new Parser(tokenizer); AST ast = parser.parse(); SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); semanticAnalyzer.analyze(ast); CodeGenerator codeGenerator = new CodeGenerator(); String code = codeGenerator.generate(ast); System.out.println(code); } } ``` 这个编译器的功能很简单,只能编译一个输出"Hello, World!"的Java程序。但是,它演示了一个编译器的基本流程,包括词法分析、语法分析、语义分析和代码生成。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alexabc3000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值