AutoLISP

提供:GizmoLabs - だいたい CAD LISP なサイト

AutoLisp の概要

AutoLisp は、AutoCAD に搭載されているインタープリタ型プログラミング言語。BricsCAD や IntelliCAD, IJCAD など互換の CAD ソフトでも利用できる。 自作のコマンドやシステム変数、ダイアログ ボックス(DCL)を呼び出すことができる。 初期の AutoCAD 2.18 から搭載され一番長くサポートされている API (バージョン履歴とサポートAPI参照) であり、他の API に比べ CAD のバージョンアップに伴う影響を受けにくい API といえる。 AutoCAD LT においてはバージョン 2024 の以降から利用できるようになったがパフォーマンスは良くない。(AutoCAD LT で AutoLisp の機能を利用可能にするソフトウェアも存在したが、LT2002 以降のバージョンに対応したものはなくなっている。)

  • ちなみに、AutoLISP は XLISP 1.0 からの派生(サブセット&スーパーセット)と言われている。>> バージョン履歴とサポートAPI
  • VisualLISP は、Basis Software, Inc. の Vital LISP を買収したものがベースになっている。Wikipedia
  • VisualLISP 搭載以前と以降を分けて話をする時、以前を Vanilla Lisp(日本の感覚でいうと"素のLISP") と言ったりする。
  • DWGデータに LISP に関連する情報が埋め込める仕組みがあるので、DWG 互換 CAD =LISP に対応している。となり、対応してないものはデータ互換の質が低いものといって差し支えない。


AutoLISP が使える CAD ソフト

Lispが使えるCADも参照。

製品名 LSP対応 LSP(ユニコード)対応 DCL対応 VL関数対応 FAS/VLX対応
AresCAD COMed
(≒ CorelCAD, ≒ Draftsight有料版)
? ○*6 ×
AutoCAD ○(v2021-)
AutoCAD(Mac版) ○(v2021-) △(v2021-)*4 × ×
BricsCAD(全グレード) ○(v19-) ×
GstarCAD(STD or PRO グレード) ○(v2024-) △*3*4
IJCAD(STD or PRO グレード)
(≒ GstarCAD)
○(2024-) △*3*4
IntelliCAD系CAD ○(v8-) △(v8-)*4 ×
nanoCAD ? △*2 × ×
ZWCAD ? ×
▼ 使えないグレードと製品
AresCAD(≒ Draftsight (Standard, 旧Free)) × × × × ×
AutoCAD LT × ○(2024-) ○(2024-) × ×
GstarCAD LT △*5 × × × ×
IJCAD LT △*5 × × × ×
  • *2 … 日本語の扱いが良くない。
  • *3 … 自前でコンパイルは出来ない。ユニコードベースのファイルには対応していない。IJCAD 2023 時点
  • *4 … 部分的なサポート。
  • *5 … メニューマクロとコマンドラインでのみ部分的に利用可能。
  • *6 … AresCAD Com2022 から


AutoCAD の AutoLISP と比較した 互換CAD の LISP

  • VisualLISP (vl)系の関数を除いた LISP関数の互換性は、どの CAD もだいたい利用可能。
  • VisualLISP 系の関数を含めた場合
    • AutoCAD との関数的互換性: AutoCAD=100 として、BricsCAD=99、IJCAD=96、IntelliCAD系=83 という感じ。
    • LISP の処理パフォーマンス: AutoCAD=100 として、BricsCAD=500、IJCAD=78、IntelliCAD系=80 という感じ。
    • LISP の開発環境の充実度: AutoCAD=100 として、BricsCAD=120、IJCAD=50、IntelliCAD系=50 という感じ。

(いずれも 2023年3月時点における個人的な主観です。)


AutoLisp 関数の構文

AutoLisp の構文は非常にシンプルである。以下に例を示す。

caption


