WinAli - CPU ảo để hiểu ngôn ngữ lắp ráp


8

WinAli là một trình biên dịch mô hình cho Windows. Nó mô phỏng một CPU thực sự và có nghĩa là giúp sinh viên học và hiểu ngôn ngữ hội.

Bài viết Wikipedia tiếng Đức: http://de.wikipedia.org/wiki/WinAli (hiện tại không có bài viết tiếng Anh nào)

Trong trường hợp bạn muốn kiểm tra đầu ra được sản xuất của mình: Liên kết với Google Drive (bản thân chương trình bằng tiếng Đức nhưng rất dễ sử dụng ngay cả khi bạn không hiểu tiếng Đức)

Một số thông tin về WinAli (dữ liệu và cú pháp)

Loại dữ liệu:

Kiểu dữ liệu duy nhất trong WinAli là "Số nguyên" dài 2 byte, trên thực tế là Nhỏ hoặc ngắn . Vì vậy, bạn không cần phải chăm sóc các loại chính xác. Điều này cũng được làm tròn khi chia.

Các biến và hằng:

Các biến được định nghĩa như thế này sau các lệnh:

name DS F
  • Tên rõ ràng là tên của biến
  • DS là từ khóa cho một biến mới
  • F xác định độ dài của biến tính theo bit; đây là không dựa trên cơ sở và thập lục phân nên F = 16 bit

Các hằng số rất giống nhau:

name DC value
  • Tên chỉ đơn giản là tên của hằng số
  • DC là từ khóa cho một hằng số mới
  • giá trị là giá trị được gán cho hằng số đó, vdtwo DC '2'
  • Bạn không cần chỉ định các hằng số ở cuối mã. Bạn cũng có thể viết chúng nội tuyến với thao tác LDA(tải), vd LDA 0,'2'. Điều này tải "2" vào thanh ghi 0 (bộ tích lũy).
Cú pháp:

Mã được căn chỉnh thành 4 cột được phân tách bằng khoảng trắng hoặc tab:

label command params comment
  • nhãn được sử dụng cho b labellệnh ( goto label) và thường bị bỏ qua.
  • lệnh một trong các lệnh được liệt kê dưới đây.
  • params một hoặc hai tham số có ít nhất một đăng ký và nếu cần thiết khác đăng ký, thay đổi, chồng hoặc địa chỉ; các tham số này được phân tách bằng dấu phẩy ( ,).
  • bình luận (tùy chọn) một bình luận có tiền tố ;hoặc *cho đến cuối dòng.

Tham chiếu mã nhỏ:

Có nhiều lệnh hơn nhưng đối với thử thách này, bạn chỉ cần những lệnh đó:

  • INI A Lưu trữ đầu vào người dùng tiếp theo vào biến A
  • OUTI AXuất ra giá trị mà biến Ađang giữ. Bạn không thể sử dụng một đăng ký ở đây vì một số lý do.
  • LDA 0,ATải giá trị của Avào thanh ghi 0
  • STA 0,A Lưu giá trị của thanh ghi 0 vào biến A
  • ADD 0,AThêm giá trị của Avào giá trị của thanh ghi 0
  • SUB 0,ANhân giá trị của Avới giá trị của thanh ghi 0
  • DIV 0,AChia giá trị Atheo giá trị của thanh ghi 0
  • EOJXác định kết thúc công việc tức là mã thực thi. Khai báo biến và liên tục bắt đầu sau dấu này.

Không rõ ràng cần thiết cho thử thách này:

  • program START 0Đặt địa chỉ đầu tiên được thực thi thành 0 tức là dòng tiếp theo ( programchỉ là tên của chương trình nhưng cần thiết cho trình biên dịch)
  • END program Kết thúc chương trình tức là dừng thực thi, ngay cả khi các hoạt động khác sẽ tuân theo

Thử thách của bạn!

Viết chương trình hoặc tập lệnh lấy biểu thức toán học có số và biến không đổi và xuất mã WinAli lấy tất cả các biến làm đầu vào và xuất kết quả của biểu thức đó.

  • Bạn không cần phải xuất STARTENDlệnh
  • Mặc dù có 16 thanh ghi được định nghĩa trong WinAli, chúng tôi chỉ sử dụng thanh ghi 0, đây là bộ tích lũy cho tất cả các tính toán
  • Bạn không thể sử dụng hai biến làm tham số của lệnh. Bạn phải lưu tất cả các kết quả của bạn vào bộ tích lũy (đăng ký 0)
  • Đầu vào luôn ở dạng x:=(a+b)/choặc đơn giản (a+b)/c, bạn quyết định
  • Bạn chỉ cần chăm sóc + - * / (ADD, SUB, MUL, DIV), vì vậy không có tính toán phức tạp như rễ, hình vuông hoặc thậm chí là xoang
  • Mẹo: Trước tiên hãy thử trích xuất các biểu thức đơn giản chỉ với 2 đối số, a:=a+bsau đóx:=a/c
  • Mẹo: Chương trình của bạn được phép sử dụng các biến bổ sung (phụ trợ) nếu bạn không thể ghi đè lên các biến không được sử dụng sau này trong mã của bạn. Xác định chúng là h1 DS F.
  • Mẹo: Dòng trống là vô dụng. Cố gắng tránh chúng. (Bạn thực sự không cần chúng)

