/* Copyright 2016 Ian Jauslin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "parser.h" #include #include #include // define MPFR_USE_VA_LIST to enable the use of mpfr_inits and mpfr_clears #define MPFR_USE_VA_LIST #include // read parameter string #define P_VAR_T1 1 #define P_VAR_T2 2 #define P_VAR_LAMBDA 3 #define P_VAR_OMEGA 4 #define P_VAR_SINPHI 5 #define P_VAR_W 6 #define P_VAR_PHI 7 int read_params(hh_params* params, char* str){ char* ptr; char* buffer; char* buffer_ptr; int ret; int var_flag=0; unsigned int reset_W=0; unsigned int set_phi=0; unsigned int set_sinphi=0; mpfr_t tmp, tmp2; buffer=calloc(str_len(str), sizeof(char)); buffer_ptr=buffer; *buffer_ptr='\0'; for(ptr=str; *ptr!='\0'; ptr++){ switch(*ptr){ // left side of equation case '=': if(str_cmp(buffer, "t1")==1){ var_flag=P_VAR_T1; } else if(str_cmp(buffer, "t2")==1){ var_flag=P_VAR_T2; } else if(str_cmp(buffer, "lambda")==1){ var_flag=P_VAR_LAMBDA; } else if(str_cmp(buffer, "omega")==1){ var_flag=P_VAR_OMEGA; } else if(str_cmp(buffer, "sinphi")==1){ var_flag=P_VAR_SINPHI; // reset W to -3*omega*sqrt(3)*sin(phi) provided W is not set explicitly if(reset_W==0){ reset_W=1; } // do not allow setting both sinphi and phi set_sinphi=1; } else if(str_cmp(buffer, "phi")==1){ var_flag=P_VAR_PHI; // reset W to -3*omega*sqrt(3)*sin(phi) provided W is not set explicitly if(reset_W==0){ reset_W=1; } // do not allow setting both sinphi and phi set_phi=1; } else if(str_cmp(buffer, "W")==1){ var_flag=P_VAR_W; // do not reset W reset_W=2; } else{ fprintf(stderr, "parsing error: unrecognized token '%s'\n", buffer); free(buffer); return(-1); } // reset buffer buffer_ptr=buffer; *buffer_ptr='\0'; break; // assign value case ';': if(var_flag==P_VAR_T1){ ret=mpfr_set_str(params->t1, buffer, 10, MPFR_RNDN); if(ret<0){ fprintf(stderr, "parsing error: t1 must be assigned to an MPFR floating point number\n got '%s'\n", buffer); free(buffer); return(-1); } } else if(var_flag==P_VAR_T2){ ret=mpfr_set_str(params->t2, buffer, 10, MPFR_RNDN); if(ret<0){ fprintf(stderr, "parsing error: t2 must be assigned to an MPFR floating point number\n got '%s'\n", buffer); free(buffer); return(-1); } } else if(var_flag==P_VAR_LAMBDA){ ret=mpfr_set_str(params->lambda, buffer, 10, MPFR_RNDN); if(ret<0){ fprintf(stderr, "parsing error: lambda must be assigned to an MPFR floating point number\n got '%s'\n", buffer); free(buffer); return(-1); } } else if(var_flag==P_VAR_SINPHI){ if(set_phi==1){ fprintf(stderr, "error: cannot set both phi and sinphi\n"); free(buffer); return(-1); } ret=mpfr_set_str(params->sinphi, buffer, 10, MPFR_RNDN); if(ret<0){ fprintf(stderr, "parsing error: sinphi must be assigned to an MPFR floating point number\n got '%s'\n", buffer); free(buffer); return(-1); } // check value if(mpfr_cmp_ui(params->sinphi,1)>0 || mpfr_cmp_si(params->sinphi,-1)<0){ fprintf(stderr, "error: sinphi must be in [-1,1]\n"); free(buffer); return(-1); } // set phi mpfr_asin(params->phi, params->sinphi, MPFR_RNDN); } else if(var_flag==P_VAR_PHI){ if(set_sinphi==1){ fprintf(stderr, "error: cannot set both phi and sinphi\n"); free(buffer); return(-1); } ret=mpfr_set_str(params->phi, buffer, 10, MPFR_RNDN); if(ret<0){ fprintf(stderr, "parsing error: phi must be assigned to an MPFR floating point number\n got '%s'\n", buffer); free(buffer); return(-1); } // set sinphi mpfr_sin(params->sinphi, params->phi, MPFR_RNDN); } else if(var_flag==P_VAR_W){ ret=mpfr_set_str(params->W, buffer, 10, MPFR_RNDN); if(ret<0){ fprintf(stderr, "parsing error: W must be assigned to an MPFR floating point number\n got '%s'\n", buffer); free(buffer); return(-1); } } else if(var_flag==P_VAR_OMEGA){ ret=sscanf(buffer, "%d", &(params->omega)); if(ret!=1){ fprintf(stderr, "parsing error: omega must be assigned to an integer\n got '%s'\n", buffer); free(buffer); return(-1); } // check value if(params->omega!=1 && params->omega!=-1){ fprintf(stderr, "error: omega must be either +1 or -1\n"); return(-1); } } else{ fprintf(stderr, "parsing error: read right side of equation, but the matching token was not found\n"); free(buffer); return(-1); } var_flag=0; // reset buffer buffer_ptr=buffer; *buffer_ptr='\0'; break; // add to buffer default: buffer_ptr=str_addchar(buffer_ptr, *ptr); break; } } // check that all variables were read if(*buffer_ptr!='\0'){ fprintf(stderr, "parsing error: trailing characters: '%s'\n", buffer); free(buffer); return(-1); } if(var_flag!=0){ fprintf(stderr, "parsing error: empty assignment at the end of the string\n"); free(buffer); return(-1); } // check that 3*abs(t2)t2, MPFR_RNDN); mpfr_mul_ui(tmp, tmp, 3, MPFR_RNDN); mpfr_abs(tmp2, params->t1, MPFR_RNDN); if(mpfr_cmp(tmp, tmp2)>0){ fprintf(stderr, "error: |t2| must be smaller than |t1|/3\n"); return(-1); } // if W was not set, reset its default to -3*omega*sqrt(3)*t2*sin(phi) if(reset_W==1){ mpfr_sqrt_ui(params->W, 3, MPFR_RNDN); mpfr_mul_ui(params->W, params->W, 3, MPFR_RNDN); mpfr_mul(params->W, params->W, params->sinphi, MPFR_RNDN); mpfr_mul(params->W, params->W, params->t2, MPFR_RNDN); if(params->omega==1){ mpfr_neg(params->W, params->W, MPFR_RNDN); } } mpfr_clears(tmp, tmp2, NULL); free(buffer); return(0); } // length of a string int str_len(char* str){ char* ptr=str; int ret=0; while(*ptr!='\0'){ret++;ptr++;} return(ret); } // compare strings int str_cmp(char* str1, char* str2){ char* ptr1=str1; char* ptr2=str2; while(*ptr1==*ptr2 && *ptr1!='\0' && *ptr2!='\0'){ ptr1++; ptr2++; } if(*ptr1=='\0' && *ptr2=='\0'){ return(1); } else{ return(0); } } // append a character to the end of a string at the location pointed at by 'ptr' char* str_addchar(char* ptr, const char c){ *ptr=c; ptr++; *ptr='\0'; return(ptr); }