解説
上の例では、foo 関数には 1 つの必須引数 string と、1 つの省略可能な引数 number があり、引数 number は追加で指定することができる。一般に、引数の名前は予期されるデータ タイプを表している。 この foo 関数で有効な呼び出しと無効な呼び出しの例をを示す。

  • 有効な呼び出し例
    • (foo "catch")
    • (foo "catch" 22)
    • (foo "catch" 22 31)
  • 無効な呼び出し例
    • (foo 44 13) ; <- 引数 string が無い
    • (foo "fi" "foe" 44 13)  ; <-引数 number に文字が指定されている
    • (foo)  ; <- 引数が無い。

無効な呼び出しを行うとエラーになり、処理が中断される。


コメントの記述

LISP プログラムのファイル中のコメントは、

  • 単一行コメント : ";" (セミコロン)以降から改行位置までがコメントとして扱われます。
  • 複数行のコメント : ";|" で始まり "|;" で終わる形で記述し、その間がコメントして扱われます。

一部の互換CADは、複数行コメントの記述に対応していません。

(princ "コメント対応チェック!")
; (princ "\n一行コメントだよ")
;| 
  (princ "複数行コメントだよ")
|;
(princ "\n上にコメント表示されていたらコメント対応できてない!")


AutoLISP のデータ タイプ

AutoLISP には以下のデータタイプがある。AutoLISPをフル活用するには、データタイプの使い方を理解する事が必須と言っていい。



関数の機能別一覧

以下は関数を分類分けしたもの。他に、目次からのアクセスが AutoLISP 関数一覧的で便利かも。


AutoLISP プログラムの作成・開発環境

AutoLISP のプログラムは、以下の 3つのファイル形式のうちのいずれかで作成する。

  • LSP ファイル(.lsp) ・・・ AutoLISP プログラム コードが記述された ASCII テキストファイル。(日本だと Shift-JIS の文字コードが一般的だが、AutoCAD 2021 からはユニコードが標準に。)
  • FAS ファイル(.fas) ・・・ 1 つの LSP プログラム ファイルのコンパイル済みバイナリ ファイル。
  • VLX ファイル(.vlx) ・・・ 1 つ以上の LSP(FAS) ファイルとダイアログ コントロール言語(DCL)ファイルの両方または一方をコンパイルしたファイル。


AutoCAD(~2022)と BricsCAD は製品内に開発環境(IDE)を備えているのでそれを使えるが、その他の IDE が無い互換製品はテキストエディタなどによる開発となる。

LISP の開発に使用するテキストエディタは括弧の補完機能や字下げ機能があると便利で、以下のようなものがある。

  • Visual Studio Code … AutoCAD 2021 から標準的な開発環境になり拡張機能を追加することでデバックまで可能になっている。互換CADではデバックはできないが、シンタックスハイライトは活用できる。
  • Notepad ++
  • xyzzyemacs など

以下は、市販エディタ。


また、AutoCAD やほとんどの互換 CAD では、次のようにコマンドプロンプトに直接記述して実行することが出来る。

コマンド: (+ 1 2 3 4 5 )
15   <- 実行結果


AutoLISP プログラムの秘匿化

各CADの秘匿化方法は以下の通り。

  • AutoCAD の場合
    • AutoCAD 2021 から makelispapp コマンドから VLX ファイルにコンパイルできる。(LISPSYS=1 の場合。このコマンドでコンパイルすると 2021 以前のバージョンで読み込めないものになる。)
    • AutoCAD 2000 から Visual LISP (VLISP) の環境搭載されコンパイラ、デバッガ、などを備えた統合開発環境(IDE)を備えているため、その上で AutoLISP プログラムを .fas や .vlx のファイルにパッケージングすることが出来る。
    • (暗号強度は低い)古い PROTECT.EXE での暗号化も利用可能。
  • BricsCAD の場合
    • V18.2 のバージョンより BLADE という開発環境(IDE)が搭載されたので、そこからプロジェクトをまとめて、またはファイルを個別にコンパイルできる。(descoder.exe)
    • V18.2 以前では、コンパイル用の exe が搭載されているのでそれを使ってコンパイルできる。
  • GstrCAD/IJCAD の場合
    • 2013 以降では CAD 上からコンパイル用のコマンド(_ENCRYLISP)を実行できるのでそれで暗号化する。古いAutoCAD の秘匿化プログラム PROTECT.EXE での秘匿化と同じタイプと、AES、DES、3DS タイプの独自暗号化が可能。また、IJCAD 上でコンパイルはできないが AutoCAD で作成された FAS、VLX ファイルも読み込んで利用できる。(但し、名前空間の扱いや最適化されたものの動作については未対応。また、ユニコード LISP も未対応。)
    • 2013 以前のバージョンで、LISP プログラムを秘匿化したい場合は、AutoCAD に搭載されている PROTECT.EXE か、旧 ebatech社(IntelliJAPAN の前身)からでていた IJPROLSP.EXE を利用して暗号化する。ただ、どちらも暗号強度としては弱くわりと簡単に復号できてしまう。


