0027432: Null Handle Access When Creating AIS_Trihedron
[occt.git] / src / Units / Units_Sentence.cxx
1 // Created on: 1992-06-24
2 // Created by: Gilles DEBARBOUILLE
3 // Copyright (c) 1992-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <Units_Lexicon.hxx>
19 #include <Units_NoSuchType.hxx>
20 #include <Units_Operators.hxx>
21 #include <Units_Sentence.hxx>
22 #include <Units_ShiftedToken.hxx>
23 #include <Units_Token.hxx>
24 #include <Units_TokensSequence.hxx>
25
26 static Handle(Units_Token) CreateTokenForNumber(const Standard_CString str)
27 {
28   TCollection_AsciiString tstr = str[0];
29   Standard_Boolean IsPoint = Standard_False;
30   Standard_Size len = strlen(str);
31   for(Standard_Size in=1; in < len; in++) {
32     if( str[in]=='0' || str[in]=='1' || str[in]=='2' || str[in]=='3' || 
33         str[in]=='4' || str[in]=='5' || str[in]=='6' || str[in]=='7' || 
34         str[in]=='8' || str[in]=='9' ) {
35       tstr.AssignCat(str[in]);
36     }
37     else if( str[in]=='.' && !IsPoint ) {
38       tstr.AssignCat(str[in]);
39       IsPoint = Standard_True;
40     }
41     else
42       break;
43   }
44   return new Units_Token(tstr.ToCString(), "0");
45 }
46
47
48 //=======================================================================
49 //function : Units_Sentence
50 //purpose  : 
51 //=======================================================================
52
53 Units_Sentence::Units_Sentence(const Handle(Units_Lexicon)& alexicon,
54                                const Standard_CString astring)
55 {
56   Standard_Integer index;
57   Standard_Size i,limchain;
58   Handle(Units_Token) token;
59   Handle(Units_Token) referencetoken;
60   
61   thesequenceoftokens = new Units_TokensSequence();
62   Handle(Units_TokensSequence) lstlexicon=alexicon->Sequence();
63   if(lstlexicon.IsNull())
64     Units_NoSuchType::Raise("BAD LEXICON descriptor");
65   limchain=strlen(astring);
66   i=0;
67
68   TCollection_AsciiString tmpstr = astring;
69   //Handle(Units_Token) tmptoken;
70   TCollection_AsciiString PrevMean;
71   TCollection_AsciiString PrevWord;
72   while(i < limchain) {
73     Standard_Boolean IsFound = Standard_False;
74     TCollection_AsciiString LastWord = "";
75     for(index=1; index<=lstlexicon->Length(); index++) {
76       referencetoken = lstlexicon->Value(index);
77       TCollection_AsciiString aword = referencetoken->Word();
78       int num = tmpstr.Search(aword);
79       if( num==1 && aword.Length()>=LastWord.Length() ) {
80         token = referencetoken->Creates();
81         LastWord = aword;
82         IsFound = Standard_True;
83       }
84     }
85     if(!IsFound) {
86       // may be it is a number(degree)?
87       LastWord = tmpstr.SubString(1,1);
88       if(!LastWord.IsIntegerValue()) {
89         // unknown expression - not create sentene
90         thesequenceoftokens->Clear();
91 #ifdef OCCT_DEBUG
92         cout<<"Warning: can not create correct sentence from string: "<<astring<<endl;
93 #endif
94         return;
95       }
96       else {
97         // create token for number
98         token = CreateTokenForNumber(tmpstr.ToCString());
99         LastWord = token->Word();
100       }
101     }
102     if(i>0) {
103       // make additional checking
104       if( ( token->Mean()=="M" && ( PrevMean=="M" || PrevMean=="MU" || PrevMean=="0" ) ) ||
105           ( token->Mean()=="U" && ( PrevMean=="U" || PrevMean=="0" )                   ) ||
106           ( token->Mean()=="O" && ( PrevMean=="M" || PrevMean=="O" )                   ) ||
107           ( ( token->Word()=="+" || token->Word()=="-" ) && PrevWord!="("              ) ||
108           ( token->Mean()=="S" && ( PrevMean=="M" )                                    ) ||
109           ( token->Mean()=="0" && ( PrevMean=="M" || PrevMean=="U" || PrevMean=="MU" ) ) )  {
110         // incorrect situation
111         thesequenceoftokens->Clear();
112 #ifdef OCCT_DEBUG
113         cout<<"Warning: can not create correct sentence from string: "<<astring<<endl;
114 #endif
115         return;
116       }
117     }
118     thesequenceoftokens->Append(token);
119     PrevMean = token->Mean();
120     PrevWord = token->Word();
121     i = i + LastWord.Length();
122     tmpstr.Remove(1,LastWord.Length());
123   }
124 }
125
126
127 //=======================================================================
128 //function : SetConstants
129 //purpose  : 
130 //=======================================================================
131
132 void Units_Sentence::SetConstants()
133 {
134   Standard_Integer index;
135   Standard_Real value;
136   Handle(Units_Token) token;
137   TCollection_AsciiString string;
138
139   for(index=1;index<=thesequenceoftokens->Length();index++) {
140     token = thesequenceoftokens->Value(index);
141     if(token->Value()==0.) {
142       string = token->Word();
143       if(string.IsRealValue()) {
144         value = string.RealValue();
145         token->Mean("K");
146         token->Value(value);
147       }
148     }
149   }
150 }
151
152
153 //=======================================================================
154 //function : CalculateLocal
155 //purpose  : auxilary
156 //=======================================================================
157 static Handle(Units_Token) CalculateLocal(const Handle(Units_TokensSequence)& aSeq)
158 {
159   //cout<<endl;
160   //for(int index=1; index<=aSeq->Length(); index++) {
161   //  Handle(Units_Token) tok = aSeq->Value(index);
162   //  cout<<tok->Word()<<" ";
163   //}
164   //cout<<endl;
165   Handle(Units_Token) tok1,tok2;
166   Standard_Integer i,j;
167
168   if(aSeq->Length()==1) {
169     return aSeq->Value(1);
170   }
171
172   // case of unar sign
173   if(aSeq->Length()==2) {
174     if(aSeq->Value(1)->Word()=="+")
175       aSeq->Remove(1);
176     if(aSeq->Value(1)->Word()=="-") {
177       tok2 = aSeq->Value(2);
178       TCollection_AsciiString aword = "-";
179       aword.AssignCat(tok2->Word());
180       tok1 = new Units_Token(aword.ToCString(), tok2->Mean().ToCString(),
181                              tok2->Value()*(-1.0), tok2->Dimensions());
182       aSeq->Remove(1);
183       aSeq->SetValue(1,tok1);
184     }
185     return aSeq->Value(1);
186   }
187
188   Standard_Boolean IsBracket = Standard_True;
189   while(IsBracket) {
190     for(i=1; i<=aSeq->Length(); i++) {
191       if(aSeq->Value(i)->Word()=="(") {
192         Handle(Units_TokensSequence) TmpSeq = new Units_TokensSequence;
193         Standard_Integer NbBrackets = 1;
194         for(j=i+1; j<=aSeq->Length(); j++) {
195           if(aSeq->Value(j)->Word()==")")
196             NbBrackets--;
197           if(aSeq->Value(j)->Word()=="(")
198             NbBrackets++;
199           if(NbBrackets>0)
200             TmpSeq->Append(aSeq->Value(j));
201           else
202             break;
203         }
204         tok1 = CalculateLocal(TmpSeq);
205         aSeq->Remove(i+1,j);
206         aSeq->SetValue(i,tok1);
207         break;
208       }
209     }
210     if(i>aSeq->Length()) {
211       IsBracket = Standard_False;
212       // there are not brackets => make calculations
213       // step 1: operation '**'
214       for(i=1; i<=aSeq->Length(); i++) {
215         if(aSeq->Value(i)->Word()=="**") {
216           tok1 = aSeq->Value(i-1);
217           tok2 = aSeq->Value(i+1);
218           tok1 = pow(tok1,tok2);
219           aSeq->Remove(i);
220           aSeq->Remove(i);
221           aSeq->SetValue(i-1,tok1);
222           i--;
223         }
224       }
225       // step 2: operation '*', '.' and '/'
226       for(i=1; i<=aSeq->Length(); i++) {
227         if(aSeq->Value(i)->Mean()=="O") {
228           tok1 = aSeq->Value(i-1);
229           tok2 = aSeq->Value(i+1);
230           if(aSeq->Value(i)->Word()=="/")
231             tok1 = tok1 / tok2;
232           else
233             tok1 = tok1 * tok2;
234           aSeq->Remove(i);
235           aSeq->Remove(i);
236           aSeq->SetValue(i-1,tok1);
237           i--;
238         }
239       }
240       // now aSeq have to include only one result token
241     }
242   }
243   return tok1;
244 }
245
246
247 //=======================================================================
248 //function : Evaluate
249 //purpose  : 
250 //=======================================================================
251
252 Handle(Units_Token) Units_Sentence::Evaluate()
253 {
254   Handle(Units_Token) rtoken,ktoken;
255   if(thesequenceoftokens->Length()==0)
256     return rtoken;
257
258 /* old variant
259   Standard_Integer index;
260   static char *ooper[6] = { "+", "-", "*", ".", "/", "**" };
261   Standard_Integer numterm,i,j,k,maxlevel,curlevel,level[255];
262   Handle(Units_Token) currenttoken;
263   TCollection_AsciiString string;
264   TCollection_AsciiString mean;
265   TCollection_AsciiString oper;
266   
267   numterm=curlevel=i=0;
268   for(index=1;index<=thesequenceoftokens->Length();index++) {
269     string = thesequenceoftokens->Value(index)->Word();
270
271     if( string=="(" ) {
272       level[numterm]=curlevel;
273       curlevel++;
274     }
275     else if( string==")" ) {
276       curlevel--;
277       level[numterm]=curlevel;
278     }
279     else {
280       level[numterm]=curlevel;
281     }
282     numterm++;
283   }
284
285   //if(IPrint==1) {
286   //  cout<<endl;
287   //  for(index=1; index<=thesequenceoftokens->Length(); index++) {
288   //    Handle(Units_Token) tok = thesequenceoftokens->Value(index);
289   //    cout<<tok->Word()<<" ";
290   //  }
291   //  cout<<endl;
292   //  for(index=1; index<=thesequenceoftokens->Length(); index++) {
293   //    cout<<level[index-1]<<" ";
294   //  }
295   //  cout<<endl;
296   //}
297
298   if(curlevel) {
299     cout<<" Incorrect number of brackets"<<endl;
300     return new Units_Token();
301   }
302
303   for(k=0; k<6; k++) {
304     for(index=1,i=0; index<=thesequenceoftokens->Length(); index++,i++) {
305       if( thesequenceoftokens->Value(index)->Word() == ooper[k] ) {
306         j=i+1;
307         curlevel=level[j];
308         while(j < numterm && level[j] >= curlevel)
309           level[j++]++;
310         j=i-1;
311         curlevel=level[j];
312         while(j >= 0 && level[j] >= curlevel)
313           level[j--]++;
314       }
315     }
316   }
317
318   Handle(Units_Dimensions) aDim;
319
320   numterm--;
321   while(numterm>0) {
322
323     maxlevel=0;
324     for(i=0; i<=numterm; i++)if(level[i] > maxlevel)
325       maxlevel=level[i];
326
327     i=0;
328     while(level[i] != maxlevel)
329       i++;
330
331     oper.Clear();
332
333     k=i;
334     while( k<=numterm && level[k]==maxlevel ) {
335       ktoken=thesequenceoftokens->Value(k+1);
336       mean=ktoken->Mean();
337       if(mean=="O") {
338         oper = ktoken->Word();
339       }
340       else if(mean!="S") {
341         if     (oper == "/")  rtoken = rtoken / ktoken;
342         else if(oper == "+")  rtoken = rtoken + ktoken;
343         else if(oper == "-")  rtoken = rtoken - ktoken;
344         else if(oper == "*")  rtoken = rtoken * ktoken;
345         else if(oper == "**") rtoken = pow(rtoken,ktoken);
346         else if(oper == ".")  rtoken = rtoken * ktoken;
347         else                  rtoken = ktoken->Creates();
348       }
349       k++;
350     }
351     thesequenceoftokens->SetValue(i+1,rtoken);
352     level[i]=maxlevel-1;
353
354     if( (i+1) != k ) {
355       thesequenceoftokens->Remove(i+2,k);
356       j=i;
357       while(k <= numterm)
358         level[++j]=level[k++];
359       numterm=j;
360     }
361   }
362
363   rtoken = thesequenceoftokens->Value(1)->Creates();
364
365   if( rtoken->Value()==0. ) {
366     cout << "*BAD token value from unit '" << rtoken->Word() << "'" << endl;
367     rtoken->Value(1.);
368   }
369 */ // end old variant
370
371   // variant skl 15.09.2005
372   rtoken = CalculateLocal(thesequenceoftokens);
373
374   //rtoken->Dump(0,1);
375
376   return rtoken;
377 }