コラム
2025/07/31
プログラミングについて 第114回目
『テキストファイルを読み込む その2』
私の会社はプリント基板のパターン設計を行なうことを主としているので、得意先から回路の接続データ(ネットリスト)を支給してもらって使用しています。このネットリストがなかなかの曲者で、嬉しいくらいに多くのフォーマットがあるのです。ちょっとそれらの例を紹介しましょう。
例1
1000[R64-1,U7-57,R65-2]
1001[L2-2,P3-2,P3-34,P3-66,P3-7,
P3-39,P3-71,P3-12,P3-44,P3-76,
P3-17,P3-49,P3-81,P3-22,P3-54,
P3-86,P3-25,P3-57,P3-89,P3-31,
P3-63,P3-95]
例2
$NET_LIST [ MM ] {
comp { /* test data */
TB201[]={TB2P ,T, 503.000, 69.500, 270.0};
TB202[]={TB2P ,T, 503.000, 72.500, 270.0};
:
:
P401 []={8931E68 ,T, 360.000, 59.900, 180.0};
P451 []={8931E68 ,T, 290.000, 59.900, 180.0};
}
nets {
GND ={P621 - 1,P621 - 2,P621 - 5,P621 - 6,P621 - 9,
P621 - 10,P621 - 17,P621 - 18,P621 - 19,P621 - 20,
P621 - 21,P621 - 22,P622 - 1,P622 - 2,P622 - 5,
:
:
P401 - 2,P401 - 1,P451 - 8,P451 - 10,P451 - 9,
P451 - 1,P451 - 5,P451 - 6,P451 - 4,P451 - 2};
1002 ={P237 -124,P655 - 98};
1003 ={P237 - 33,P655 - 96};
:
:
AQD21 ={P216 - 79,P224 -175};
AQD22 ={P218 - 79,P226 -175};
}
}
例3
$CCF {
DEFINITION {
UMV1C470MFH:C2,C3,C6,C7,C10,C11,C14,C15,C403,C404,C423,C424
,C508;
GL3ED8:CD110;
:
:
J10ET250LA:DL201;
}
NET {
NET2:FL401(6),R460(2),R459(2);
NET3:IC451(6),R433(2);
+10V:C3(1),C14(1),IC2(3),C4(2),C13(2),CD2(4),CD2(5),CD2(6)
,FL1(3),L401(1),L421(1);
:
:
NET248:IC3(4),R2(1);
NET249:CD2(1),R2(2);
}
}
例4
(EDIF D_BARCIRBARCDJ1815_SCH
(joined
(qualify X101 P_2)
(qualify C102 P_2)
(qualify IC101 P_001)
)
:
:
(joined
(qualify IC101 P_063)
UCLK
(qualify IC105 P_193)
)
)
あまり例ばかり紹介するとこれだけで今回の話しが終わってしまいそうなのでこのくらいにしましょう。単純なリスト形式のもの、C言語風のもの、LISP風のものと千差万別なのです。
基板のパターン設計を行なうのが目的ですので、使用するCADシステムのネットリストの書式に変換をしなければなりません。当然のことですが、初めて出会う書式のネットリストのときにはプログラムを書かなければなりません。それものんびり一日もかけてやっていたのでは仕事になりませんので、書式にもよりますが30分から3時間程度の時間でプログラムを書き上げてフォーマットの変換を行なっています。プログラムは出力部分は同じ書式なので共通に使えますので、読み込みの部分を作る訳です。
例1の場合は簡単な方ですが、例2、3、4の場合になると簡単にはいきません。データがブロック構造になっている上、コメントまであるのでそれを正しく処理していかなければならないのです。例2と例3はC言語風で似ているのですが、よく見ると、例2では、
TB202[]={TB2P ,T, 503.000, 72.500, 270.0};
というように } の後にセミコロンがあり、例3では、
NET2:FL401(6),R460(2),R459(2);
というように { .. } の内側のものにセミコロンが付いています。
よくもまあこれだけ色々な書式を考えるものだと感心させられます。今回は例1を読み込む(各要素を表示する)ことを考えてみます。例1は、
1000[R64-1,U7-57,R65-2]
1001[L2-2,P3-2,P3-34,P3-66,P3-7,
P3-39,P3-71,P3-12,P3-44,P3-76,
P3-17,P3-49,P3-81,P3-22,P3-54,
P3-86,P3-25,P3-57,P3-89,P3-31,
P3-63,P3-95]
となっていて各行は必ずコンマかカッコで終わっていますので、行単位に読み込んで処理しても良さそうです。またこの書式の要素の意味は、
1000[R64-1,U7-57,R65-2]
| | |
| |ピン番号
| 部品番号
信号名称または信号番号
となっています。信号名称と [ から ] までが1つのデータの集まりです。電気に詳しくない方にはあまり聞き慣れない言葉ですがあまり気にしないで下さい。とにかくこれをプログラムにしてみました。
#include <stdio.h>
main()
{
FILE *fp;
char data[513],*ss,*se,*kind;
fp=fopen("sample1.net","r");
while(fgets(data,sizeof(data),fp)){
kind=NULL;
ss=se=data;
while(*se){
if(*se=='[' )kind="Net name=";
else if(*se=='-' )kind="Parts=";
else if(*se==',' || *se==']')kind="Pin=";
if(kind){
*se='\0';
printf("%s %s\n",kind,ss);
kind=NULL;
ss=se+1;
}
se++;
}
}
fclose(fp);
}
プログラムは非常に短いものです。1行ずつ読み込んで、それぞれの行の文字を順に調べていき、キーになる文字 [,-] のときに各項目を表示するということを行なっています。じっくり見れば理解できると思います。
例1の書式が行儀正しいのでこのような単純な書き方ができますが、次のように途中に無駄なスペースがあったり、項目の途中で改行しているときには上のプログラムではうまくいきません。
10 0 0[ R6 4-1,U7-57,R65- 2]1001[L2-2,P3-2, P3-34,P3-6
6,P3-7, P3-39,P3-71,P3-12,P3-44,P3-76,
P3-17,P3-49,P3-81,P3-22,P3-54, P3-86,P
3-25,P3-57,P3-89,P3-31,
P3-63,P3
-95
]
実際にはこんな行儀の悪いデータというのは殆ど出会うことはありませんが、こういうときでも上のプログラムと同じ結果を出すプログラムを作ってみましょう。
#include <stdio.h>
main()
{
FILE *fp;
char data[81],*s,*kind;
int c;
fp=fopen("sample1.net","r");
s=data;
kind=NULL;
while((c=fgetc(fp))!=EOF){
if(c==' ' || c=='\t' || c=='\n')continue;
if(c=='[' )kind="Net name=";
else if(c=='-' )kind="Parts=";
else if(c==',' || *se==']')kind="Pin=";
if(kind){
*s='\0';
printf("%s %s\n",kind,data);
s=data;
kind=NULL;
}
else{
*s++ =c;
}
}
fclose(fp);
}
と、こんな風に1文字ずつ読み込んで処理していきます。扱ったデータの書式が単純でしたので、この書き方でも充分実用になりますが複雑なものになるともう少し工夫しなければなりません。
それではまた次回。
第114回 プログラミングについて『テキストファイルを読み込む その2』