秘匿化されたものを元のソースコードの状態に復元することは基本的にできない。 ただし、AutoCAD の PROTECT.EXE と IJCAD の IJPROLSP.EXE でコンパイルされたものについては、暗号強度が無いに等しいレベルなので簡単に復元できてしまう。

秘匿化されたプログラムは、基本的にそのソフトでしか使えないと思った方がいい。そのため、読み込ませたくない場合はとりあえず秘匿化しておくと良いが、例外的に AutoCAD の PROTECT.EXE で秘匿化されたものは 他の互換CAD でも読み込めることが多いので注意。


AutoLISP プログラムの使用

AutoLISP のプログラム(.lsp のファイル)は、まずそのプログラムをCADへロードする必要がある。

ロードは、コマンド プロンプトに対して load 関数を使用して AutoLISP コードを入力する。 load 関数が正常に終了すると、ファイル内の最後の式の値がコマンド プロンプト領域に表示される。これは通常そのファイルで定義されている最後の関数の名前か、新しくロードされた関数の使用説明となる。

load 関数が失敗すると、AutoLISP のエラー メッセージが表示される。 load 関数の失敗は、AutoLISPファイルのコーディング間違いや、コマンド プロンプトに対して間違ったファイル名を入力した場合に起こる。

load 関数の構文は、次のとおり。

(load filename [onfailure]) 

この構文は、load 関数に 2 つの引数があることを示している。 1つ目の filename は、読み込むAutoLISPファイル名(とパス)で必須。 2つ目の onfailure は省略可能で、失敗した場合のメッセージを入力する。 コマンドラインからの入力で AutoLISP ファイルをロードする場合は通常、filename 引数のみを指定する。

次の例は、AutoLisp ファイル newfile.lsp をロードしている。

コマンド: (load "newfile")

拡張子 .lsp は省略可能。この形式は、現在のライブラリ パス上のどの LSP ファイルに対しても動作する。

ライブラリ パス上にない AutoLisp ファイルをロードする場合は、filename 引数として、ファイル名を絶対パスで指定する必要がある。

コマンド: (load "d:/files/morelisp/newfile")
または
コマンド: (load "d:\\files\\morelisp\\newfile")

注 : フォルダ パスを指定する場合、スラッシュ(/)または 2つの円記号(¥¥)を区切り記号として使用する必要がある。通常Windowsで利用される単一の円記号(¥)での指定は、2つの円記号(¥¥)となる。これは、AutoLisp では単一の円記号(¥)には特別な意味があるため。

  • 尚、大体の CAD は LISP ファイルを CAD のウィンドウに ドラッグ&ドロップしても読み込まれる。


自動ロード

