Ian Jauslin
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c274
1 files changed, 274 insertions, 0 deletions
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..9c4801a
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,274 @@
+/*
+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 <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+// define MPFR_USE_VA_LIST to enable the use of mpfr_inits and mpfr_clears
+#define MPFR_USE_VA_LIST
+#include <mpfr.h>
+
+// 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)<abs(t1)
+ mpfr_inits(tmp, tmp2, NULL);
+ mpfr_abs(tmp, params->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);
+}
+