11! =============================================================================
22! expression parser utility --
33! for parsing simple linear mathematical expressions of the form
4- ! X = a*Y + b*Z + ...
4+ ! X = a*R + b*S + c*(X + Y + Z) ...
55!
66! =============================================================================
77module shr_expr_parser_mod
88 use shr_kind_mod,only : r8 = > shr_kind_r8
9- use shr_kind_mod,only : cx = > shr_kind_cx
9+ use shr_kind_mod,only : CXX = > shr_kind_cxx
1010
1111 implicit none
1212 private
@@ -35,82 +35,122 @@ function shr_exp_parse( exp_array, nitems ) result(exp_items_list)
3535 integer , optional , intent (out ) :: nitems ! number of expressions parsed
3636 type (shr_exp_item_t), pointer :: exp_items_list ! linked list of items returned
3737
38- integer :: i,j, jj, nmax, nterms, n_exp_items
39- character (len= cx) :: tmp_str
38+ integer :: i,j, n_exp_items
4039 type (shr_exp_item_t), pointer :: exp_item, list_item
40+ integer :: ndxs(512 )
41+ integer :: nelem, j1,j2,k
42+ character (len= CXX) :: tmp_str, tmp_name
43+ character (len= 8 ) :: xchr ! multipler
44+ real (r8 ) :: xdbl
45+ real (r8 ) :: coeff0
46+ logical :: more_to_come
47+ character (len= CXX), allocatable :: sums_grps(:)
48+ character (len= CXX) :: sum_string
49+
50+ allocate (sums_grps(size (exp_array)))
4151
4252 nullify( exp_items_list )
4353 nullify( exp_item )
4454 nullify( list_item )
4555
46- n_exp_items = 0
47- nmax = size ( exp_array )
56+ sums_grps(:) = ' '
4857
49- do i = 1 ,nmax
50- if (len_trim (exp_array(i))>0 ) then
58+ ! combine lines that have a trailing "+" with the next line
59+ i= 1
60+ j= 1
61+ loop1: do while ( len_trim (exp_array(i)) > 0 )
5162
52- j = scan ( exp_array(i), ' =' )
63+ k = scan (exp_array(i), ' +' , back= .true. )
64+ more_to_come = k == len_trim (exp_array(i)) ! line ends with "+"
5365
54- if ( j> 0 ) then
66+ if ( more_to_come ) then
67+ sums_grps(j) = trim (sums_grps(j)) // trim (adjustl (exp_array(i)))
68+ else
69+ sums_grps(j) = trim (sums_grps(j)) // trim (adjustl (exp_array(i)))
70+ j = j+1
71+ endif
72+
73+ i = i+1
74+ if ( i > size (exp_array) ) exit loop1
5575
56- n_exp_items = n_exp_items + 1
76+ end do loop1
5777
58- allocate ( exp_item )
59- exp_item% n_terms = 0
60- exp_item% name = trim (adjustl (exp_array(i)(:j-1 )))
78+ n_exp_items = j-1
6179
62- tmp_str = trim ( adjustl (exp_array(i)(j +1 :)))
80+ ! a group is a summation of terms
6381
64- nterms = 1
65- jj = scan ( tmp_str, ' +' )
66- do while (jj> 0 )
67- nterms = nterms + 1
68- tmp_str = tmp_str(jj+1 :)
69- jj = scan ( tmp_str, ' +' )
70- enddo
82+ ! parse the individual sum strings... and form the groupings
83+ has_grps: if (n_exp_items> 0 ) then
7184
72- allocate ( exp_item % vars(nterms) )
73- allocate ( exp_item % coeffs(nterms) )
85+ ! from shr_megan_mod ... should be generalized and shared...
86+ grploop: do i = 1 ,n_exp_items
7487
75- tmp_str = trim (adjustl (exp_array(i)(j+1 :)))
88+ ! parse out the term names
89+ ! from first parsing out the terms in the summation equation ("+" separates the terms)
7690
91+ sum_string = sums_grps(i)
92+ j = scan ( sum_string, ' =' )
93+ nelem = 1
94+ ndxs(nelem) = j ! ndxs stores the index of each term of the equation
95+
96+ ! find indices of all the terms in the equation
97+ tmp_str = trim ( sum_string(j+1 :) )
98+ j = scan ( tmp_str, ' +' )
99+ do while (j> 0 )
100+ nelem = nelem+1
101+ ndxs(nelem) = ndxs(nelem-1 ) + j
102+ tmp_str = tmp_str(j+1 :)
77103 j = scan ( tmp_str, ' +' )
104+ enddo
105+ ndxs(nelem+1 ) = len (sum_string)+ 1
78106
79- if (j> 0 ) then
80- call set_coefvar( tmp_str(:j-1 ), exp_item )
81- tmp_str = tmp_str(j-1 :)
82- else
83- call set_coefvar( tmp_str, exp_item )
84- endif
107+ allocate ( exp_item )
85108
86- else
109+ exp_item % n_terms = nelem ! number of terms
87110
88- tmp_str = trim (adjustl (exp_array(i))) ! assumed to begin with '+'
111+ exp_item % name = trim (adjustl ( sum_string(:ndxs( 1 ) - 1 ))) ! thing to the left of the "=" is used as the name of the group
89112
90- endif
113+ ! now that we have the number of terms in the summation allocate memory for the terms
114+ allocate ( exp_item% vars(nelem) )
115+ allocate ( exp_item% coeffs(nelem) )
91116
92- ! at this point tmp_str begins with '+'
93- j = scan ( tmp_str, ' +' )
117+ coeff0 = 1._r8 ! default multiplier
94118
95- if (j> 0 ) then
119+ ! now parse out the multiplier from the terms
120+ elmloop: do k = 1 ,nelem
96121
97- ! remove the leading + ...
98- tmp_str = tmp_str(j+1 :)
99- j = scan ( tmp_str, ' +' )
122+ exp_item% coeffs(k) = coeff0
100123
101- do while (j> 0 )
124+ ! get the term name which follows the '*' operator if the is one
125+ tmp_name = adjustl (sum_string(ndxs(k)+ 1 :ndxs(k+1 )- 1 ))
102126
103- call set_coefvar( tmp_str(:j-1 ), exp_item )
127+ j = scan ( tmp_name, ' *' )
128+ if (j> 0 ) then
104129
105- tmp_str = tmp_str(j+1 :)
106- j = scan ( tmp_str, ' +' )
130+ xchr = tmp_name(1 :j-1 ) ! get the multipler (left of the '*')
131+ read ( xchr, * ) xdbl ! convert the string to a real
132+ exp_item% coeffs(k) = xdbl ! store the multiplier
107133
108- enddo
134+ j1 = scan ( tmp_name, ' (' )
135+ if (j1> 0 ) then
136+ coeff0 = xdbl
137+ tmp_name = trim (adjustl (tmp_name(j1+1 :))) ! get the term name (right of the '*')
138+ else
139+ coeff0 = 1._r8
140+ tmp_name = trim (adjustl (tmp_name(j+1 :))) ! get the term name (right of the '*')
141+ endif
109142
110- call set_coefvar( tmp_str, exp_item )
143+ endif
111144
112- endif
145+ j2 = scan ( tmp_name, ' )' )
146+ if (j2> 0 ) then
147+ coeff0 = 1._r8
148+ tmp_name = tmp_name(1 :j2-1 )
149+ endif
113150
151+ exp_item% vars(k) = trim (tmp_name)
152+
153+ enddo elmloop
114154
115155 if (associated (exp_item)) then
116156 if (associated (exp_items_list)) then
@@ -124,13 +164,16 @@ function shr_exp_parse( exp_array, nitems ) result(exp_items_list)
124164 endif
125165 endif
126166
127- endif
128- enddo
167+
168+ enddo grploop
169+ endif has_grps
129170
130171 if ( present (nitems) ) then
131172 nitems = n_exp_items
132173 endif
133174
175+ deallocate (sums_grps)
176+
134177 end function shr_exp_parse
135178
136179 ! -----------------------------------------------------------------
@@ -157,29 +200,4 @@ subroutine shr_exp_list_destroy( list )
157200
158201 end subroutine shr_exp_list_destroy
159202
160- ! ==========================
161- ! Private Methods
162-
163- ! -----------------------------------------------------------------
164- ! -----------------------------------------------------------------
165- subroutine set_coefvar ( term , item )
166- character (len=* ), intent (in ) :: term
167- type (shr_exp_item_t) , intent (inout ) :: item
168-
169- integer :: k, n
170-
171- item% n_terms = item% n_terms + 1
172- n = item% n_terms
173-
174- k = scan ( term, ' *' )
175- if (k> 0 ) then
176- item% vars(n) = trim (adjustl (term(k+1 :)))
177- read ( term(:k-1 ), * ) item% coeffs(n)
178- else
179- item% vars(n) = trim (adjustl (term))
180- item% coeffs(n) = 1.0_r8
181- endif
182-
183- end subroutine set_coefvar
184-
185203end module shr_expr_parser_mod
0 commit comments