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

Annotation of /trunk/base/generic/compiler/units.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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