まず、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];
%%