/[ascend]/trunk/ascend/compiler/units.c
ViewVC logotype

Contents of /trunk/ascend/compiler/units.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3355 - (show annotations) (download) (as text)
Mon Apr 16 05:56:23 2018 UTC (5 weeks, 2 days ago) by jpye
File MIME type: text/x-csrc
File size: 22656 byte(s)
unexpected behaviour in FindOrDefineUnits eg with 'N/m)'

1 /* ASCEND modelling environment
2 Copyright (C) 2006, 2011 Carnegie Mellon University
3 Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *//**
18 @file
19 Ascend Units Type definitions.
20 *//*
21 by Tom Epperly 13 Sept 1989
22 Last in CVS: $Revision: 1.18 $ $Date: 1998/04/11 01:32:11 $ $Author: ballan $
23 */
24
25 #include <math.h>
26 #include <ctype.h>
27 #include <ascend/general/platform.h>
28 #include <ascend/general/ascMalloc.h>
29 #include <ascend/general/hashpjw.h>
30 #include <ascend/general/dstring.h>
31
32 #include "instance_enum.h"
33 #include "cmpfunc.h"
34 #include "symtab.h"
35
36 #include "dimen_io.h"
37 #include "units.h"
38
39 enum units_scanner_tokens {
40 units_id,
41 units_real,
42 units_times,
43 units_divide,
44 units_power,
45 units_open,
46 units_close,
47 units_end,
48 units_err, /* unexpected character at position */
49 units_oversized, /* oversized */
50 units_real_err /* bad character in real or character */
51 /* missing */
52 };
53
54 struct ParseReturn {
55 double conv;
56 dim_type dim;
57 };
58
59 /* parsing global variables */
60 char *g_units_str = NULL;
61 unsigned long g_units_str_len = 0;
62 char g_units_id_space[MAXTOKENLENGTH+1];
63
64 /* hash table global variables */
65 struct Units *g_units_hash_table[UNITS_HASH_SIZE];
66 unsigned long g_units_size = 0;
67 unsigned long g_units_collisions = 0;
68
69 static struct ParseReturn CheckNewUnits(CONST char *
70 , unsigned long int *CONST, int *CONST
71 );
72
73 static struct ParseReturn ParseString(CONST char *c
74 , unsigned long int *CONST pos, int *CONST error_code
75 );
76
77
78 static void CopyToGlobal(register CONST char *c){
79 register char *p;
80 register unsigned length;
81 length = strlen(c);
82 if (g_units_str==NULL) {
83 g_units_str = ascmalloc((unsigned)length+(unsigned)1);
84 g_units_str_len = length;
85 }
86 else
87 if (length > g_units_str_len) {
88 g_units_str = ascrealloc(g_units_str,(unsigned)length+(unsigned)1);
89 g_units_str_len = length;
90 }
91 p = g_units_str;
92 while((*c) != '\0')
93 if (!isspace(*c)) *(p++) = *(c++);
94 else c++;
95 *p = '\0';
96 }
97
98
99 static void DefineFundamentalUnit(CONST char *dimname, char *unitname){
100 CONST struct Units *uptr;
101 dim_type dim, *dimp;
102
103 dimp = &dim;
104 ClearDimensions(dimp);
105 ParseDim(dimp,dimname);
106 dimp = (dim_type *)FindOrAddDimen(dimp);
107 uptr = DefineUnits(AddSymbol(unitname),(double)1.0,dimp);
108 if (uptr==NULL) {
109 FPRINTF(ASCERR,"Unable to define SI unit %s.\n",unitname);
110 }
111 }
112
113
114 static void DefineFundamentalUnits(void){
115 DefineFundamentalUnit("M",UNIT_BASE_MASS);
116 DefineFundamentalUnit("Q",UNIT_BASE_QUANTITY);
117 DefineFundamentalUnit("T", UNIT_BASE_TIME);
118 DefineFundamentalUnit("L", UNIT_BASE_LENGTH);
119 DefineFundamentalUnit("TMP", UNIT_BASE_TEMPERATURE);
120 DefineFundamentalUnit("C", UNIT_BASE_CURRENCY);
121 DefineFundamentalUnit("E", UNIT_BASE_ELECTRIC_CURRENT);
122 DefineFundamentalUnit("LUM", UNIT_BASE_LUMINOUS_INTENSITY);
123 DefineFundamentalUnit("P", UNIT_BASE_PLANE_ANGLE);
124 DefineFundamentalUnit("S", UNIT_BASE_SOLID_ANGLE);
125 }
126
127 /* internal translate table of some utility */
128 static char *g_unit_base_name[NUM_DIMENS];
129
130
131 void InitUnitsTable(void){
132 register unsigned long c;
133 //register CONST struct Units *result;
134
135 for(c=0;c<UNITS_HASH_SIZE;g_units_hash_table[c++]=NULL);
136 /* no body */
137 g_units_size = 0;
138 g_units_collisions = 0;
139 DefineUnits(AddSymbol("?"),1.0,WildDimension());
140 DefineUnits(AddSymbol(""),1.0,Dimensionless());
141 DefineFundamentalUnits();
142 g_unit_base_name[D_MASS] = UNIT_BASE_MASS;
143 g_unit_base_name[D_QUANTITY] = UNIT_BASE_QUANTITY;
144 g_unit_base_name[D_LENGTH] = UNIT_BASE_LENGTH;
145 g_unit_base_name[D_TIME] = UNIT_BASE_TIME;
146 g_unit_base_name[D_TEMPERATURE] = UNIT_BASE_TEMPERATURE;
147 g_unit_base_name[D_CURRENCY] = UNIT_BASE_CURRENCY;
148 g_unit_base_name[D_ELECTRIC_CURRENT] = UNIT_BASE_ELECTRIC_CURRENT;
149 g_unit_base_name[D_LUMINOUS_INTENSITY] = UNIT_BASE_LUMINOUS_INTENSITY;
150 g_unit_base_name[D_PLANE_ANGLE] = UNIT_BASE_PLANE_ANGLE;
151 g_unit_base_name[D_SOLID_ANGLE] = UNIT_BASE_SOLID_ANGLE;
152 }
153
154
155 void DestroyUnitsTable(void){
156 register unsigned long c;
157 struct Units *ptr,*next;
158 for(c=0;c<UNITS_HASH_SIZE;g_units_hash_table[c++]=NULL){
159 next = g_units_hash_table[c];
160 while((ptr = next)!=NULL){
161 next = ptr->next;
162 ascfree(ptr);
163 }
164 }
165 g_units_size = 0;
166 g_units_collisions = 0;
167 if (g_units_str) ascfree(g_units_str);
168 g_units_str = 0;
169 g_units_str_len = 0;
170 }
171
172 struct UnitDefinition *CreateUnitDef(symchar *lhs, CONST char *rhs,
173 CONST char *filename, int linenum)
174 {
175 int len;
176 struct UnitDefinition *ud;
177 char *ustr;
178
179 if (lhs==NULL || rhs == NULL || filename == NULL) {
180 FPRINTF(ASCERR," CreateUnitDef miscalled.\n");
181 return NULL;
182 }
183 ud = (struct UnitDefinition *)ascmalloc(sizeof(struct UnitDefinition));
184 if (ud == NULL) {
185 FPRINTF(ASCERR," malloc failed in CreateUnitDef for %s: %s %d\n",
186 SCP(lhs),filename,linenum);
187 return NULL;
188 }
189 len = strlen(rhs) + 1;
190 ustr = ASC_NEW_ARRAY(char,len);
191 if (ustr == NULL) {
192 FPRINTF(ASCERR," malloc failed in CreateUnitDef for %s: %s %d\n",
193 rhs,filename,linenum);
194 ascfree(ud);
195 return NULL;
196 }
197 strcpy(ustr,rhs);
198
199 ud->new_name = lhs;
200 ud->unitsexpr = ustr;
201 ud->filename = filename;
202 ud->linenum = linenum;
203 return ud;
204 }
205
206
207 void DestroyUnitDef(struct UnitDefinition *ud){
208 if (ud==NULL) {
209 return;
210 }
211 ascfree((char *)ud->unitsexpr);
212 ud->new_name = NULL;
213 ud->unitsexpr = ud->filename = NULL;
214 ascfree((char *)ud);
215 }
216
217
218 void ProcessUnitDef(struct UnitDefinition *ud){
219 CONST struct Units *result;
220 struct ParseReturn pr;
221 unsigned long pos;
222 char **errv;
223 int code;
224
225 if (ud==NULL) {
226 return;
227 }
228 pr = CheckNewUnits(ud->unitsexpr,&pos,&code);
229 if (code!=0) {
230 errv = UnitsExplainError(ud->unitsexpr,code,pos);
231 FPRINTF(ASCERR,"ERROR checking: %s.\n", errv[0]);
232 FPRINTF(ASCERR," %s =\n",SCP(ud->new_name));
233 FPRINTF(ASCERR," {%s};\n",errv[1]);
234 FPRINTF(ASCERR," -%s\n",errv[2]);
235 FPRINTF(ASCERR," %s:%d\n\n",ud->filename,ud->linenum);
236 errv = UnitsExplainError(NULL,-1,0);
237 return;
238 }
239 result = DefineUnits(ud->new_name,pr.conv,FindOrAddDimen(&pr.dim));
240 if (result == NULL) {
241 errv = UnitsExplainError(ud->unitsexpr,11,0);
242 FPRINTF(ASCERR,"ERROR defining units: %s.\n", errv[0]);
243 FPRINTF(ASCERR," %s =\n",SCP(ud->new_name));
244 FPRINTF(ASCERR," {%s};\n",errv[1]);
245 FPRINTF(ASCERR," -%s\n",errv[2]);
246 FPRINTF(ASCERR," %s:%d\n\n",ud->filename,ud->linenum);
247 errv = UnitsExplainError(NULL,-1,0);
248 return;
249 }
250 }
251
252 /*
253 * it is not appropriate to replace this with a pointer hashing
254 * function since the string hashed may not be a symchar.
255 */
256 #define UnitsHashFunction(s) hashpjw(s,UNITS_HASH_SIZE)
257
258
259 CONST struct Units *LookupUnits(CONST char *c){
260 register struct Units *result;
261 register int str_cmp=1;
262 if ((result=g_units_hash_table[UnitsHashFunction(c)])!=NULL) {
263 while(((str_cmp=strcmp(SCP(UnitsDescription(result)),c))<0) &&
264 (result->next != NULL))
265 result = result->next;
266 if (str_cmp==0) return result;
267 }
268 return NULL;
269 }
270
271
272 static struct Units *CheckUnitsMatch(struct Units *p
273 , double conv, CONST dim_type *dim
274 ){
275 if((conv!=UnitsConvFactor(p))||(!SameDimen(dim,UnitsDimensions(p)))) {
276 return NULL;
277 }else{
278 return p;
279 }
280 }
281
282
283 CONST struct Units *DefineUnits(symchar *c
284 , double conv, CONST dim_type *dim
285 ){
286 register unsigned long bucket;
287 register struct Units *result,*tmp;
288 register int str_cmp;
289 assert(AscFindSymbol(c)!=NULL);
290 bucket=UnitsHashFunction(SCP(c));
291 if(g_units_hash_table[bucket]!=NULL){
292 result=g_units_hash_table[bucket];
293 str_cmp = CmpSymchar(c,UnitsDescription(result));
294 if(str_cmp==0){
295 return CheckUnitsMatch(result,conv,dim);
296 }else if (str_cmp<0){
297 /* insert before list head */
298 g_units_hash_table[bucket]=
299 (struct Units *)ascmalloc(sizeof(struct Units));
300 g_units_hash_table[bucket]->next = result;
301 result = g_units_hash_table[bucket];
302 }else{
303 while((result->next!=NULL)&&
304 ((str_cmp=CmpSymchar(c,UnitsDescription(result->next)))>0))
305 result = result->next;
306 if(str_cmp==0) return CheckUnitsMatch(result->next,conv,dim);
307 tmp = result->next;
308 result->next = (struct Units *)ascmalloc(sizeof(struct Units));
309 result = result->next;
310 result->next = tmp;
311 }
312 g_units_size++;
313 g_units_collisions++;
314 result->description = c;
315 result->conversion_factor = conv;
316 result->dim = dim;
317 }else{
318 /* empty bucket */
319 g_units_size++;
320 result = g_units_hash_table[bucket] =
321 (struct Units *)ascmalloc(sizeof(struct Units));
322 result->next = NULL;
323 result->description = c;
324 result->dim = dim;
325 result->conversion_factor = conv;
326 }
327 return result;
328 }
329
330
331 static void SkipStrBlanks(CONST char *c, unsigned long int *CONST pos){
332 while(isspace(c[*pos])) (*pos)++;
333 }
334
335
336 static int AddChar(register char ch, register unsigned int pos){
337 if (pos < MAXTOKENLENGTH) {
338 g_units_id_space[pos]=ch;
339 return 1;
340 }
341 g_units_id_space[MAXTOKENLENGTH] = '\0';
342 return 0;
343 }
344
345
346 static enum units_scanner_tokens GetUnitsToken(CONST char *c
347 , unsigned long int *CONST pos
348 ){
349 register unsigned cc;
350 SkipStrBlanks(c,pos);
351 if (isalpha(c[*pos])) {
352 cc = 0;
353 do {
354 if (AddChar(c[*pos],cc++)) (*pos)++;
355 else return units_oversized;
356 } while(isalpha(c[*pos])||(isdigit(c[*pos]))||(c[*pos]=='_'));
357 g_units_id_space[cc]='\0';
358 return units_id;
359 }
360 else if (isdigit(c[*pos])) { /* real or integer */
361 cc = 0;
362 do {
363 if (AddChar(c[*pos],cc++)) (*pos)++;
364 else return units_oversized;
365 } while (isdigit(c[*pos]));
366 if (c[*pos] == '.') {
367 if (AddChar(c[*pos],cc++)) (*pos)++;
368 else return units_oversized;
369 while (isdigit(c[*pos])) {
370 if (AddChar(c[*pos],cc++)) (*pos)++;
371 else return units_oversized;
372 }
373 }
374 if ((c[*pos] == 'e')||(c[*pos] == 'E')) {
375 if (AddChar(c[*pos],cc++)) (*pos)++;
376 else return units_oversized;
377 if ((c[*pos] == '+')||(c[*pos] == '-')) {
378 if (AddChar(c[*pos],cc++)) (*pos)++;
379 else return units_oversized;
380 }
381 if (isdigit(c[*pos])) {
382 do {
383 if (AddChar(c[*pos],cc++)) (*pos)++;
384 else return units_oversized;
385 } while (isdigit(c[*pos]));
386 }
387 else {
388 g_units_id_space[cc]='\0';
389 return units_real_err;
390 }
391 }
392 g_units_id_space[cc]='\0';
393 return units_real;
394 }
395 else
396 switch(c[*pos]) {
397 case '.': /* real */
398 cc = 0;
399 if (AddChar(c[*pos],cc++)) (*pos)++;
400 else return units_oversized;
401 if (isdigit(c[*pos])) {
402 do {
403 if (AddChar(c[*pos],cc++)) (*pos)++;
404 else return units_oversized;
405 } while (isdigit(c[*pos]));
406 }
407 else {
408 g_units_id_space[cc]='\0';
409 return units_real_err;
410 }
411 if ((c[*pos] == 'e')||(c[*pos] == 'E')) {
412 if (AddChar(c[*pos] ,cc++)) (*pos)++;
413 else return units_oversized;
414 if ((c[*pos] == '+')||(c[*pos] == '-')) {
415 if (AddChar(c[*pos],cc++)) (*pos)++;
416 else return units_oversized;
417 }
418 if (isdigit(c[*pos])) {
419 do {
420 if (AddChar(c[*pos],cc++)) (*pos)++;
421 else return units_oversized;
422 } while (isdigit(c[*pos]));
423 }
424 else {
425 g_units_id_space[cc]='\0';
426 return units_real_err;
427 }
428 }
429 g_units_id_space[cc]='\0';
430 return units_real;
431 case '^':
432 (*pos)++;
433 return units_power;
434 case '*':
435 (*pos)++;
436 return units_times;
437 case '/':
438 (*pos)++;
439 return units_divide;
440 case '(':
441 (*pos)++;
442 return units_open;
443 case ')':
444 (*pos)++;
445 return units_close;
446 case '\0':
447 return units_end;
448 default:
449 return units_err;
450 }
451 }
452
453 static
454 double AdjustConv(double d, struct fraction f, int *CONST error_code)
455 {
456 f = Simplify(f);
457 if (Numerator(f)<0) {
458 if (Denominator(f)!=1) {
459 *error_code = 10;
460 return 0.0;
461 }
462 return 1.0/pow(d,-(double)Numerator(f));
463 }
464 else
465 return pow(d,(double)Numerator(f)/(double)Denominator(f));
466 }
467
468 static
469 FRACPART ParseInt(CONST char *c,
470 unsigned long int *CONST pos,
471 int *CONST error_code)
472 {
473 register unsigned count=0;
474 SkipStrBlanks(c,pos);
475 if ((c[*pos]=='-')||(c[*pos]=='+'))
476 g_units_id_space[count++]=c[(*pos)++];
477 if (!isdigit(c[*pos])) {
478 *error_code = 10;
479 return 1;
480 }
481 while (isdigit(c[*pos])) {
482 if (count < MAXTOKENLENGTH)
483 g_units_id_space[count++]=c[(*pos)++];
484 else {
485 *error_code = 10;
486 return 1;
487 }
488 }
489 g_units_id_space[count]='\0';
490 return (FRACPART)atoi(g_units_id_space);
491 }
492
493 static
494 struct fraction ParseFraction(CONST char *c,
495 unsigned long int *CONST pos,
496 int *CONST error_code)
497 {
498 register FRACPART num,denom;
499 SkipStrBlanks(c,pos);
500 if (c[*pos]=='(') {
501 (*pos)++;
502 num = ParseInt(c,pos,error_code);
503 if (*error_code != 0) {
504 SkipStrBlanks(c,pos);
505 if (c[*pos] == '/') {
506 (*pos)++;
507 denom = ParseInt(c,pos,error_code);
508 if (*error_code != 0) {
509 SkipStrBlanks(c,pos);
510 if (c[*pos] == ')') {
511 (*pos)++;
512 return CreateFraction(num,denom);
513 }
514 else { /* unclosed parenthesis */
515 *error_code = 2;
516 return CreateFraction(1,1);
517 }
518 }
519 }
520 else if (c[*pos] == ')') { /* okay */
521 (*pos)++;
522 return CreateFraction(num,1);
523 }
524 else { /* error unclosed parenthesis */
525 *error_code = 2;
526 return CreateFraction(1,1);
527 }
528 }
529 }
530 else if (isdigit(c[*pos])||(c[*pos]=='+')||(c[*pos]=='-'))
531 return CreateFraction(ParseInt(c,pos,error_code),1);
532 *error_code = 10;
533 return CreateFraction(1,1);
534 }
535
536 static
537 struct ParseReturn ParseTerm(CONST char *c,
538 unsigned long int *CONST pos,
539 int *CONST error_code)
540 {
541 register CONST struct Units *lookup;
542 struct fraction frac;
543 //enum units_scanner_tokens tok;
544 struct ParseReturn result;
545 unsigned long oldpos;
546 result.conv = 1.0;
547 ClearDimensions(&(result.dim));
548 SkipStrBlanks(c,pos);
549 oldpos = *pos;
550 switch(GetUnitsToken(c,pos)) {
551 case units_id:
552 lookup = LookupUnits(g_units_id_space);
553 if (lookup!=NULL) {
554 CopyDimensions(UnitsDimensions(lookup),&result.dim);
555 result.conv = UnitsConvFactor(lookup);
556 }
557 else {
558 *pos = oldpos;
559 *error_code = 1;
560 return result;
561 }
562 break;
563 case units_real:
564 result.conv = atof(g_units_id_space);
565 break;
566 case units_open:
567 result = ParseString(c,pos,error_code);
568 if (*error_code == 0) {
569 if (GetUnitsToken(c,pos)!=units_close) {/* unbalanced parenthesis */
570 *error_code = 2;
571 *pos = oldpos;
572 return result;
573 }
574 } else {
575 return result;
576 }
577 break;
578 case units_err:
579 *error_code = 3;
580 return result;
581 case units_end:
582 *error_code = 7;
583 return result;
584 case units_oversized:
585 *error_code = 5;
586 *pos = oldpos;
587 return result;
588 case units_real_err:
589 *error_code = 4;
590 *pos = oldpos;
591 return result;
592 case units_divide:
593 case units_power:
594 case units_times:
595 *pos = oldpos;
596 *error_code = 8;
597 return result;
598 case units_close:
599 *pos = oldpos;
600 *error_code = 9;
601 return result;
602 }
603 SkipStrBlanks(c,pos);
604 if (c[*pos]=='^') {
605 GetUnitsToken(c,pos);
606 SkipStrBlanks(c,pos);
607 oldpos = *pos;
608 frac = ParseFraction(c,pos,error_code);
609 if (*error_code==0) {
610 result.dim = ScaleDimensions(&result.dim,frac);
611 result.conv = AdjustConv(result.conv,frac,error_code);
612 }
613 if (*error_code!=0) *pos = oldpos;
614 }
615 return result;
616 }
617
618 static
619 struct ParseReturn MultiplyPR(CONST struct ParseReturn *r1,
620 CONST struct ParseReturn *r2)
621 {
622 struct ParseReturn result;
623 result.conv = r1->conv*r2->conv;
624 result.dim = AddDimensions(&(r1->dim),&(r2->dim));
625 return result;
626 }
627
628 static
629 struct ParseReturn DividePR(CONST struct ParseReturn *r1,
630 CONST struct ParseReturn *r2)
631 {
632 struct ParseReturn result;
633 result.conv = r1->conv/r2->conv;
634 result.dim = SubDimensions(&(r1->dim),&(r2->dim));
635 return result;
636 }
637
638 static
639 struct ParseReturn ParseString(CONST char *c,
640 unsigned long int *CONST pos,
641 int *CONST error_code)
642 {
643 struct ParseReturn result1,result2;
644 unsigned long oldpos;
645 result1 = ParseTerm(c,pos,error_code);
646 while (*error_code == 0 ) {
647 SkipStrBlanks(c,pos);
648 oldpos = *pos;
649 switch(GetUnitsToken(c,pos)) {
650 case units_oversized:
651 case units_id:
652 case units_real_err:
653 case units_real:
654 case units_open:
655 *pos = oldpos;
656 *error_code = 6;
657 return result1;
658 case units_times:
659 result2 = ParseTerm(c,pos,error_code);
660 if (*error_code==0) {
661 result1 = MultiplyPR(&result1,&result2);
662 }
663 break;
664 case units_divide:
665 result2 = ParseTerm(c,pos,error_code);
666 if (*error_code==0) {
667 result1 = DividePR(&result1,&result2);
668 }
669 break;
670 case units_close:
671 case units_end: /* natural closings */
672 return result1;
673 case units_err:
674 *error_code = 3;
675 return result1;
676 default:
677 /* units power? */
678 break;
679 }
680 }
681 return result1;
682 }
683
684 /*
685 * Checks the RHS of a new unit definition.
686 * returns valid parsereturn iff *error_code = 0 on exit.
687 * This has no effects
688 * on the global unit table, so it returns a ParseReturn
689 * instead of a units pointer.
690 * If unit already exists and the old and new definitions
691 * are incompatible, returns error.
692 */
693 static
694 struct ParseReturn CheckNewUnits(CONST char *c,
695 unsigned long int *CONST pos,
696 int *CONST error_code)
697 {
698 struct ParseReturn preturn;
699 register CONST struct Units *result;
700
701 /* initialize return codes */
702 *pos = 0;
703 *error_code = 0;
704 /* copy string to global string while removing blanks */
705 CopyToGlobal(c);
706 /* check if units are previously defined */
707 result = LookupUnits(g_units_str);
708 if (result != NULL) {
709 preturn.conv = UnitsConvFactor(result);
710 preturn.dim = *(UnitsDimensions(result));
711 return preturn;
712 }
713 /* it couldn't find a match, so the string must be parsed */
714 preturn = ParseString(c,pos,error_code);
715 return preturn;
716 }
717
718 CONST struct Units *FindOrDefineUnits(CONST char *c,
719 unsigned long int *CONST pos,
720 int *CONST error_code)
721 {
722 register CONST struct Units *result;
723 struct ParseReturn preturn;
724
725 /* initialize return codes */
726 *pos = 0;
727 *error_code = 0;
728 /* copy string to global string while removing blanks */
729 CopyToGlobal(c);
730 /* check if units are previously defined */
731 result = LookupUnits(g_units_str);
732 if (result != NULL) {
733 return result;
734 }
735 /* it couldn't find a match, so the string must be parsed */
736 preturn = ParseString(c,pos,error_code);
737 if (*error_code == 0) {
738 result = DefineUnits(AddSymbol(g_units_str),
739 preturn.conv,
740 FindOrAddDimen(&preturn.dim));
741 }
742 return result;
743 }
744
745 char *UnitsStringSI(const struct Units *p)
746 {
747 Asc_DString ds, *dsPtr;
748 char expo[20];
749 char *result;
750 int numseen = 0;
751 int i;
752 int k;
753
754 if (p==NULL) {
755 return NULL;
756 }
757 if (IsWild(p->dim)) {
758 result = ASC_NEW_ARRAY(char,2);
759 sprintf(result,"*");
760 return result;
761 }
762 dsPtr = &ds;
763 Asc_DStringInit(dsPtr);
764 for (i=0; i < NUM_DIMENS; i++) {
765 k = GetDimPower(*(p->dim),i);
766 if (k > 0) {
767 if (numseen) {
768 Asc_DStringAppend(dsPtr,"*",1);
769 }
770 Asc_DStringAppend(dsPtr,g_unit_base_name[i],-1);
771 if (k > 1) {
772 sprintf(expo,"^%d",k);
773 Asc_DStringAppend(dsPtr,expo,-1);
774 }
775 numseen =1;
776 }
777 }
778 if (!numseen) {
779 Asc_DStringAppend(dsPtr,"1",1);
780 }
781 for (i=0; i < NUM_DIMENS; i++) {
782 k = GetDimPower(*(p->dim),i);
783 if (k < 0) {
784 Asc_DStringAppend(dsPtr,"/",1);
785 Asc_DStringAppend(dsPtr,g_unit_base_name[i],-1);
786 if (k < -1) {
787 sprintf(expo,"^%d",-k);
788 Asc_DStringAppend(dsPtr,expo,-1);
789 }
790 }
791 }
792 result = Asc_DStringResult(dsPtr);
793 return result;
794 }
795
796 void DumpUnits(FILE *file)
797 {
798 register unsigned long c;
799 register struct Units *p;
800 char *ds;
801 FPRINTF(file,"Units dump\n");
802 for(c=0;c<UNITS_HASH_SIZE;c++) {
803 for(p = g_units_hash_table[c];p!=NULL;p=p->next) {
804 ds = WriteDimensionString(p->dim);
805 FPRINTF(file,"%35s %14g %s\n",
806 SCP(p->description),
807 p->conversion_factor,ds);
808 if (ds != NULL) {
809 ascfree(ds);
810 }
811 }
812 }
813 }
814
815 static
816 char *g_unit_explain_error_strings[3] = {NULL,NULL,NULL};
817 #define ERRV g_unit_explain_error_strings
818
819 char **UnitsExplainError(CONST char *ustr, int code, int pos)
820 {
821 #define UEESIZE 14
822 #define UEELAST (UEESIZE-3) /* last real message */
823 #define UEECALL (UEESIZE-2)
824 #define UEEMEM (UEESIZE-1)
825 static char *g_units_errors[UEESIZE] = {
826 "unit ok",
827 "undefined unit in expression",
828 "unbalanced ( or () in denominator",
829 "illegal character",
830 "illegal real value",
831 "unit name too long",
832 "operator ( * or / ) missing",
833 "term missing after *,/, or (",
834 "term missing before * or /",
835 "too many )",
836 "illegal fractional exponent",
837 "redefinition of unit",
838 /* these two should be last */
839 "error in call to UnitsExplainError",
840 "malloc fail in UnitsExplainError"
841 };
842 int c,len;
843 char *line;
844
845 if (ERRV[2] != g_units_errors[UEECALL] &&
846 ERRV[2] != g_units_errors[UEEMEM] &&
847 ERRV[2] != NULL) {
848 /* clean up the memory allocated to the line indicator on the last call */
849 ascfree(ERRV[2]);
850 ERRV[2] = NULL;
851 }
852
853 if (code<0 || code>UEELAST || ustr==NULL) {
854 ERRV[0] = g_units_errors[UEECALL];
855 ERRV[1] = g_units_errors[UEECALL];
856 ERRV[2] = g_units_errors[UEECALL];
857 return ERRV;
858 }
859 len = strlen(ustr);
860 if (pos<0 || pos>=len ) {
861 ERRV[0] = g_units_errors[UEECALL];
862 ERRV[1] = g_units_errors[UEECALL];
863 ERRV[2] = g_units_errors[UEECALL];
864 return ERRV;
865 }
866 line = ASC_NEW_ARRAY_CLEAR(char,len+2);
867 if (line==NULL) {
868 ERRV[0] = g_units_errors[UEEMEM];
869 ERRV[1] = g_units_errors[UEEMEM];
870 ERRV[2] = g_units_errors[UEEMEM];
871 return ERRV;
872 }
873 ERRV[0] = g_units_errors[code];
874 ERRV[1] = (char *)ustr;
875 ERRV[2] = line;
876 c = 0;
877 while ( c < pos) {
878 line[c] = '-';
879 c++;
880 }
881 line[c] = '^';
882 c++;
883 line[c] = '\0';
884 return ERRV;
885 }
886

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22