CAD  起動時  ファイルオープン時 備考
AutoCAD acad.lsp acaddoc.lsp システム変数:ACADLSPASDOC を1にすると、ファイルオープン時に acad.lsp をロードするようになる。
BricsCAD V9 以降 on_start.lsp on_doc_load.lsp システム変数:ACADLSPASDOC を1にすると、ファイルオープン時に on_start.lsp をロードするようになる。
GstarCAD & IJCAD gcad.lsp gcad.lsp IJCAD 2014 以前と以後でベースのCADがIntelliCADからGstarCADに変更されたためロードの仕方が変わっている。一貫性に欠けているので「 #IJCAD で自動ロードする場合の注意点 」を参照。
IntelliCAD icad.lsp icaddoc.lsp IntelliCAD 8.0 以降がベースの製品 。(IJCAD だと 8 が該当)
  • AutoCAD ではシステム変数:LISPINIT を1にすると、図面が開かれるたび、作成されるたびに LISP 環境が初期化される。(SDI モード時に変数値を引き継ぎたいなら0にする)
  • 自動ロードファイルはファイルの初期化前に実行されるため、command 関数は使ってはいけない。(互換CAD でも基本は避けておいたほうが無難。)AutoCAD の場合は、S::STARTUP 関数に記述する事になっている。
  • BricsCAD は V17以降、別途でレジストリに登録しておいてロードさせる仕組みがある。


IJCAD で自動ロードする場合の注意点

  • IJCAD 2014 ~ (GstarCAD ベース)
    • gcad.lsp が起動時に読み込まれ、ACADLSPASDOC が 1 だと、gcad.lsp が毎回読み込まれる。
    • 図面毎に名前空間が分かれている。LISPINIT は無効。
  • IJCAD 2013
    • icad.lsp が毎回読み込まれる。
    • 図面毎に名前空間が分かれていないため、自動ロードで何か初期化を行う処理がある場合、別の図面を開いたときにすでに開いている変数値などが上書きされてしまう可能性があるため、特に複数のファイルにまたがる処理をする場合は注意が必要である。
  • IJCAD 8
    • icaddoc.lsp が有効になったので、ドキュメント毎に読み込みたい処理は icad.lsp ではなく icaddoc.lsp に記述しておくと良い。(2012.04 のアップデートから)
    • ACADLSPASDOC が有効になったので、初期値では icad.lsp を起動時にしか読み込まない。icaddoc.lsp +icad.lsp の両方を読み込みたければ ACADLSPASDOC=1 にしておくと良い。(読み込まれる順番は icad.lsp -> icaddoc.lsp)
    • 名前空間が一応分かれてるので変数はドキュメント毎。 LISPINIT が有効なので、変数を共有したい場合は LISPINIT=2、開いたファイルにアクティブドキュメントの変数をコピーして使うなら 0 に切り替えておく。
  • IJCAD 7
    • 図面毎に名前空間が分かれているような動きだが完全じゃないので、ファイルの close などで変数が上書きされた状態になったりする可能性がある。複数のファイルにまたがる処理をする場合は注意が必要。
  • IJCAD 6
    • 図面毎に名前空間が分かれていないため、自動ロードで何か初期化を行う処理がある場合、別の図面を開いたときにすでに開いている変数値などが上書きされてしまう可能性がある。特に複数のファイルにまたがる処理をする場合は注意が必要。
  • IJCAD 5以前
    • 図面毎に名前空間が分かれていないため、自動ロードで何か初期化を行う処理がある場合、別の図面を開いたときにすでに開いている変数値などが上書きされてしまう可能性がある。特に複数のファイルにまたがる処理をする場合は注意が必要。


32bit と 64bit


; 整数範囲外の計算
(= 2147483650 (+ 2147483647 3)) ; 整数だと範囲外の解になる計算は正しくない
nil

(= 2147483650 (+ 2147483647 3.0))  ; 浮動小数点が絡む計算なら整数範囲外の解になる計算は正しい
T

; 整数範囲外だと丸められてしまう例
(atoi "2150000000")
2147483647

(atoi "-2150000000")
-2147483647


  • ARX や .NET など他の言語のカスタマイズを読み込むときに AutoLISP を使ったりする。(以下サンプル)
; AutoCAD が 64bit版かどうか(なお、AutoCAD 2020 以降は 64bit しか無いのでこれは不要になる)
(defun cadx64-app ()
  (vl-load-com)
  (> (strlen (vl-prin1-to-string (vlax-get-acad-object))) 40)
)