プログラミングについて 第114回目
『テキストファイルを読み込む その2』
私の会社はプリント基板のパターン設計を行なうことを主としているので、得意先から回路の接続データ(ネットリスト)を支給してもらって使用しています。このネットリストがなかなかの曲者で、嬉しいくらいに多くのフォーマットがあるのです。ちょっとそれらの例を紹介しましょう。
例1
1000[R64-1,U7-57,R65-2]
1001[L2-2,P3-2,P3-34,P3-66,P3-7,
P3-39,P3-71,P3-12,P3-44,P3-76,
P3-17,P3-49,P3-81,P3-22,P3-54,
P3-86,P3-25,P3-57,P3-89,P3-31,
P3-63,P3-95]
例2
$NET_LIST [ MM ] {
comp { /* test data */
TB201[]={TB2P ,T, 503.000, 69.500, 270.0};
TB202[]={TB2P ,T, 503.000, 72.500, 270.0};
:
:
P401 []={8931E68 ,T, 360.000, 59.900, 180.0};
P451 []={8931E68 ,T, 290.000, 59.900, 180.0};
}
nets {
GND ={P621 - 1,P621 - 2,P621 - 5,P621 - 6,P621 - 9,
P621 - 10,P621 - 17,P621 - 18,P621 - 19,P621 - 20,
P621 - 21,P621 - 22,P622 - 1,P622 - 2,P622 - 5,
:
:
P401 - 2,P401 - 1,P451 - 8,P451 - 10,P451 - 9,
P451 - 1,P451 - 5,P451 - 6,P451 - 4,P451 - 2};
1002 ={P237 -124,P655 - 98};
1003 ={P237 - 33,P655 - 96};
:
:
AQD21 ={P216 - 79,P224 -175};
AQD22 ={P218 - 79,P226 -175};
}
}
例3
$CCF {
DEFINITION {
UMV1C470MFH:C2,C3,C6,C7,C10,C11,C14,C15,C403,C404,C423,C424
,C508;
GL3ED8:CD110;
:
:
J10ET250LA:DL201;
}
NET {
NET2:FL401(6),R460(2),R459(2);
NET3:IC451(6),R433(2);
+10V:C3(1),C14(1),IC2(3),C4(2),C13(2),CD2(4),CD2(5),CD2(6)
,FL1(3),L401(1),L421(1);
:
:
NET248:IC3(4),R2(1);
NET249:CD2(1),R2(2);
}
}
例4
(EDIF D_BARCIRBARCDJ1815_SCH
(joined
(qualify X101 P_2)
(qualify C102 P_2)
(qualify IC101 P_001)
)
:
:
(joined
(qualify IC101 P_063)
UCLK
(qualify IC105 P_193)
)
)
あまり例ばかり紹介するとこれだけで今回の話しが終わってしまいそうなのでこのくらいにしましょう。単純なリスト形式のもの、C言語風のもの、LISP風のものと千差万別なのです。
基板のパターン設計を行なうのが目的ですので、使用するCADシステムのネットリストの書式に変換をしなければなりません。当然のことですが、初めて出会う書式のネットリストのときにはプログラムを書かなければなりません。それものんびり一日もかけてやっていたのでは仕事になりませんので、書式にもよりますが30分から3時間程度の時間でプログラムを書き上げてフォーマットの変換を行なっています。プログラムは出力部分は同じ書式なので共通に使えますので、読み込みの部分を作る訳です。
例1の場合は簡単な方ですが、例2、3、4の場合になると簡単にはいきません。データがブロック構造になっている上、コメントまであるのでそれを正しく処理していかなければならないのです。例2と例3はC言語風で似ているのですが、よく見ると、例2では、
TB202[]={TB2P ,T, 503.000, 72.500, 270.0};
というように } の後にセミコロンがあり、例3では、
NET2:FL401(6),R460(2),R459(2);
というように { .. } の内側のものにセミコロンが付いています。
よくもまあこれだけ色々な書式を考えるものだと感心させられます。今回は例1を読み込む(各要素を表示する)ことを考えてみます。例1は、
1000[R64-1,U7-57,R65-2]
1001[L2-2,P3-2,P3-34,P3-66,P3-7,
P3-39,P3-71,P3-12,P3-44,P3-76,
P3-17,P3-49,P3-81,P3-22,P3-54,
P3-86,P3-25,P3-57,P3-89,P3-31,
P3-63,P3-95]
となっていて各行は必ずコンマかカッコで終わっていますので、行単位に読み込んで処理しても良さそうです。またこの書式の要素の意味は、
1000[R64-1,U7-57,R65-2]
| | |
| |ピン番号
| 部品番号
信号名称または信号番号
となっています。信号名称と [ から ] までが1つのデータの集まりです。電気に詳しくない方にはあまり聞き慣れない言葉ですがあまり気にしないで下さい。とにかくこれをプログラムにしてみました。
#include <stdio.h>
main()
{
FILE *fp;
char data[513],*ss,*se,*kind;
fp=fopen("sample1.net","r");
while(fgets(data,sizeof(data),fp)){
kind=NULL;
ss=se=data;
while(*se){
if(*se=='[' )kind="Net name=";
else if(*se=='-' )kind="Parts=";
else if(*se==',' || *se==']')kind="Pin=";
if(kind){
*se='\0';
printf("%s %s\n",kind,ss);
kind=NULL;
ss=se+1;
}
se++;
}
}
fclose(fp);
}
プログラムは非常に短いものです。1行ずつ読み込んで、それぞれの行の文字を順に調べていき、キーになる文字 [,-] のときに各項目を表示するということを行なっています。じっくり見れば理解できると思います。
例1の書式が行儀正しいのでこのような単純な書き方ができますが、次のように途中に無駄なスペースがあったり、項目の途中で改行しているときには上のプログラムではうまくいきません。
10 0 0[ R6 4-1,U7-57,R65- 2]1001[L2-2,P3-2, P3-34,P3-6
6,P3-7, P3-39,P3-71,P3-12,P3-44,P3-76,
P3-17,P3-49,P3-81,P3-22,P3-54, P3-86,P
3-25,P3-57,P3-89,P3-31,
P3-63,P3
-95
]
実際にはこんな行儀の悪いデータというのは殆ど出会うことはありませんが、こういうときでも上のプログラムと同じ結果を出すプログラムを作ってみましょう。
#include <stdio.h>
main()
{
FILE *fp;
char data[81],*s,*kind;
int c;
fp=fopen("sample1.net","r");
s=data;
kind=NULL;
while((c=fgetc(fp))!=EOF){
if(c==' ' || c=='\t' || c=='\n')continue;
if(c=='[' )kind="Net name=";
else if(c=='-' )kind="Parts=";
else if(c==',' || *se==']')kind="Pin=";
if(kind){
*s='\0';
printf("%s %s\n",kind,data);
s=data;
kind=NULL;
}
else{
*s++ =c;
}
}
fclose(fp);
}
と、こんな風に1文字ずつ読み込んで処理していきます。扱ったデータの書式が単純でしたので、この書き方でも充分実用になりますが複雑なものになるともう少し工夫しなければなりません。
それではまた次回。