Một trình biên dịch, giống như bất kỳ trình biên dịch nào khác, được viết tốt nhất như là một trình phân tích từ vựng đưa vào bộ xử lý ngữ pháp ngôn ngữ.
Ngôn ngữ lắp ráp thường dễ dàng hơn các ngôn ngữ được biên dịch thông thường vì bạn không cần phải lo lắng về các cấu trúc vượt qua ranh giới đường và định dạng thường được sửa.
tôi đã viết một lắp ráp cho một (hư cấu) CPU khoảng hai năm trước cho các mục đích giáo dục và về cơ bản điều trị mỗi dòng như:
- nhãn bắt buộc (ví dụ,
:loop
). Hoạt động
- (ví dụ:
mov
).
- toán hạng (ví dụ:
ax,$1
).
Cách dễ nhất để làm điều đó là đảm bảo rằng mã thông báo có thể dễ dàng phân biệt được.
Đó là lý do tại sao tôi thực hiện quy tắc mà nhãn phải bắt đầu bằng :
- nó đã làm cho việc phân tích dòng dễ dàng hơn rất nhiều. Quá trình xử lý một dòng là:
- xoá nhận xét (đầu tiên
;
ngoài chuỗi để kết thúc dòng).
- nhãn trích xuất nếu có.
- từ đầu tiên sau đó là hoạt động.
- nghỉ ngơi là các toán hạng.
Bạn có thể dễ dàng nhấn mạnh rằng các toán hạng khác nhau cũng có các điểm đánh dấu đặc biệt để làm cho cuộc sống của bạn dễ dàng hơn. Tất cả điều này là giả sử bạn có quyền kiểm soát định dạng đầu vào. Nếu bạn được yêu cầu sử dụng định dạng Intel hoặc AT & T, điều này sẽ khó khăn hơn một chút.
Con đường tôi tiếp cận nó là rằng có một đơn giản chức năng cho mỗi hoạt động đó đã gọi (ví dụ, doJmp
, doCall
, doRet
) và chức năng quyết định những gì được cho phép trong các toán hạng.Ví dụ: doCall
chỉ cho phép một số hoặc nhãn, doRet
không cho phép gì.
Ví dụ, đây là một đoạn mã từ encInstr
chức năng:
private static MultiRet encInstr(
boolean ignoreVars,
String opcode,
String operands)
{
if (opcode.length() == 0) return hlprNone(ignoreVars);
if (opcode.equals("defb")) return hlprByte(ignoreVars,operands);
if (opcode.equals("defbr")) return hlprByteR(ignoreVars,operands);
if (opcode.equals("defs")) return hlprString(ignoreVars,operands);
if (opcode.equals("defw")) return hlprWord(ignoreVars,operands);
if (opcode.equals("defwr")) return hlprWordR(ignoreVars,operands);
if (opcode.equals("equ")) return hlprNone(ignoreVars);
if (opcode.equals("org")) return hlprNone(ignoreVars);
if (opcode.equals("adc")) return hlprTwoReg(ignoreVars,0x0a,operands);
if (opcode.equals("add")) return hlprTwoReg(ignoreVars,0x09,operands);
if (opcode.equals("and")) return hlprTwoReg(ignoreVars,0x0d,operands);
Các hlpr...
chức năng chỉ đơn giản là các toán hạng và trở về một mảng byte chứa các hướng dẫn. Chúng hữu ích khi nhiều thao tác có yêu cầu toán hạng tương tự, chẳng hạn như adc ,
thêm and
và` tất cả yêu cầu hai toán hạng đăng ký trong trường hợp trên (tham số thứ hai kiểm soát opcode được trả về cho lệnh).
Bằng cách làm cho các loại toán hạng dễ phân biệt, bạn có thể kiểm tra xem toán hạng nào được cung cấp, cho dù chúng là hợp pháp và chuỗi byte nào tạo ra. Việc tách các hoạt động thành các hàm riêng của chúng cung cấp một cấu trúc lôgic tốt đẹp. Ngoài ra, hầu hết các CPU theo một bản dịch hợp lý từ opcode đến hoạt động (để làm cho các nhà thiết kế chip sống dễ dàng hơn) do đó sẽ có các tính toán tương tự trên tất cả các mã cho phép, ví dụ, địa chỉ được lập chỉ mục.
Để tạo mã đúng cách trong CPU cho phép các hướng dẫn có độ dài thay đổi, tốt nhất bạn nên làm trong hai lần.
Trong lần truy cập đầu tiên, không tạo mã, chỉ cần tạo độ dài của hướng dẫn. Điều này cho phép bạn gán các giá trị cho tất cả các nhãn khi bạn gặp chúng. Pass thứ hai sẽ tạo ra mã và có thể điền vào các tham chiếu tới các nhãn đó vì các giá trị của chúng được biết đến. ignoreVars
trong đoạn mã trên được sử dụng cho mục đích này (chuỗi byte mã được trả về để chúng tôi có thể biết độ dài nhưng bất kỳ tham chiếu nào đến các ký hiệu vừa được sử dụng 0).
Bạn đã cân nhắc sử dụng một trình kết hợp hiện có như ['gas'] (http://en.wikipedia.org/wiki/GNU_Assembler) hay [' nasm'] (http://nasm.us)? [Chương 11] (http://www.nasm.us/doc/nasmdo11.html) của tài liệu NASM mô tả các tính năng x86-64 của nó. –
Để kết thúc trở lại, hãy lấy một bản sao của sổ tay AMD (nó trực tuyến miễn phí). Đối với giao diện người dùng, kiến thức cơ bản về trình biên dịch sẽ là đủ, vì x86 (và amd64) lắp ráp đặc biệt dễ phân tích cú pháp. –