広告

Gコード分析ライブラリ for Python・Ncコメント編【Vol.2】

AI

Ncコメント編【Vol.2】

前回は、「NCワード」を「アドレスと数値・数字」に分解するコードを作成しました
次は、一行の「NCブロック」を「NCワード」に分解させる予定ですが、その前に処理しておきたいのがコメントです。
コメントはファナックでは、( ~ )に挟まれた文字は、制御器は無視するのでメッセージなどに利用されますが、
「Gコード」や「X、Y、Z」などNCワードと同形式の文字列がコメント部に含まれていると
単純に文字列検索だけで処理すると、思わぬ分析ミスになりかねません
この記事では、純粋なコード部分とコメント部分を分離するライブラリを作成します

広告

コントローラによるコメント記号の種類

Fanuc制御器では ( で始まり、 ) で閉じるまでをコメントと認識
このコメントは、複数行を跨いでも ) で閉じるまで、コメントとして扱います

OSP制御器も基本的にFanucと同じですが、( から、行末までをコメントにします
したがって、 ) で閉じる必要はないですが、Fanucのように、行を跨がせないのが一般的です
変換ソフトなどで、ファナックと共有したい場合には、確実に閉じたほうが安全です

Heidenhain の場合は、; 文字から、行末まで、
行頭に * の場合一行すべてをコメントとして扱います

Roedersの場合には、C言語に似ていて、
/* ~ */の間、や // 文字列から行末までがコメントになります

今回は、将来性も考えて、上記4点に対応した、コメント処理ライブラリを作成します

クラスライブラリ

 class BlockCommentRule: 

「開始記号〜終了記号」で囲むタイプのコメント1種類分の仕様を定義
行コメント(”;” や “//”)はこのクラスの対象外(line_markers側で扱う)

open_: 開始記号。例 “(” “/*”
close_: 終了記号。例 “)” “*/”
nested: 入れ子 “(…(…)…)” を許容するか。
multiline: 行末までに閉じなかった場合、未閉鎖の状態を次の行に持ち越すか
  True  = 複数行にまたがるコメントを許容する(例: FANUC)
  False = 必ずその行の中で強制的に閉じる(例: OSPは自動で閉じるがデータでの処理が安全)

# test code
bcr = BlockCommentRule("/*", "*/")
open = bcr.open
close = bcr.close
print(f"コメント始まり文字={open} コメント終了文字={close}")

/* */

 class DialectSpec(TypedDict): 

TypedDict は 実態はただの辞書(dict)であるが、dictに型情報を付与するための仕組み。
dictは値の型が曖昧だが、このクラスで辞書の型を決定し型情報が違う場合、
静的型チェッカーが教えてくれる。

#このクラスでコメントのタイプの型形式を定義
class DialectSpec(TypedDict):
    blocks: List[BlockCommentRule] # 囲むタイプ [("(",")") , ("/*","*/")]など
    line_markers: List[str]        # 行末までのタイプ [ ";" , "//" ]など
    line_start_markers: List[str]  # 必ず先頭にあるタイプ["*"]など
 DIALECTS: Dict[str, DialectSpec] 

制御器名とコメント記法(囲みコメントか単独か)の違いをまとめて定義
DIALECTS[“fanuc”][“blocks”][0].open で、
“fanuc”の”blicks”コメントの始まり文字(open)を参照できる

# test code
a = DIALECTS["osp"]["blocks"][0].open
b = DIALECTS["osp"]["blocks"][0].close
c = DIALECTS["osp"]["blocks"][0].nested
d = DIALECTS["osp"]["blocks"][0].multiline
print(f"open={a} close={b} nested={c} multiline={d}") 

「実行結果」
open=( close=) nested=True multiline=False

 class NcCommentProcessor: 

NCブロックを純粋コードとコメントに分解する

 def _init__(self, dialect: Union[str, Sequence[str]] = “fanuc”): 

引数:dialectに制御器情報を渡すが、複数定義にも対応している
dialect=”fanuc”(文字列1個)と dialect=[“fanuc”,”heidenhain”](リスト)の両方に対応
また、省略定義にも対応
“F”→”fanuc” “O”→”osp” “H”→”heidenhain” “R”→”roeders”

  @property
    def open_comment(self) -> str: 

コメントの始まり記号を返す(@propertyなので、変数のように使える)

 def reset(self) -> None: 

コメントの引き継ぎ状態をリセットする

 def _scan(self, line: str)-> List[Tuple[str, str]]: 

一行のNC文字列を、NCコードとコメントに分解する

 reset_open_block(self): 

別のNCデータを連続で実施する場合、コメントを確実に閉じる

 def parse_code_comment(self, line: str)-> Tuple[str, str]: 

一行NC文字列をNCコードとコメントに分解し、それぞれtupleで返す

# test code
ncblock = [
"G01 X10 Y20 (this is a comment) F100(next",
"next)G02 X30(unterminated comment ;starts here",
]
processor = NcCommentProcessor(dialect="fanuc")

for line in ncblock:
print(f"Original Nc={line!r}")
code, comment = processor.parse_code_comment(line)
print(f"parse_code_comment: code={code!r}, comment={comment!r}")
print(f"-------------------------------")
「実行結果」
Original Nc='G01 X10 Y20 (this is a comment) F100(next'
parse_code_comment: code='G01 X10 Y20 F100', comment='(this is a comment)(next)'
-------------------------------
Original Nc='next)G02 X30(unterminated comment ;starts here'
parse_code_comment: code='G02 X30', comment='(next)(unterminated comment ;starts here)'
-------------------------------

NCコメントプロセッサクラス

実際の、コードです
ただし、コメント行が跨る場合で、意図しない分割になる可能性もあります
NCのコメントは、確実にその行で閉じる処理をすることが安全です

NC分析ライブラリ、記事一覧

コメント

タイトルとURLをコピーしました