まず、if文の構文は、
if(logical) ' ' exp ' ' ELSE ' ' exp
と定義した。(if_statement:L91:pro_mfcalc.y)このプログラムでは、if文の
実行後に、必ず値を返さなければならなかったので、else部のないif文は対象と
しなかった。なお、else ifにも簡単のため、対応していない。
次に、while文の構文は、
while(VAR:変ソ? 比較演算子 exp) ' ' 算術演算子 exp
と定義した。(while_statement:L95:pro_mfcalc.y)単文しか対象としないため、
while文の条件が成立して、loopに入った場合、比較を行った変数が変わらなけ
れば、loopからぬけることがない。
そのため、条件を判定する際に用いた変数に対して、while文の中で演算を行う
ようにした。上記のwhile文は、C言語では、
while(VAR 比較演算子 exp) ' ' VAR =(ASSIGN) VAR 算術演算子 exp
のように書ける。なお、ここでは、条件部には、簡単な比較演算しか入らない。
また、演算子毎に処理を分けるようにしてしまったため、冗長な構文定義になっ
てしまったことが残念だ。
for文の構文は、
fo文の構文は、
for(exp(初期値) ; exp(上限) ; exp(増分)) ' ' VAR 算術演算子 ASSIGN exp
と定義した。(if_statement:L129:pro_mfcalc.y)C言語では、条件をより複雑
にできるのだが、ここでは、簡単のため、初期値を設定し、増分を上限の値にな
るまで加えられる回数だけ、expを繰りかえすようにした。また、繰りかえさ、?
る式は、変数に定数を代入する式などでは、繰りかえしても実行結果が変わらな
く、繰りかえす意味がないと思ったので、ひとつの変数に演算を加えるような式
を対象にした。C言語では、
for(i=初期値;i<上限;i+=増分) ' ' VAR 算術演算子 ASSIGN exp
となる。
それから、関ソ? add_matrix(L399:pro_mfcalc.y),minus_matrix(L428:pro_mfcalc.y), multi_matrix(L452:pro_mfcalc.y)内で、BLASのLevel3の関 数cblas_dgemm(C \rightarrow \alpha op(A)op(B) + \beta C)を呼び出し て、行列の演算結果を導くようにした。ここで、演算結果は、Cに出力さ、? るので、入力にCを用いている場ケ?(add_matrix,minus_matrix)には、入力 の行ホ?Cを複製 (make_matrix(L506:pro_mfcalc.y),cpy_matrix(L525:pro_mfcalc.y))してお いて、演算が終ったら元に戻すようにしておいた。
また、新しく割算の関数divide_matrixを追加した。関ソ? divide_matrix(L465:pro_mfcalc.y)内では、LAPACKの関数dgesv_(Ax=B:x \rightarrow B)が呼び出されている。関数dgesv_は、入力に用いた行ホ? A,Bが書き換えられてしまうので、関数add_matrix,minus_matrixと同様に それらの複製を作成して演算が終ったら元に戻すようにした。
また、課ツ?3で付加した機能、具体的には、ひとつ前の行列演算の履歴をみる機 能、行列の代入機能についても、正しく動作するか確認した。
使用法は、LAPACKの関数を用いる場合には、CLAPACKのlibcblaswr.aを用いて、
gcc /CLAPACK/lapack_arch.a /CLAPACK/libcblaswr.a
/ATLAS/lib/$(MY_ARCH)/libcblas.a
/ATLAS/lib/$(MY_ARCH)/libatlas.a
/CLAPACK/F2CLIBS/libF77.a
でもよいし、LAPACK.txt(ATLAS/doc)に従って、ATLASでLAPACKの関数を完全に扱
えるようにした場合には、
gcc -L$(MY_HOME)/ATLAS/lib/$(MY_ARCH)/ -llapack -lf77blas -lcblas
-latlas
としてもよい。(Fortran77を用いない場合には、-lf77blasは省略可能)
また、BLASSの関数を扱う場合には、
gcc -L$(MY_HOME)/ATLAS/lib/$(MY_ARCH)/ -llapack -ltstatlas -latlas
とすればよい。
r=5 5 t=1 1 if(r==5||t<0) r=1 else r=2 1 if(r==4&&t>0) r=3 else r=4 4 while(r<5) +1 5 for(1;10;2) t+=1 6
/* MATRIXの要素 一時格納場ス?*/ struct matrix_element{ double element; struct matrix_element *right,*down; }; typedef struct matrix_element matrix_element; /* MATRIX */ struct matr{ double *matrix_top; long int wide,leng; }; typedef struct matr matr; /* 記号表のリンクを表すデータ型 */ struct symrec{ char *name; /* 記号の名前 */ int type; /* 記号の種ホ?:VAR,CONSTまたはFNCT,FNCT2 */ union{ double var; /* VAR,CONSTの値 */ double (*fnctptr)(); /* FNCT,FNCT2の値 */ matr *mat; /* MATRIX */ }value; struct symrec *next; }; typedef struct symrec symrec; /* `struct symrec'のリンクである記号表 */ extern symrec *sym_table; symrec *putsym(); symrec *getsym(); symrec *ans; symrec *ANS; matrix_element *init_matrix(double); matrix_element *wide_add_matrix(double,matrix_element*); matrix_element *leng_add_matrix(double,matrix_element*); matrix_element *free_matrix_el(matrix_element*); void matrix_print(matr*); matr *is_matrix(matrix_element*); matr *add_matrix(matr*,matr*); matr *minus_matrix(matr*,matr*); matr *multi_matrix(matr*,matr*); matr *inv_matrix(matr*); matr *cpy_matrix(matr*,matr*); matr *make_matrix(long int,long int); matr *ideal_matrix(long int); matr *add_matrix(matr*,matr*); matr *minus_matrix(matr*,matr*); matr *multi_matrix(matr*,matr*); matr *divide_matrix(matr*,matr*);
%{ #include <math.h> /* 数学関数のた、? */ #include <stdlib.h> #include "pro_calc.h" /* 'symrec'の定義を含、? */ %} %union { double val; /* 数値を返すた、? */ matr *mat; matrix_element *mat_el; symrec *tptr; /* 記号表へのポインタを返す */ } %token <val> NUM /* 単純な倍精度数値 */ %token <tptr> VAR CONST FNCT FNCT2 MA STMA /* 変数と関ソ? */ %token IF ELSE WHILE FOR LP RP LC RC LB RB COMMA ASSIGN EQ NE GT GE LT LE ADD SUB MUL DIV MOD SQ AND OR NOT %type <val> exp bool logical if_statement while_statement for_statement %type <mat> matrix %type <mat_el> matrix_el %right ASSIGN /* '=' */ %left SUB ADD /* '-' '+' */ %left MUL DIV /* '*' '/' */ %left NEG /* 否ト? -- 単項のノ? */ %right SQ MOD /* べきセ?,剰余 */ %left OR %left AND %left NOT %% input: /* カ? */ | input line ; logical: bool {$$=$1;} | logical AND logical {if($1==1.0 && $3==1.0) $$=1.0; else $$=0.0;} | logical OR logical {if($1==1.0 || $3==1.0) $$=1.0; else $$=0.0;} | NOT logical {if($2==1.0) $$=0.0; else $$=1.0;} | LP logical RP {$$=$2;} ; bool: exp EQ exp {if($1==$3) $$=1.0; else $$=0.0;} | exp NE exp {if($1!=$3) $$=1.0; else $$=0.0;} | exp GT exp {if($1>$3) $$=1.0; else $$=0.0;} | exp GE exp {if($1>=$3) $$=1.0; else $$=0.0;} | exp LT exp {if($1<$3) $$=1.0; else $$=0.0;} | exp LE exp {if($1<=$3) $$=1.0; else $$=0.0;} ; line: '\n' | exp '\n' { printf("\t%.10g\n",$1);ans->value.var=$1;} | exp ';''\n' {ans->value.var=$1;} | matrix '\n' {matrix_print($1);ANS->value.mat=$1;} | matrix';''\n'{ANS->value.mat=$1;} | if_statement'\n' {printf("\t%.10g\n",$1);ans->value.var=$1;} | while_statement'\n' {printf("\t%.10g\n",$1);} | for_statement'\n' {printf("\t%.10g\n",$1);} | error '\n' ; matrix: LB matrix_el RB {$$=is_matrix($2);$2=free_matrix_el($2);} | MA {$$=$1->value.mat;} | MA ASSIGN matrix {$$=$3;$1->value.mat=$3;} | STMA {$$=$1->value.mat;} | matrix ADD matrix {$$=add_matrix($1,$3);} | matrix SUB matrix {$$=minus_matrix($1,$3);} | matrix MUL matrix {$$=multi_matrix($1,$3);} | matrix DIV matrix {$$=divide_matrix($1,$3);} ; matrix_el: exp {$$=init_matrix($1);} | matrix_el COMMA exp {$$=wide_add_matrix($3,$1);} | matrix_el ';' exp {$$=leng_add_matrix($3,$1);} ; exp: NUM {$$=$1;} | VAR {$$=$1->value.var;} | VAR ASSIGN exp { $$=$3; $1->value.var=$3;} | FNCT LP exp RP {$$=(*($1->value.fnctptr))($3);} | FNCT2 LP exp COMMA exp RP {$$=(*($1->value.fnctptr))($3,$5);} | exp ADD exp {$$=$1+$3;} | exp SUB exp {$$=$1-$3;} | exp MUL exp {$$=$1*$3;} | exp DIV exp {$$=$1/$3;} | SUB exp %prec NEG { $$=-$2;} | exp SQ exp {$$=pow($1,$3);} | exp MOD exp {$$=fmod($1,$3);} | LP exp RP {$$=$2;} | CONST {$$=$1->value.var;} ; if_statement: IF LP logical RP ' ' exp ' ' ELSE ' ' exp {if($3==1.0) $$=$6; else $$=$10;} ; while_statement: WHILE LP VAR LT exp RP ' ' ADD exp {while($3->value.var<$5) $3->value.var+=$9; $$=$3->value.var;} | WHILE LP VAR LT exp RP ' ' SUB exp {while($3->value.var<$5) $3->value.var-=$9; $$=$3->value.var;} | WHILE LP VAR LT exp RP ' ' MUL exp {while($3->value.var<$5) $3->value.var*=$9; $$=$3->value.var;} | WHILE LP VAR LT exp RP ' ' DIV exp {while($3->value.var<$5) $3->value.var/=$9; $$=$3->value.var;} | WHILE LP VAR LE exp RP ' ' ADD exp {while($3->value.var<=$5) $3->value.var+=$9; $$=$3->value.var;} | WHILE LP VAR LE exp RP ' ' SUB exp {while($3->value.var<=$5) $3->value.var-=$9; $$=$3->value.var;} | WHILE LP VAR LE exp RP ' ' MUL exp {while($3->value.var<=$5) $3->value.var*=$9; $$=$3->value.var;} | WHILE LP VAR LE exp RP ' ' DIV exp {while($3->value.var<=$5) $3->value.var/=$9; $$=$3->value.var;} | WHILE LP VAR GT exp RP ' ' ADD exp {while($3->value.var>$5) $3->value.var+=$9; $$=$3->value.var;} | WHILE LP VAR GT exp RP ' ' SUB exp {while($3->value.var>$5) $3->value.var-=$9; $$=$3->value.var;} | WHILE LP VAR GT exp RP ' ' MUL exp {while($3->value.var>$5) $3->value.var*=$9; $$=$3->value.var;} | WHILE LP VAR GT exp RP ' ' DIV exp {while($3->value.var>$5) $3->value.var/=$9; $$=$3->value.var;} | WHILE LP VAR GE exp RP ' ' ADD exp {while($3->value.var>=$5) $3->value.var+=$9; $$=$3->value.var;} | WHILE LP VAR GE exp RP ' ' SUB exp {while($3->value.var>=$5) $3->value.var-=$9; $$=$3->value.var;} | WHILE LP VAR GE exp RP ' ' MUL exp {while($3->value.var>=$5) $3->value.var*=$9; $$=$3->value.var;} | WHILE LP VAR GE exp RP ' ' DIV exp {while($3->value.var>=$5) $3->value.var/=$9; $$=$3->value.var;} ; for_statement: FOR LP exp ';' exp ';' exp RP ' ' VAR ADD ASSIGN exp {int i; for(i=$3;i<$5;i+=$7) $10->value.var+=$13; $$=$10->value.var;} | FOR LP exp ';' exp ';' exp RP ' ' VAR SUB ASSIGN exp {int i; for(i=$3;i<$5;i+=$7) $10->value.var-=$13; $$=$10->value.var;} | FOR LP exp ';' exp ';' exp RP ' ' VAR MUL ASSIGN exp {int i; for(i=$3;i<$5;i+=$7) $10->value.var*=$13; $$=$10->value.var;} | FOR LP exp ';' exp ';' exp RP ' ' VAR DIV ASSIGN exp {int i; for(i=$3;i<$5;i+=$7) $10->value.var/=$13; $$=$10->value.var;} ; %% #include <stdio.h> main(){ init_table(); yyparse(); } yyerror(s) /* エラーがあるとyyparseから呼び出され、? */ char *s; { printf("%s\n",s); } struct init{ char *fname; double (*fnct)(); }; struct init arith_fncts[] ={ "sin",sin, "cos",cos, "atan",atan, "ln",log, "exp",exp, "sqrt",sqrt, "acos",acos, "asin",asin, "cosh",cosh, "sinh",sinh, "tanh",tanh, "log",log10, "ceil",ceil, "fabs",fabs, "floor",floor, 0,0 }; struct init arith_functs2[] ={ "atan2",atan2, 0,0 }; struct init_const{ char *vname; double value; }; struct init_const arith_const[] ={ "pi",3.14, 0,0 }; /* 記号表 : `struct symrec'のリスト */ symrec *sym_table=(symrec *)0; init_table(){ /* 数学関数を表にす、? */ int i; symrec *ptr; ans=putsym("ans",CONST); ANS=putsym("ANS",STMA); for(i=0;arith_fncts[i].fname!=0;i++){ ptr=putsym(arith_fncts[i].fname,FNCT); ptr->value.fnctptr=arith_fncts[i].fnct; } for(i=0;arith_functs2[i].fname!=0;i++){ ptr=putsym(arith_functs2[i].fname,FNCT2); ptr->value.fnctptr=arith_functs2[i].fnct; } for(i=0;arith_const[i].vname!=0;i++){ ptr=putsym(arith_const[i].vname,CONST); ptr->value.var=arith_const[i].value; } } symrec * putsym(sym_name,sym_type) char *sym_name; int sym_type; { symrec *ptr; ptr=(symrec *)malloc(sizeof(symrec)); ptr->name=(char*)malloc(strlen(sym_name)+1); strcpy(ptr->name,sym_name); ptr->type=sym_type; ptr->value.var=0; /* 関数の場合にも値0にす、? */ ptr->next=(struct symrec *)sym_table; sym_table=ptr; return ptr; } symrec *getsym(sym_name) char *sym_name; { symrec *ptr; for(ptr=sym_table;ptr!=(symrec *)0;ptr=(symrec *)ptr->next) if(strcmp(ptr->name,sym_name)==0) return ptr; return 0; } matrix_element *init_matrix(double el){ matrix_element *root; if((root=(matrix_element*)malloc(sizeof(matrix_element)))==NULL){ printf("memory_error\n"); } else{ root->element=el; root->right=NULL; root->down=NULL; } return root; } matr *init_matr(matrix_element *root,long int wide,long int leng){ matr *r; matrix_element *s,*t; int n=0; r=make_matrix(wide,leng); if(r==NULL) return NULL; else{ t=root; while(t!=NULL){ s=t; while(s!=NULL){ r->matrix_top[n]=s->element; s=s->down; n++; } t=t->right; } } return r; } matrix_element *wide_add_matrix(double el,matrix_element *root){ matrix_element *wide,*t,*s=NULL; wide=init_matrix(el); if(wide!=NULL){ t=root; while(t->down!=NULL){ s=t; t=t->down; } while(t->right!=NULL){ t=t->right; if(s!=NULL){ if(s->right!=NULL){ s=s->right; } else return NULL; } } t->right=wide; if(s!=NULL){ if(s->right!=NULL){ s=s->right; s->down=wide; } else return NULL; } return root; } else return NULL; } matrix_element *leng_add_matrix(double el,matrix_element *root){ matrix_element *leng,*t; leng=init_matrix(el); if(leng!=NULL){ t=root; while(t->down!=NULL){ t=t->down; } t->down=leng; return root; } else return NULL; } matr *is_matrix(matrix_element *root){ matr *r; matrix_element *t,*s; long int n=0,m,l=0; /* matrixになっていることの確認,matrixの列数n,行数l */ if(root==NULL){ return NULL; } else{ t=root; l++; while(t!=NULL){ n++; t=t->right; } s=root->down; while(s!=NULL){ t=s; l++; m=0; while(t!=NULL){ m++; t=t->right; } if(n!=m) return NULL; s=s->down; } r=init_matr(root,n,l); return r; } } matrix_element *free_matrix_el(matrix_element *root){ matrix_element *t,*s,*w; t=s=root; while(t!=root){ t=t->down; while(s!=root){ w=s; s=s->right; free(w); } s=t; } return NULL; } void matrix_print(matr *root){ long int i,j; if(root==NULL){ printf("no matrix\n"); } else{ for(i=0;i<root->leng;i++){ for(j=0;j<root->wide;j++){ printf("\t%.10g",root->matrix_top[i+j*root->leng]); } printf("\n"); } } } matr *add_matrix(matr *A,matr *C){ matr *B,*C_COPY,*ANSI; if(A->wide!=C->wide || A->leng!=C->leng) return NULL; B=ideal_matrix(A->wide); C_COPY=make_matrix(C->wide,C->leng); ANSI=make_matrix(B->wide,A->leng); if(B==NULL || C_COPY==NULL || ANSI==NULL){ printf("memory_error\n"); return NULL; } C_COPY=cpy_matrix(C,C_COPY); /* cblas_dgemm(const enum CBLAS_ORDER Order,const enum CBLAS_TRANSPOSE Trans A,const enum CBLAS_TRANSPOSE TransB,const int M,const int N,const int K,const SCALAR alpha,const TYPE *A,const int lda,const TYPE *B,const int ldb,const SCALAR beta,TYPE *C,const ind ldc) */ /* CblasColMajor=102,CblasNoTrrans=111 */ cblas_dgemm(102,111,111,(int)A->leng,(int)B->wide,(int)A->wide,1.0,A->matrix_top,(int)A->leng,B->matrix_top,(int)B->leng,1.0,C->matrix_top,(int)C->leng); ANSI=cpy_matrix(C,ANSI); C=cpy_matrix(C_COPY,C); free(B->matrix_top); free(C_COPY->matrix_top); free(B); free(C_COPY); return ANSI; } matr *minus_matrix(matr *A,matr *C){ matr *B,*C_COPY,*ANSI; if(A->wide!=C->wide || A->leng!=C->leng) return NULL; B=ideal_matrix(A->wide); C_COPY=make_matrix(C->wide,C->leng); ANSI=make_matrix(B->wide,A->leng); if(B==NULL || C_COPY==NULL || ANSI==NULL) return NULL; C_COPY=cpy_matrix(C,C_COPY); cblas_dgemm(102,111,111,(int)A->leng,(int)B->wide,(int)A->wide,1.0,A->matrix_top,(int)A->leng,B->matrix_top,(int)B->leng,-1.0,C->matrix_top,(int)C->leng); ANSI=cpy_matrix(C,ANSI); C=cpy_matrix(C_COPY,C); free(B->matrix_top); free(C_COPY->matrix_top); free(B); free(C_COPY); return ANSI; } matr *multi_matrix(matr *A,matr *B){ matr *C; if(A->wide!=B->leng) return NULL; C=make_matrix(B->wide,A->leng); if(C==NULL) return NULL; cblas_dgemm(102,111,111,(int)A->leng,(int)B->wide,(int)A->wide,1.0,A->matrix_top,(int)A->leng,B->matrix_top,(int)B->leng,0.0,C->matrix_top,(int)C->leng); return C; } matr *divide_matrix(matr *A,matr *B){ long int piv[B->leng],info; matr *A_COPY,*B_COPY,*ANSI; if(B->leng!=1) return NULL; A_COPY=make_matrix(A->wide,A->leng); B_COPY=make_matrix(B->wide,B->leng); ANSI=make_matrix(B->wide,B->leng); if(A_COPY==NULL || B_COPY==NULL || ANSI==NULL) return NULL; A_COPY=cpy_matrix(A,A_COPY); B_COPY=cpy_matrix(B,B_COPY); dgesv_(&A->leng,&B->wide,A->matrix_top,&A->leng,piv,B->matrix_top,&B->leng,&info); if(info!=0) return NULL; ANSI=cpy_matrix(B,ANSI); A=cpy_matrix(A_COPY,A); B=cpy_matrix(B_COPY,B); return ANSI; } matr *ideal_matrix(long int size){ matr *Ideal; long int i,j; Ideal=make_matrix(size,size); if(Ideal==NULL) return NULL; for(i=0;i<size;i++){ for(j=0;j<size;j++){ if(i==j) Ideal->matrix_top[i+j*size]=1.0; else Ideal->matrix_top[i+j*size]=0.0; } } return Ideal; } matr *make_matrix(long int wide,long int leng){ matr *A; if((A=(matr*)malloc(sizeof(matr)))==NULL){ printf("memory error\n"); return NULL; } if((A->matrix_top=(double*)calloc(wide*leng,sizeof(double)))==NULL){ printf("memory_error\n"); return NULL; } A->leng=leng; A->wide=wide; return A; } matr *cpy_matrix(matr *A,matr *B){ long int i; if(A==NULL || B==NULL) return NULL; for(i=0;i<A->wide*A->leng;i++){ B->matrix_top[i]=A->matrix_top[i]; } return B; }
%{ #include "pro_calc.h" #include "pro_mfcalc.tab.h" %} %% "if" return IF; "else" return ELSE; "while" return WHILE; "for" return FOR; "(" return LP; ")" return RP; "{" return LC; "}" return RC; "[" return LB; "]" return RB; "," return COMMA; "=" return ASSIGN; "==" return EQ; "!=" return NE; ">" return GT; ">=" return GE; "<" return LT; "<=" return LE; "!" return NOT; "&&" return AND; "||" return OR; "+" return ADD; "-" return SUB; "*" return MUL; "/" return DIV; "%" return MOD; "^" return SQ; [1-9]*[0-9]+\.?[0-9]* { sscanf(yytext,"%lf",&(yylval.val)); return NUM; } [a-z][a-zA-Z_0-9]* { symrec* s; s=getsym(yytext); if(s==NULL) s=putsym(yytext,VAR); yylval.tptr=s; return s->type; } [A-Z][a-zA-Z_0-9]* { symrec* s; s=getsym(yytext); s=getsym(yytext); if(s==NULL) s=putsym(yytext,MA); yylval.tptr=s; return s->type; } [^\t0-9a-zA-Z] return yytext[0]; %%