如何自己動手設計組譯器

程式作品

C 語言

Java

C#

JavaScript

常用函數

文字處理

遊戲程式

衛星定位

系統程式

資料結構

網路程式

自然語言

人工智慧

機率統計

資訊安全

等待完成

訊息

相關網站

參考文獻

最新修改

簡體版

English

[フレーム]

程式專案下載:SicAssembler.zip

簡介

組譯器 (Assembler) 是用來將組合語言轉換成機器碼的程式,這是系統程式的一個重要主題,在本文中,我們將設計出 Beck 系統程式經典教科書中的 SIC 機器之組譯器,以下是一個簡單的 SIC 組合語言範例。

.-------------- SUM.sic -----------------------
SUMP START 0
LOOP LDA I . i++
 ADD ONE
 STA I
 ADD SUM . sum += i
 STA SUM
 LDA I
 COMP N . if (i < N) goto LOOP
 JLT LOOP 
 LDA SUM
 RSUB
I WORD 0
SUM WORD 0
N WORD 10
ONE WORD 1
END SUMP

實作

我們使用 C# 實作出 SIC 組合語言的組譯器,其程式原始碼如下所示。

// 共有兩個檔案
// 程式檔 : SicAssembler.cs
// 測試檔 : SUM.sic
// ------------------------------ SicAssembler.cs ------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic;
namespace SICAssembler
{
 public class SIC
 {
 static void Main(string[] args)
 {
 SicAssembler asm = new SicAssembler();
 asm.parse(args[0]);
 asm.pass2();
 SicMemory memory = new SicMemory();
 SicLoader.load(asm.codes, memory);
 SicVirtualMachine vm = new SicVirtualMachine(memory, 0);
 vm.run();
 }
 }
 public class SicVirtualMachine
 {
 public static OpTable opTable = new OpTable();
 SicMemory mem;
 int A = 0, X = 0, L = 0, SW = 0, PC = 0;
 public SicVirtualMachine(SicMemory pMemory, int pCounter) {
 mem = pMemory;
 PC = pCounter;
 }
 public void dump()
 {
 Debug.log("A=" + A + " X=" + X + " L=" + L + " SW=" + SW + " PC=" + PC);
 }
 public void run() {
 while (runCode())
 {
 }
 dump();
 }
 public int compare(int a, int b)
 {
 if (a > b) return 1;
 else if (a < b) return -1;
 else return 0;
 }
 public bool runCode()
 {
 byte op = mem.memory[PC];
 byte a1 = mem.memory[PC + 1];
 byte a2 = mem.memory[PC + 2];
 int m = ((a1 & 0x7F) << 8) + a2;
 int word = mem.getWord(m);
 String opStr = String.Format("{0:X2}", op);
 Debug.log(opTable.codeToOp[opStr]+"\tmem("+String.Format("{0:X2}", m)+")\t= "+word);
 switch (op) {
 case 0x18: // ADD m
 A += word;
 break;
 case 0x40: // AND m
 A &= word;
 break;
 case 0x28: // COMP m
 SW = compare(A, word);
 break;
 case 0x24: // DIV m
 A /= word;
 break;
 case 0x3C: // J m
 PC = m;
 break;
 case 0x30: // JEQ m
 if (SW == 0) PC = m;
 break;
 case 0x34: // JGT m
 if (SW > 0) PC = m;
 break;
 case 0x38: // JLT m
 if (SW < 0) PC = m;
 break;
 case 0x48: // JSUB m
 L = PC;
 PC = m;
 break;
 case 0x00: // LDA m
 A = word;
 break;
 case 0x50: // LDCH m
 A = (A & 0xFF0) | mem.memory[m];
 break;
 case 0x04: // LDX m
 X = word;
 break;
 case 0x20: // MUL m
 A *= word;
 break;
 case 0x44: // OR m
 A |= word;
 break;
// case 0xD8: // RD m
 case 0x4C: // RSUB
 if (L == 0) return false;
 PC = L;
 break;
 case 0x0C: // STA m
 mem.setWord(A, m);
 break;
 case 0x54: // STCH m
 mem.memory[m] = (byte)A;
 break;
 case 0x10: // STX m
 mem.setWord(X, m);
 break;
 case 0x1C: // SUB m
 A -= word;
 break;
// case 0xB0: // SVC x
// case 0xE0: // TD m
// break;
 case 0x2C: // TIX m
 X++;
 SW = compare(X, word);
 break;
// case 0xDC: // WD m
// break;
 default:
 Debug.log(String.Format("Error : op={0:X2} not found !", op));
 break;
 }
 PC += 3;
 return true;
 }
 }
 public class SicLoader
 {
 public static void load(CodeList codes, SicMemory m)
 {
 foreach (Code code in codes) {
 for (int i = 0; i < code.objCode.Length; i+=2)
 {
 String hex = code.objCode;
 int offset = code.offset + i/2;
 byte b = Byte.Parse(hex.Substring(i, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
 m.memory[offset] = b;
 Debug.log(String.Format("{0:X2}:{1:X2}", offset, b));
 }
 }
 }
 }
 public class SicMemory
 {
 public byte[] memory = new byte[32768];
 public SicMemory() {
 for (int i = 0; i < memory.Length; i++)
 memory[i] = 0;
 }
 public void setWord(int word, int offset)
 {
 memory[offset] = (byte)(word >> 16);
 memory[offset + 1] = (byte)(word >> 8);
 memory[offset + 2] = (byte)(word);
 }
 public int getWord(int offset) 
 { 
 return memory[offset] << 16 | memory[offset + 1] << 8 | memory[offset + 2]; 
 }
 }
 public class SicAssembler
 {
 public static OpTable opTable = new OpTable();
 public CodeList codes = new CodeList();
 public SymbolTable symbolTable = new SymbolTable();
 public void parse(String pFileName)
 {
 Debug.log("======================= PARSE ================================");
 String text = IO.fileToText(pFileName);
 text = text.Replace('\r', ' ');
 String[] lines = text.Split('\n');
 int offset = 0;
 for (int i = 0; i < lines.Length; i++)
 {
 String line = lines[i];
 if (line.Trim().Length == 0) continue;
 if (line.StartsWith(".")) continue;
 Code code = new Code(line, opTable);
 code.lineNumber = i;
 if (code.offset >= 0)
 offset = code.offset;
 else
 code.offset = offset;
 Debug.log(code.ToString());
 if (code.label.Length > 0)
 symbolTable.Add(code.label, code);
 codes.Add(code);
 offset = offset + code.codeSize;
 }
 }
 public void pass2()
 {
 Debug.log("======================= PASS2 ================================");
 for (int i = 0; i < codes.Count; i++)
 {
 Code code = codes[i];
 if (!code.isPseudo)
 {
 if (code.arg.Length == 0)
 code.objCode += "0000";
 else
 {
 if (symbolTable.ContainsKey(code.arg))
 {
 int argCode = symbolTable[code.arg].offset;
 if (code.x == 'X')
 argCode += 0x8000;
 code.objCode += String.Format("{0:X4}", argCode);
 }
 else Debug.error("ARG " + code.arg + " not found !");
 }
 }
 Debug.log(code.ToString());
 }
 }
 }
 public class OpTable {
 public Dictionary<String, String> opToCode = new Dictionary<String, String>();
 public Dictionary<String, String> codeToOp = new Dictionary<String, String>();
 public static String opCodes = "ADD=18,ADDF=58,ADDR=90,AND=40,CLEAR=B4,COMP=28,COMPF=88,DIV=24,DIVF=64,DIVR=9C,FIX=C4," +
 "FLOAT=C0,HIO=F4,J=3C,JEQ=30,JGT=34,JLT=38,JSUB=48,LDA=00,LDB=68,LDCH=50,LDF=70,LDL=08," +
 "LDS=6C,LDT=74,LDX=04,LPS=D0,MUL=20,MULF=60,MULR=98,NORM=C8,OR=44,RD=D8,RMO=AC,RSUB=4C," +
 "SHIFTL=A4,SHIFTR=A8,SIO=F0,SSK=EC,STA=0C,STB=78,STCH=54,STF=80,STI=D4,STL=14,STS=7C,STSW=E8," +
 "STT=84,STX=10,SUB=1C,SUBF=5C,SUBR=94,SVC=B0,TD=E0,TIO=F8,TIX=2C,TIXR=B8,WD=DC," +
 "RESB=,RESW=,BYTE=,WORD=,START=,END=";
 public OpTable() {
 Debug.log("======================= OP TABLE ================================");
 String[] records = opCodes.Split(',');
 for (int i = 0; i < records.Length; i++)
 {
 String[] tokens = records[i].Split('=');
 opToCode.Add(tokens[0], tokens[1]);
 if (tokens.Length > 1 && tokens[1].Length>0)
 codeToOp.Add(tokens[1], tokens[0]);
 Debug.log(tokens[0] + "\t" + tokens[1]);
 }
 }
 }
 public class SymbolTable : Dictionary<String, Code> { }
 public class CodeList : List<Code> { }
 public class Code
 {
 public static String PSEUDO_OP = ",RESB,RESW,BYTE,WORD,START,END,";
 public String label = "", op = "", arg = "";
 public char x = ' ';
 public String objCode = null;
 public int offset = -1;
 public int codeSize = 0;
 public int lineNumber = 0;
 public bool isPseudo;
 public Code(String line, OpTable opTable)
 {
 String[] tokens = line.Split('\t');
 int argIdx;
 if (opTable.opToCode.ContainsKey(tokens[0]))
 {
 op = tokens[0].Trim();
 argIdx = 1;
 }
 else
 {
 label = tokens[0].Trim();
 op = tokens[1].Trim();
 argIdx = 2;
 }
 if (argIdx < tokens.Length)
 {
 String argStr = tokens[argIdx];
 String[] args = argStr.Split(',');
 arg = args[0].Trim();
 if (args.Length > 1)
 if (args[1].Trim().Equals("X"))
 x = 'X';
 }
 objCode = opTable.opToCode[op];
 if (objCode == null) Debug.error("op:" + op + " not found!");
 if (op.Equals("BYTE")) 
 {
 if (arg.StartsWith("C'")) // EOF BYTE C'EOF'
 {
 String str = arg.Substring(2, arg.Length - 3);
 codeSize = str.Length;
 objCode = "";
 for (int si = 0; si < str.Length; si++)
 {
 char ch = str[si];
 int chInt = ch;
 objCode += String.Format("{0:x2}", (uint) System.Convert.ToUInt32(chInt.ToString()));
 }
 objCode = objCode.ToUpper();
 }
 else if (arg.StartsWith("X'")) // OUTPUT BYTE X'05'
 {
 String str = arg.Substring(2, arg.Length - 3);
 objCode = str;
 codeSize = str.Length / 2;
 }
 else // THREE BYTE 3
 codeSize = 1; 
 }
 else if (op.Equals("WORD")) // FIVE WORD 5
 {
 codeSize = 3;
 objCode = String.Format("{0:X6}", Int32.Parse(arg));
 }
 else if (op.Equals("RESB")) // BUFFER RESB 1024
 codeSize = Int32.Parse(arg) * 1;
 else if (op.Equals("RESW")) // LENGTH RESW 1
 codeSize = Int32.Parse(arg) * 3;
 else if (op.Equals("START")) // COPY START 1000
 offset = Int32.Parse(arg, System.Globalization.NumberStyles.AllowHexSpecifier);
 else if (op.Equals("END"))
 codeSize = 0;
 else
 codeSize = 3; // SIC 中一個指令佔 3 byte
 isPseudo = (PSEUDO_OP.IndexOf(","+op+",") >= 0);
 }
 public override String ToString()
 {
 return lineNumber + "\t" + String.Format("{0:X}", offset) + "\t" + label + "\t" + op + "\t" + arg + "\t" + x+"\t"+objCode;
 }
 }
 public class IO
 {
 // 讀取文字檔,以字串形式傳回。
 public static String fileToText(String filePath)
 {
 StreamReader file = new StreamReader(filePath);
 String text = file.ReadToEnd();
 file.Close();
 return text;
 }
 }
 class Debug
 {
 public static void error(String msg)
 {
 Debug.log(msg);
 throw new Exception(msg);
 }
 public static void log(String msg)
 {
 Console.WriteLine(msg);
 }
 }
}

Facebook

[フレーム]

Facebook

[フレーム]

Wikidot

Post preview:

(will not be published)


本網頁的作者、授權與引用方式

作者
陳鍾誠,於金門大學資訊工程系,電子郵件:wt.ude.uqn|ccc#wt.ude.uqn|ccc,網站:http://ccckmit.wikidot.com
授權
本文採用創作共用 (Creative Common) 3.0 版的 姓名標示─非商業性─相同方式分享 授權條款,歡迎轉載或修改使用,但若做為商業使用時必須取得授權,引用本文時請參考下列格式。
中文版 (APA格式)
陳鍾誠 (28 Sep 2009 01:51),(網頁標題) 如何自己動手設計組譯器,(網站標題) 陳鍾誠的網站,取自 http://ccckmit.wikidot.com/code:assembler ,網頁修改第 12 版。
英文版 (APA格式)
Chung-Chen Chen (28 Sep 2009 01:51), Retrieved from http://ccckmit.wikidot.com/code:assembler , Page Revision 12.
page revision: 12, last edited: 19 Oct 2010 09:09
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License
Click here to edit contents of this page.
Click here to toggle editing of individual sections of the page (if possible). Watch headings for an "edit" link when available.
Append content without editing the whole page source.
Check out how this page has evolved in the past.
If you want to discuss contents of this page - this is the easiest way to do it.
View and manage file attachments for this page.
A few useful tools to manage this Site.
Change the name (also URL address, possibly the category) of the page.
View wiki source for this page without editing.
View/set parent page (used for creating breadcrumbs and structured layout).
Notify administrators if there is objectionable content in this page.
Something does not work as expected? Find out what you can do.
General Wikidot.com documentation and help section.
Wikidot.com Terms of Service - what you can, what you should not etc.
Wikidot.com Privacy Policy.

AltStyle によって変換されたページ (->オリジナル) /