; OS(CPU) が64bitかどうか 64bitだったら 数値、それ以外は nil 
(defun cadx64-os (/ result)
  (if (= "x86" (getenv "PROCESSOR_ARCHITECTURE"))
    (progn
      (if (getenv "PROCESSOR_ARCHITEW6432")
         (setq result 6432)  ; OS & Process 32 bit
         (setq result nil)   ; 32 bit process on 64bit OS - WOW64
      ))
    (setq result 64)         ; OS & Process 64bit
  )
result)


特殊フォーム

特殊フォームは一般的な AutoLISP 関数呼び出しとは異なる方法で引数を評価する。一般的な関数は、関数に渡されたすべての引数を評価してからそれらの引数に基づいて実行するが、特殊フォームは、すべての引数を評価しないか、または特定の条件の下でのみいくつかの引数を評価する。


以下は特殊フォームとみなされる AutoLISP 関数。


保護されたシンボル名

以下のシンボル値は保護されているので新たな代入はできない。

  • NIL
(setq nil ...)   エラーになる
  • T
(setq t ...)   エラーになる 

BricsCAD では、以下のシンボル名は保護されているので定義のし直しはできない。

  • LET
  • INTERNAL-LAMBDA
  • AL_LEAVEDEFUN
  • AL_ENTERDEFUN
  • al_EnableLambdaListHook
  • al_CheckInternalLambda
  • al_PrepareDefun
  • al_RegisterLispDefun
  • al_ExecuteAdsDefun
  • before-gc-hook
  • after-gc-hook
  • _MACRO_ARG_1_
  • *LTE-ERROR*
  • $LTE$DEFUN-Q-SYMBOLS
  • *AL$LOCAL$FUNCS*


AutoLisp のエラーコード

AutoLISP で生成されるエラー コードの値と意味は次のとおり。AutoLISP の関数呼び出しによって発生したエラーを CAD が検出すると、システム変数 ERRNO に次の値のいずれかが設定される。

(getvar "errno") を使用すると、AutoLISP のアプリケーションで現在の ERRNO の値を検査できる。

システム変数 ERRNO は、ゼロにクリアされない場合があるため、AutoLISP の関数がエラーをレポートした直後に検査しないと、その値が示すエラーは誤っている可能性がある。この変数は、図面を新規作成したり図面を開いたときに、必ずクリアされる。

