Common Lisp で独自の x86-64 アセンブラを作成していますが、x86-64 のサブセットに対して正しいバイナリ コードを生成します。カスタム リーダー マクロを使用してアセンブリ コードを構文ツリーに変換すると、期待どおりに動作します。
私が達成しようとしているのは、アセンブリ コード内で Lisp コードを使用できるようにすることです。そうすれば、Lisp をアセンブラのマクロ言語として使用できます。#aマクロディスパッチ文字として使用し#e、リーダーに終了を知らせるために使用します。リーダー内#lで Lisp モードに変更し#a、アセンブリ モードに戻る#e(リーダー マクロの終了を通知するため) は、両方のモードで機能するはずです。
私が理解していないのは、評価されたコードの結果を入力ストリームに出力する方法 (残りのコードの前に処理される)、または Lisp コードの出力を再度読み取る方法です。 Lisp コード (アセンブリ コード) を適切に処理できます (残りのアセンブリ コードと同じ方法)。どうすればその目標を達成できますか?
補足: これは私の最初のリーダー マクロであるため、設計上の欠陥がある可能性があります。Lisp コードを文字列に読み込むという私のアプローチは、より短くて慣用的な方法があれば、必ずしも最善の方法ではないと思います。
以下は、私のリーダー マクロの簡略版です。
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun get-last-character-string (my-string)
「この関数は、入力文字列の最後の文字で構成される文字列を返します。」
(subseq my-string (1- (length my-string))))
(defun get-string-without-last-character (my-string)
「この関数は、入力文字列の最後の文字を除いた文字列を返します。」
(subseq my-string 0 (1- (長さ my-string))))
(defun get-string-without-invalid-last-character (my-string invalid-last-characters)
「文字列の最後の文字が無効な場合、文字列はそれなしで返されます。それ以外の場合は完全に返されます。」
(invalid-last-characters 内の invalid-last-character のループ
do (if (equal (get-last-character-string my-string) invalid-last-character)
(setf my-string (get-string-without-last-character my-string))))
私の文字列)
(defun transform-code-to-string (stream sub-char numarg)
"この関数は、アセンブリ コードを文字列に変換します。
#l は Lisp コードへの変更を示します。#a マークは asm に戻ります。#eマーク終了。
部分的に基づく: http://weitz.de/macros.lisp"
(宣言 (sub-char numarg を無視))
(させて*
((無効な最後の文字 (リスト "'" " " "(" ")"))
(現在のモード「asm」)
(is-there-code-on-this-line nil)
(現在のフェーズの「行頭」)
(my-string "(list ")
(lisp-code-string ""))
;; ストリームをループします。
(ループ for my-char = (coerce (list (read-char stream t nil t)) 'string)
する(条件
((等電流モード「asm」)
(状態
((等しい現在のフェーズ「ハッシュ符号読み取り」)
;; 文字はeですか?
;; はいの場合は完了です。閉じ括弧を修正して戻ります。
(状態
((equal my-char "e")
(変換コードから文字列への戻り値
(concatenate 'string (get-string-without-invalid-last-character)
(get-string-without-invalid-last-character
my-string 無効な最後の文字)
無効な最後の文字) "))")))
;; 文字 l ですか?
;; はいの場合、Lisp モードに変更します。
((等しい my-char "l")
;; ここでLispコードを読み取って評価できますか
;; それを文字列に読み込まずに?
(プログ
(setf current-mode "Lisp")
(setf is-there-code-on-this-line nil)
(setf lisp-code-string "")
(setf current-phase "beginning-of-line")))
;; そうでない場合は、印刷エラー。
(t (エラー "in asm mode undefined control character after #"))))
;; は文字 # ですか?
;; はいの場合、ハッシュ記号を既読としてマークします。
((等しい my-char "#")
(setf current-phase "hash-sign-read"))
;; 文字は改行ですか?
((equal my-char (coerce (list #\Newline) 'string))
(プログ
(状態
;; この行にコードはありませんか?
;; true の場合、何も出力しません。
((この行にあるコードではありません)
(setf current-phase "beginning-of-line"))
;; 私たちは命令の中にいますか、それともパラメーターの中にいますか?
;; true の場合、出力 ")
((または (等しい電流フェーズ「内部命令」)
(等しい電流位相「内部パラメータ」))
(プログ
(setf current-phase "beginning-of-line")
(setf is-there-code-on-this-line nil)
(setf my-string (concatenate 'string my-string "\")"))))
;; それ以外の場合は出力)
(t (プログ
(setf current-phase "beginning-of-line")
(setf is-there-code-on-this-line nil)
(setf my-string (concatenate 'string my-string ")")))))))
;; 私たちはコメントの中にいますか?
;; はいの場合、何も出力しません。
((等しい電流フェーズ「内部コメント」)
なし)
;; 私たちは列の先頭にいますか?
((等しい現在のフェーズ「ラインの始まり」)
(状態
;; これは行頭のスペースですか?
;; はいの場合、何も出力しません。
((equal my-char " ")
なし)
;; これは ( または ) ではなく、命令の最初の文字ですか?
;; はいの場合、この行にコードがあることをマークし、最初の文字を印刷済みとしてマークし、" と現在の文字を出力します。
((と
(not (equal my-char "("))
(not (equal my-char ")")))
(プログ
(setf current-phase "inside-instruction")
(setf is-there-code-on-this-line t)
(setf my-string (concatenate 'string my-string "'(\"" my-char))))
(t nil)))
;; は文字です。?
;; はいの場合、何も出力せず、コメントを開始します。
((等しい my-char ";")
(setf current-phase "inside-comment"))
;; 文字スペースまたはコンマですか?
((または (equal my-char " ")
(等しい my-char ","))
(状態
;; は文字スペースまたはコンマであり、最後の文字はスペース、コンマ、または開き括弧ではありませんか?
;; はいの場合、" とスペースを出力します。
((と
(not (equal (get-last-character-string my-string) " "))
(not (equal (get-last-character-string my-string) ","))
(not (equal (get-last-character-string my-string) "(")))
(プログ
(setf 電流位相「空間内」)
(setf my-string (concatenate 'string my-string "\" "))))
(t nil)))
;; 命令が出力され、これがパラメーターの最初の文字ですか?
((と
(not (等しい電流位相「内部命令」))
(または (equal (get-last-character-string my-string) " ")
(equal (get-last-character-string my-string) ",")))
(状態
;; パラメータ内にいることをマークし、" と現在の文字を出力します。
(t (プログ
(setf 電流位相「内部パラメータ」)
(setf my-string (concatenate 'string my-string "\"" my-char))))))
;; それ以外の場合は文字を出力します。
(t (setf my-string (concatenate 'string my-string my-char)))))
((等電流モード「Lisp」)
;; Lisp モードでは、#e または #a に到達するまでテキストを読み取り、それを評価します。
(状態
((等しい現在のフェーズ「ハッシュ符号読み取り」)
(状態
;; 文字はeですか?
;; はいの場合は完了です。閉じ括弧を修正して戻ります。
((equal my-char "e")
(プログ
(concatenate 'string "#a" (eval lisp-code-string) "#e") ; これは何か違うはずです。
(変換コードから文字列への戻り値
(concatenate 'string (get-string-without-invalid-last-character)
(get-string-without-invalid-last-character
my-string 無効な最後の文字)
無効な最後の文字) "))"))))
;; は文字 a ですか?
;; ある場合は、asm モードに変更します。
((等しい my-char "a")
(プログ
(setf current-mode "asm")
(setf is-there-code-on-this-line nil)
(setf current-phase "beginning-of-line")
(concatenate 'string "#a" (eval lisp-code-string) "#e") ; これは何か違うはずです。
;; それ以外の場合は、評価する Lisp コードに # と文字を追加します。
(t (プログ
(setf 電流位相 "")
(setf my-string (concatenate 'string lisp-code-string "#" my-char))))))
;; は文字 # ですか?
;; はいの場合、ハッシュ記号を既読としてマークします。
((等しい my-char "#")
(setf current-phase "hash-sign-read"))
;; それ以外の場合は、評価される Lisp コードに文字を追加します。
(t (setf my-string (concatenate 'string lisp-code-string my-char)))))
(t (エラー「無効な現在のモード」))))))
;;; #a は、カスタム リーダーを開始する入力です。
(set-dispatch-macro-character #\# #\a #'transform-code-to-string))
以下は、Lisp コードを含まないアセンブリ コードの例です。動作します。
(defparameter *example-code-x64* #a inc r10 ; レジスタr10をインクリメントします。 mov r11,r12 ; r12 の値を r11 に格納します。 #e)
そして、これは Lisp コードを内部に含むアセンブリ コードで、失敗します(以下のコンパイル エラーを参照してください)。この例では、Lisp コードはアセンブリ コードの後にありますが、アセンブリ コードと Lisp コードは区切り記号として#aとを使用して自由に混在させることができます。#l
(defparameter *example-code-x64-with-lisp-fails*
#a
inc r10 ; レジスタr10をインクリメントします。
mov r11,r12 ; r12 の値を r11 に格納します。
#l
(現在の命令のループ (list "inc" "dec")
do (ループ for current-arg in (list "r13" "r14" "r15")
do (princ (concatenate '文字列
現在の命令
" "
現在の引数
(coerce (list #\Newline) '文字列)))))
#e)
上記のコードの Lisp 部分は、カスタム リーダーで評価して、以下のコードと同じ結果を生成する必要があります。
(defparameter *example-code-x64-with-lisp-fails* #a inc r10 ; レジスタr10をインクリメントします。 mov r11,r12 ; r12 の値を r11 に格納します。 株式会社r13 株式会社r14 インク r15 r13 12月 12 月 r14 r15 12月 #e)
しかし、代わりにコンパイルは失敗します:
CL-ユーザー> ; ファイル「/home/user/code/lisp/lisp-asm-reader-for-stackoverflow.lisp」のコンパイル (2014 年 3 月 28 日 10:11:29 PM に書き込み): ; ; エラーをキャッチ: ; COMPILE-FILE 中の読み取りエラー: ; ; 値 -1 は型 (MOD 4611686018427387901) ではありません。 ; ; (フォームの行: 1、列: 0、ファイル位置: 0) ; ; コンパイル ユニットが中止されました ; 致命的な ERROR 状態を 1 つキャッチ ; 1 個の ERROR 状態をキャッチ ; コンパイルは 0:00:00.004 後に中止されました 1 コンパイラー・ノート: /home/user/code/lisp/lisp-asm-reader-for-stackoverflow.lisp:10487 read-error: COMPILE-FILE 中の READ エラー: 値 -1 は型 (MOD 4611686018427387901) ではありません。 (フォームの行: 1、列: 0、ファイル位置: 0) CLユーザー>