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

news/2024/5/4 13:56:19/文章来源:https://blog.csdn.net/Alexabc3000/article/details/126652289

本文的源代码摘自编译器龙书《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

主要的类之间的关系图

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_4414.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ Qt / VS2019 +opencv + onnxruntime 部署语义分割模型【经验】

本机环境&#xff1a; OS:WIN11 CUDA: 11.1 CUDNN:8.0.5 显卡&#xff1a;RTX3080 16G opencv:3.3.0 onnxruntime:1.8.1 目前C 调用onnxruntime的示例主要为图像分类网络&#xff0c;与语义分割网络在后处理部分有很大不同。 pytorch模型转为onnx格式 1.1 安装onnx, 参考官网…

Tcp通信

一发一收 Client package tcpDemo;import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception {//1.创建Socke通信管道请求服务端的连接//p…

TCP连接管理机制(超级重要)

以下是这篇文章讲解的思维导图,整理完,我也脑瓜子嗡嗡的,怎么这么多,那是因为太重要了,防止面试官把你问死,那就必须去了解,加油啊~~~ 参考 : 小林coding 书籍 : TCP/IP 卷一 网站 : 计算机网络-41-60 | 阿秀的学习笔记 知乎文章 : 看到有人说&#xff0c;只看到过TCP状态位…

【单片机原理及应用】第一篇——单片机概述

个人主页 点击这里 专栏学习 点击这里 目录 内容概要 1.1单片机简介 1.2单片机的发展历史 1.3单片机的特点 1.4单片机的应用 1&#xff0e;工业检测与控制 2&#xff0e;仪器仪表 3&#xff0e;消费类电子产品 4&#xff0e;通讯 5&#xff0e;武器装备 6.各种终…

python从入门到实践:数据类型、文件处理

目录 一、数据类型 1.数字 整型与浮点型 其他数字类型 2.字符串 3.字节串 4.列表 5.元祖 6.集合 7.字典 8.可变类型与不可变类型 数字类型 字符串 列表 元祖 字典 9.数据类型总结 二、文件处理 1.文件的引入 2.文件的基本操作流程 2.1基本流程 2.2资源回…

【Java 基础】7、学习 Java 中的方法(方法的定义、可变参数、参数的传递问题、方法重载、方法签名)通过官方教程

&#x1f4b0; 写了一段时间的 Java 程序&#xff0c;SpringBoot &#x1f343;项目也做了好几个&#xff0c;但感觉自己对 Java 的了解还是特别少&#xff0c;所以决定从零&#x1f37c;开始重新学习&#xff0c;下面是学习的笔记。【学习素材&#xff1a;韩顺平老师】 &#…

docker 安装 elasticsearch

一、安装docker Docker 的安装_傲傲娇的博客-CSDN博客 二、配置es挂载文件和目录 mkdir -p /opt/elasticsearch/{config,data,plugins} chmod 777 /opt/elasticsearch/data 在config目录下创建elasticsearch.yml配置文件 cluster.name: elasticsearch-cluster # 节点名称 n…

【MC教程】iPad启动Java版mc(无需越狱)(保姆级?) Jitterbug启动iOS我的世界Java版启动器 PojavLauncher

【MC教程】iPad启动Java版mc&#xff08;无需越狱&#xff09;(保姆级?) Jitterbug启动iOS我的世界Java版启动器 PojavLauncher 文章目录【MC教程】iPad启动Java版mc&#xff08;无需越狱&#xff09;(保姆级?) Jitterbug启动iOS我的世界Java版启动器 PojavLauncher前言iSign…

springmvc实现文件上传书本管理CRUD

今天小编给大家分享文件上传&#xff0c;和对书本管理进行新增、修改、删除、查询。 效果展示 首页 新增 修改 一、书本管理CRUD 1.开发前必做的配置 1.1 导入pom.xml文件依赖 实现CRUDspringmvc的jar包 <dependency><groupId>org.springframework</groupId…

3.实现redis哨兵,模拟master故障场景

3.实现redis哨兵,模拟master故障场景 实验拓扑图 3.1 哨兵的准备实现主从复制架构 哨兵的前提是已经实现了一个redis的主从复制的运行环境,从而实现一个一主两从基于哨兵的高可用redis架构。 注意: master 的配置文件中的masterauth 和slave的都必须相同 所有主从节点的redis…

小波神经网络的基本原理,小波神经网络功能分析

小波神经网络的优势是什么&#xff1f;谢谢 小波神经网络相比于前向的神经网络,它有明显的优点:首先小波神经网络的基元和整个结构是依据小波分析理论确定的,可以避免BP神经网络等结构设计上的盲目性;其次小波神经网络有更强的学习能力,精度更高。 总的而言&#xff0c;对同样…

数据结构初步(一)- 时间与空间复杂度

目录前言1. 数据结构与算法1.1 数据结构是啥1.2 算法是啥2. 算法效率2.1 如何衡量一个算法的效率2.2 算法的复杂度3. 时间复杂度3.1 概念3.2 大O的渐进表示法3.3 例子分析计算Func2的时间复杂度计算Func3的时间复杂度计算Func4的时间复杂度计算strchr的时间复杂度计算冒泡排序的…

端口号被占用解决办法(超详细)

文章目录问题描述java.net.BindException: Address already in use: JVM_BindWeb server failed to start. Port 8899 was already in use.解决方案问题描述 java.net.BindException: Address already in use: JVM_Bind Web server failed to start. Port 8899 was already in…

极几何,本质矩阵,基础矩阵,单应矩阵

什么是三角化&#xff1f; 三角化就是下图的红字部分&#xff1a; 什么是极几何&#xff1f; 极几何描述了同一场景或者物体在两个视点图像间的对应关系。 下图中的O1和O2分别是两个相机的光心&#xff0c;即摄像机坐标系的原点。由下图可知给定了一个三维空间下的P点&…

07-Linux基本权限

1. 权限基本概述 1.1 什么是权限&#xff1f; 权限: 操作系统对用户能够执行的功能所设立的限制, 主要用于约束用户能对系统所做的操作, 以及内容访问的范围, 或者说, 权限是指某个特定的用户具有特定的系统资源使用权力.1.2 为什么要有权限&#xff1f; 因为系统中不可能只…

最详解消息队列以及RabbbitMQ之HelloWorld

1、消息队列 1、MQ的相关概念 1、什么是MQ MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递消息。 在互联…

webpack中的插件

1.webpack插件的作用通过安装和配置第三方插件,可以拓展webpack的能力,从而让webpack用起来更方便。最常用的webpack插件如下有两个:webpack-dev-server 类似于node.js阶段用到的nodemon工具 每当修改了源代码,webpack会自动进行项目的打包和构建html-webpack-pluginwebpac…

(分布式缓存)Redis哨兵

对应的教程视频&#xff1a; 高级篇Day3-03-Redis哨兵_哔哩哔哩_bilibili 目录&#xff1a; 哨兵的作用和原理搭建哨兵集群RedisTemplate的哨兵模式 一、哨兵的作用和原理 二、搭建哨兵集群 1.集群结构 这里我们搭建一个三节点形成的Sentinel集群&#xff0c;来监管之前的Re…

C++版本的OpenCV 5.x编译生成opencv-python==5.x(GPU版本)接口并进行调用

实现文章连接&#xff1a;强力推荐】基于Nvidia-Docker-Linux(Ubuntu18.04)平台&#xff1a;新版OpenCV5.x(C)联合CUDA11.1(GPU)完美配置视觉算法开发环境 目录1、关于有粉丝私信问我怎么调用的问题2、opencv5.x&#xff08;GPU&#xff09;测试成功opencv-python5.x测试代码Op…

黑马C++ 02 核心6 —— 类和对象_继承(重难点)

文章目录1.1 继承基本语法普通实现(重复率高)继承实现(减少重复代码)1.2 继承方式公共继承保护继承私有继承1.3 继承中的对象模型1.4 继承中构造与析构顺序1.5 继承同名成员处理方法同名成员属性同名成员函数1.6 继承同名静态成员处理方式1.6.1 同名静态成员属性通过对象访问通…