Thí dụ:

Biểu thức toán học:
 x: = (a + b) * c

Đầu ra dự kiến ​​(dòng trống để đọc dễ dàng hơn):
    INI a
    INI b
    INI c

    LDA 0, một
    THÊM 0, b
    MUL 0, c
    STA 0, một

    NGOÀI a
    EOJ
một DS F
b DS F
c DS F

Ghi điểm:

Điểm của bạn được xác định bởi độ dài mã của bạn + độ dài đầu ra của các biểu thức sau:

x:=a+b+c*c/d

x:=(a+b)/c-d

x:=a-b*c-d/e

x:=2*a-b*c+d
  • -10% nếu mã của bạn có thể xử lý dấu trừ đơn phương trong biểu thức.

Trong trường hợp hòa, câu trả lời tạo ra mã WinAli hoạt động ngắn nhất sẽ thắng.

Các giải pháp có thể không được mã hóa theo bất kỳ cách nào. Tôi sẽ xác nhận từng câu trả lời bằng các biểu thức bổ sung để đảm bảo câu trả lời của bạn là chính xác.


Chính xác thì biểu thức toán học là gì? Ví dụ như hằng số âm được phép? Điểm trừ đơn phương? Tên biến dài hơn một chữ cái?
nutki

Các chỉ thị đầu vào (INI x) có cần tuân theo bất kỳ thứ tự cụ thể nào không?
nutki

@nutki một biểu thức toán học có nghĩa là một x = a + b đơn giản vì vậy không giải được các phương trình phức tạp, hằng số âm được cho phép, tên biến có thể nhiều hơn một chữ cái (ab không phải là * b), INI x có thể được đặt ở đâu bao giờ bạn muốn không có thứ tự cụ thể cần thiết vì nó lưu trữ đầu vào tiếp theo vào biến đưa ra nhưng sẽ rất tuyệt nếu họ tuân theo thứ tự az thay vì ngẫu nhiên
GiantTree

@nutki bởi unary trừ bạn nghĩa là gì MUL 0,-a? điều này là không thể bởi vì không có địa chỉ âm ( achỉ là một con trỏ tới một giá trị), nhưng bạn có thể trừ giá trị từ 0 để có được biểu diễn âm ( SUB 0,a) và sau đó làm việc với giá trị âm này; bạn thậm chí có thể lưu trữ điều này trong biến ban đầu.
GiantTree

Tôi có nghĩa là trừ unary trong biểu thức đầu vào, ví dụ x:=-a*bhay x:=a/-(b+c). Vì thứ tự đầu vào không được chỉ định, tôi đoán chúng ta phải sử dụng cùng tên biến trong mã WinAli, có phải vậy không? Với những hạn chế đó, có những định danh không bao giờ có trên đầu vào? Ví dụ có thể h1là một tên biến đầu vào?
nutki

Câu trả lời:


4

Perl 5: 948, mã 355 + đầu ra 593

Sau khi chơi golf. Phiên bản ngắn hơn trước đó không phân tích đúng (a+b)-4*c.

%m=split'\b','-SUB+ADD/DIV*MUL<LDA>STA';$i='(\w+|(?<!\w|\))-\d+)';
$_=<>;@x{@y=/([a-z]\w*)/gi}=@y;print"\tINI $_
"for@x=keys%x;
$f=$_,$x.="<$&>".($g=(grep$f!~$_,a..zz)[0]),$x{$g}=s/@/$g/
while s|\($i\)|$1|g,s|$i[*/]$i|@|||s|$i[+-]$i|@|;$_="$x
\tOUTI $_\tEOJ
";s/>$i<\1//g;s!(^|\b)[-+/*<>]!\n\t$m{$&} 0,!g;
s!-?\d+$!'$&'!mg;print;print"$_\tDS F
"for keys%x

Ví dụ sử dụng:

$perl winali.pl <<<"2*a-b*c+d"
    INI b
    INI a
    INI d
    INI c

    LDA 0,'2'
    MUL 0,a
    STA 0,a
    LDA 0,b
    MUL 0,c
    STA 0,b
    LDA 0,a
    SUB 0,b
    ADD 0,d
    STA 0,b
    OUTI b
    EOJ
b   DS F
a   DS F
d   DS F
c   DS F

Đã xác minh. Sẽ tốt đẹp nếu đầu vào được sắp xếp theo thứ tự abc. Chỉ cần một mẹo: các dòng trống bị bỏ qua để chúng có thể giảm độ dài đầu ra của bạn xuống một chút
GiantTree

Một số tối ưu hóa bạn có thể làm: xóa dòng mới
GiantTree

Với các tối ưu hóa ở trên, đầu ra của bạn sẽ dài 585 byte (giảm 8 byte)
GiantTree

Trailing newline có thể được loại bỏ miễn phí mã, nhưng để xóa một dòng trống sau INI có thể sẽ tốn hơn 4 ký tự mã.
nutki

oh, sau đó chỉ cần xóa dòng mới, nó không cần thiết và sẽ giúp bạn tiết kiệm 4 byte :)
GiantTree
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.