注:ERRNO の値とその意味は、将来変更される可能性がある。

  • 値 … 意 味
  • 0 … エラーはありません
  • 1 … 無効なシンボル テーブル名です
  • 2 … 無効な図形名または選択セット名です
  • 3 … 選択セットの最大数を超えました
  • 4 … 無効な選択セットです
  • 5 … ブロック定義が不正に使用されました
  • 6 … xref が不正に使用されました
  • 7 … オブジェクトを選択: クリックが失敗しました
  • 8 … 図形ファイルの終わりです
  • 9 … ブロック定義ファイルの終わりです
  • 10 … 最後の図形が見つかりません
  • 11 … ビューポート オブジェクトを不正に削除しようとしました
  • 12 … PLINE[ポリライン]中は操作できません
  • 13 … 無効なハンドルです
  • 14 … ハンドルが使用可能になっていません
  • 15 … 座標変換要求に無効な引数があります
  • 16 … 座標変換要求に無効な空間があります
  • 17 … 削除した図形が不正に使用されました
  • 18 … 無効なテーブル名です
  • 19 … 無効なテーブル関数の引数です
  • 20 … 読み込み専用の変数に代入しようとしました
  • 21 … ゼロ値は許されていません
  • 22 … 値が範囲外です
  • 23 … 複雑な REGEN の処理中です
  • 24 … 図形タイプを変更しようとしました
  • 25 … 不正な画層名です
  • 26 … 不正な線種名です
  • 27 … 不正な色名です
  • 28 … 不正な文字スタイル名です
  • 29 … 不正なシェイプ名です
  • 30 … 図形タイプのフィールドが不正です
  • 31 … 削除した図形を変更しようとしました
  • 32 … Seqend 従属図形を変更しようとしました
  • 33 … ハンドルを変更しようとしました
  • 34 … ビューポートの可視性を変更しようとしました
  • 35 … 図形はロックされている画層にあります
  • 36 … 不正な図形タイプです
  • 37 … 不正なポリライン図形です
  • 38 … ブロック内の複合化図形が不完全です
  • 39 … 無効なブロック名フィールドです
  • 40 … ブロック フラグ フィールドが重複しています
  • 41 … ブロック名フィールドが重複しています
  • 42 … 不正な法線ベクトルです
  • 43 … ブロック名がありません
  • 44 … ブロック フラグがありません
  • 45 … 名前のないブロックが無効です
  • 46 … ブロック定義が無効です
  • 47 … 必須フィールドがありません
  • 48 … 拡張データ(XDATA)のタイプが認識できません
  • 49 … XDATA 内のリストのネストが正しくありません
  • 50 … APPID フィールドの位置が正しくありません
  • 51 … XDATA の最大サイズを超えました
  • 52 … オブジェクトを選択: null 応答です
  • 53 … APPID が重複しています
  • 54 … ビューポート図形を作成または変更しようとしました
  • 55 … xref、xdef、xdep を作成または変更しようとしました
  • 56 … ssget フィルタ: リストが途中で終わっています
  • 57 … ssget フィルタ: テスト オペランドがありません
  • 58 … ssget フィルタ: opcode(-4)文字列が無効です
  • 59 … ssget フィルタ: ネストが正しくないか条件条項が空です
  • 60 … ssget フィルタ: 条件条項の始まりと終わりが一致していません
  • 61 … ssget フィルタ: 条件条項における引数の数が誤っています(NOT または XOR)
  • 62 … ssget フィルタ: ネストの最大数を超えました
  • 63 … ssget フィルタ: グループ コードが無効です
  • 64 … ssget フィルタ: 文字列テストが無効です
  • 65 … ssget フィルタ: ベクトル テストが無効です
  • 66 … ssget フィルタ: 実数テストが無効です
  • 67 … ssget フィルタ: 整数テストが無効です
  • 68 … ディジタイザがタブレット モードではありません
  • 69 … タブレットが位置合わせされていません
  • 70 … タブレット引数が無効です
  • 71 … ADS エラー: 新規のリザルト バッファを割り当てられません
  • 72 … ADS エラー: null ポインタを検出しました
  • 73 … 実行ファイルを開けません
  • 74 … アプリケーションは既にロードされています
  • 75 … 最大数のアプリケーションが既にロードされています
  • 76 … アプリケーションを実行できません
  • 77 … 互換性のないバージョン番号です
  • 78 … ネストしたアプリケーションをロード解除できません
  • 79 … アプリケーションがロード解除を拒否しました
  • 80 … アプリケーションが現在ロードされていません
  • 81 … メモリが不足しているのでアプリケーションをロードできません
  • 82 … ADS エラー: 変換マトリックスが無効です
  • 83 … ADS エラー: シンボル名が無効です
  • 84 … ADS エラー: シンボル値が無効です
  • 85 … ダイアログ ボックスの表示中は AutoLISP/ADS を操作できません


各CAD の LISP の更新履歴

CAD 毎に追える分だけ。


CAD系 LISPを拡張する諸々

CAD に追加でロードして使うことで便利になるプログラム。LISPベースのものもあれば、C/C++/.NETベースのものもある。

  • ADOLisp : Access Database Objact 関連
  • DosLib: OS・システム関連の拡張
  • expresstools関数: expresstools に含まれている関数
  • GzLib: 日本語対応とかOS・システム関連の拡張
  • Sqlitelsp:SQLITE データベース関連拡張
  • OpenDCL : UIインターフェスの拡張


関連