exip  Alpha 0.5.4
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
genUtils.c
Go to the documentation of this file.
1 /*==================================================================*\
2 | EXIP - Embeddable EXI Processor in C |
3 |--------------------------------------------------------------------|
4 | This work is licensed under BSD 3-Clause License |
5 | The full license terms and conditions are located in LICENSE.txt |
6 \===================================================================*/
7 
17 #include "genUtils.h"
18 #include "memManagement.h"
19 #include "stringManipulate.h"
20 #include "grammars.h"
21 #include "ioUtil.h"
22 #include "initSchemaInstance.h"
23 
25 static char rulesEqual(ProtoGrammar* g1, Index ruleIndx1, ProtoGrammar* g2, Index ruleIndx2);
26 
29 static errorCode addProductionsToARule(ProtoGrammar* left, Index ruleIndxL, ProtoGrammar* right, Index ruleIndxR,
30  unsigned int* currRuleIndex, unsigned int initialLeftRulesCount);
31 
33 {
34  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
35  unsigned int ruleIterL = 0;
36  unsigned int ruleIterR = 0;
37  unsigned int prodIterL = 0;
38  unsigned int prodIterR = 0;
39  unsigned int currRuleIndex;
40  unsigned int initialLeftRulesCount;
41  ProtoRuleEntry* pRuleEntry;
42 
43  assert(left);
44 
45  if(right == NULL)
46  return EXIP_OK;
47 
48  /*
49  * Concatentation works as follows:
50  * Add each rule apart from the first one on the RHS to the LHS.
51  * Example:
52  * LHS has two rules already:
53  * left->rule[2]
54  * RHS has four rules to concatentate:
55  * right->rule[4]
56  * Append all RHS rule productions excluding the first rule directly to LHS
57  * left->rule[2] = right->rule[1]
58  * left->rule[3] = right->rule[2]
59  * left->rule[4] = right->rule[3]
60  * Merge all LHS rule productions with the first RHS rule productions ("+=" means merge)
61  * left->rule[0] += right->rule[0]
62  * left->rule[1] += right->rule[0]
63  * Merging occurs after the EE production; this is replaced with the first production
64  * to be merged
65  * Resolve any collisions
66  */
67 
68  /* Make a note of how many rules are currently in LHS for the new non terminal IDs */
69  initialLeftRulesCount = left->count;
70 
71  /* Add in rules from the RHS */
72  for(ruleIterR = 1; ruleIterR < right->count; ruleIterR++)
73  {
74  /* Create new rule entry in LHS proto grammar */
75  TRY(addProtoRule(left, right->rule[ruleIterR].count, &pRuleEntry));
76 
77  /* Copy the RHS productions into the new rule entry, adjusting the non terminal ID */
78  for(prodIterR = 0; prodIterR < right->rule[ruleIterR].count; prodIterR++)
79  {
80  TRY(addProduction(pRuleEntry, GET_PROD_EXI_EVENT(right->rule[ruleIterR].prod[prodIterR].content),
81  right->rule[ruleIterR].prod[prodIterR].typeId,
82  right->rule[ruleIterR].prod[prodIterR].qnameId,
83  GET_PROD_NON_TERM(right->rule[ruleIterR].prod[prodIterR].content) + ((GET_PROD_EXI_EVENT(right->rule[ruleIterR].prod[prodIterR].content) == EVENT_EE)?0:(initialLeftRulesCount-1))));
84  }
85  }
86 
87  currRuleIndex = left->count;
88 
89  for(ruleIterL = 0; ruleIterL < initialLeftRulesCount; ruleIterL++)
90  {
91  for(prodIterL = 0; prodIterL < left->rule[ruleIterL].count; prodIterL++)
92  {
93  if(GET_PROD_EXI_EVENT(left->rule[ruleIterL].prod[prodIterL].content) == EVENT_EE)
94  {
95  if(!rulesEqual(left, ruleIterL, right, 0))
96  {
97  /* Remove the EE production */
98  delDynEntry(&left->rule[ruleIterL].dynArray, prodIterL);
99 
100  if(left->rule[ruleIterL].count == 0)
101  {
102  // Just copy all the production...
103  for(prodIterR = 0; prodIterR < right->rule[0].count; prodIterR++)
104  {
105  TRY(addProduction(&left->rule[ruleIterL],
106  GET_PROD_EXI_EVENT(right->rule[0].prod[prodIterR].content),
107  right->rule[0].prod[prodIterR].typeId,
108  right->rule[0].prod[prodIterR].qnameId,
109  GET_PROD_NON_TERM(right->rule[0].prod[prodIterR].content) + ((GET_PROD_EXI_EVENT(right->rule[0].prod[prodIterR].content) == EVENT_EE)?0:(initialLeftRulesCount-1))));
110  }
111  }
112  else
113  {
114  /* Merge productions from RHS rule 0 into each left rule */
115  TRY(addProductionsToARule(left,
116  ruleIterL,
117  right,
118  0,
119  &currRuleIndex,
120  initialLeftRulesCount - 1));
121  }
122  }
123  break;
124  }
125  }
126  }
127 
128  return EXIP_OK;
129 }
130 
131 static errorCode addProductionsToARule(ProtoGrammar* left, Index ruleIndxL, ProtoGrammar* right, Index ruleIndxR,
132  unsigned int* currRuleIndex, unsigned int initialLeftRulesCount)
133 {
134  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
135  unsigned int prodIterL = 0;
136  unsigned int prodIterR = 0;
137  boolean rProdFoundInLeft = FALSE;
138  Index nonTermRight;
139  unsigned int prodCountR = right->rule[ruleIndxR].count; // Needed as left might be the same grammar as right
140 
141  for(prodIterR = 0; prodIterR < prodCountR; prodIterR++)
142  {
143  /* Check for equivalent productions */
144  rProdFoundInLeft = FALSE;
145 
146  /* The use case when the Non-Terminal RHS symbol of the production is pointing to the same grammar rule
147  * can cause problems when the rules are merged. Few possible outcomes:
148  * - If all the productions from the right rule are contained in the left rule then the Non-Terminal RHS symbol
149  * can again point to the same rule safely
150  * - If that is not the case, try to find a rule in the left grammar that is equivalent to the
151  * right rule and make the Non-Terminal RHS symbol point to that grammar instead
152  * - If non of these is true then we need to create a new grammar rule on the left that is
153  * equivalent to the right rule and point the Non-Terminal RHS symbol to it */
154  if(GET_PROD_NON_TERM(right->rule[ruleIndxR].prod[prodIterR].content) == 0)
155  {
156  ProtoRuleEntry* pRuleEntry;
157  unsigned int tmpIterL, tmpIterR;
158  boolean equalRRuleFound = FALSE;
159  boolean allRProdIn = TRUE;
160  boolean rProdFound = FALSE;
161 
162  // It is only an issue if we have productions in (right, ruleIndxR) that are not in (left, ruleIndxL); EE excluded
163  for(tmpIterR = 0; tmpIterR < right->rule[ruleIndxR].count; tmpIterR++)
164  {
165  if(GET_PROD_EXI_EVENT(right->rule[ruleIndxR].prod[tmpIterR].content) != EVENT_EE)
166  {
167  rProdFound = FALSE;
168  for(tmpIterL = 0; tmpIterL < left->rule[ruleIndxL].count; tmpIterL++)
169  {
170  if(GET_PROD_EXI_EVENT(right->rule[ruleIndxR].prod[tmpIterR].content) == GET_PROD_EXI_EVENT(left->rule[ruleIndxL].prod[tmpIterL].content))
171  {
172  rProdFound = TRUE;
173  break;
174  }
175  }
176 
177  if(rProdFound == FALSE)
178  {
179  allRProdIn = FALSE;
180  break;
181  }
182  }
183  }
184 
185  if(allRProdIn)
186  {
187  // All productions in (right, ruleIndxR) are available in (left, ruleIndxL)
188  nonTermRight = ruleIndxL;
189  }
190  else
191  {
192  // Try to find a rule in left, different from ruleIndxL that is equal to (right,ruleIndxR)
193  for(tmpIterL = 0; tmpIterL < left->count; tmpIterL++)
194  {
195  if(tmpIterL != ruleIndxL && rulesEqual(left, tmpIterL, right, ruleIndxR))
196  {
197  // We found a rule that is equal, then make the Non-TermS on the RHS pointing to it
198  nonTermRight = tmpIterL;
199  equalRRuleFound = TRUE;
200  break;
201  }
202  }
203 
204  if(equalRRuleFound == FALSE)
205  {
206  // Creating a new rule ...
207 
208  nonTermRight = *currRuleIndex;
209 
210  /* Create new rule entry in LHS proto grammar */
211  TRY(addProtoRule(left, right->rule[ruleIndxR].count, &pRuleEntry));
212 
213  /* Copy the RHS productions into the new rule entry, adjusting the non terminal ID */
214  for(tmpIterR = 0; tmpIterR < right->rule[ruleIndxR].count; tmpIterR++)
215  {
216  TRY(addProduction(pRuleEntry, GET_PROD_EXI_EVENT(right->rule[ruleIndxR].prod[tmpIterR].content),
217  right->rule[ruleIndxR].prod[tmpIterR].typeId, right->rule[ruleIndxR].prod[tmpIterR].qnameId,
218  GET_PROD_NON_TERM(right->rule[ruleIndxR].prod[tmpIterR].content) + ((GET_PROD_EXI_EVENT(right->rule[ruleIndxR].prod[tmpIterR].content) == EVENT_EE)?0:(initialLeftRulesCount-1))));
219  }
220 
221  *currRuleIndex += 1;
222  }
223  }
224  }
225  else
226  nonTermRight = GET_PROD_NON_TERM(right->rule[ruleIndxR].prod[prodIterR].content) + ((GET_PROD_EXI_EVENT(right->rule[ruleIndxR].prod[prodIterR].content) == EVENT_EE)?0:initialLeftRulesCount);
227 
228  for(prodIterL = 0; prodIterL < left->rule[ruleIndxL].count; prodIterL++)
229  {
230  /* Check for the same terminal symbol e.g. SE(qname) */
231  if(GET_PROD_EXI_EVENT(left->rule[ruleIndxL].prod[prodIterL].content) == GET_PROD_EXI_EVENT(right->rule[ruleIndxR].prod[prodIterR].content) &&
232  left->rule[ruleIndxL].prod[prodIterL].typeId == right->rule[ruleIndxR].prod[prodIterR].typeId &&
233  left->rule[ruleIndxL].prod[prodIterL].qnameId.uriId == right->rule[ruleIndxR].prod[prodIterR].qnameId.uriId &&
234  left->rule[ruleIndxL].prod[prodIterL].qnameId.lnId == right->rule[ruleIndxR].prod[prodIterR].qnameId.lnId)
235  {
236  /* Now check the non-terminal ID (noting that EE's don't have a non-terminal ID) */
237  if(GET_PROD_EXI_EVENT(left->rule[ruleIndxL].prod[prodIterL].content) == EVENT_EE ||
238  GET_PROD_NON_TERM(left->rule[ruleIndxL].prod[prodIterL].content) == nonTermRight)
239  {
240  /*
241  * If the NonTerminals are the same as well, no need to add
242  * the production as it's already there
243  */
244  rProdFoundInLeft = TRUE;
245  /* Check the next production in LHS... */
246  break;
247  }
248  else
249  {
250  // The LHS non-terminals are different for the two productions with the same terminal
251  // Check if the rules that are indicated by the terminals are equal
252  if(rulesEqual(left, GET_PROD_NON_TERM(left->rule[ruleIndxL].prod[prodIterL].content), left, nonTermRight))
253  {
254  // NonTerminals are different indexes but are otherwise equal
255  // no need to add the production as it's already there
256  rProdFoundInLeft = TRUE;
257  /* Check the next production in LHS... */
258  break;
259  }
260  else
261  {
262  // Collision: equal terminals and non-equal non-terminals
263  // We have a collision detected - must be traced why it happens
264  // From analysis of the spec, the only way that to happen is in
265  // <sequence> definition.
266  // When there are adjacent same definitions such as:
267  // <sequence><any> <any></sequence> or
268  // <sequence><element name="test"> <element name="test"></sequence>
269  // TODO: solve that!
270  assert(FALSE);
271  }
272  }
273  }
274  }
275 
276  if(rProdFoundInLeft == FALSE)
277  {
278  /*
279  * We have been through all LHS productions and there were no clashes
280  * so just add the production
281  */
282  TRY(addProduction(&left->rule[ruleIndxL],
283  GET_PROD_EXI_EVENT(right->rule[ruleIndxR].prod[prodIterR].content),
284  right->rule[ruleIndxR].prod[prodIterR].typeId,
285  right->rule[ruleIndxR].prod[prodIterR].qnameId,
286  nonTermRight));
287  }
288  }
289  return EXIP_OK;
290 }
291 
293 {
294  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
295  QNameID qnameID = {URI_MAX, LN_MAX};
296  ProtoRuleEntry* pRuleEntry;
297 
298  TRY(createProtoGrammar(2, simpleGrammar));
299 
300  TRY(addProtoRule(simpleGrammar, 3, &pRuleEntry));
301  TRY(addProduction(pRuleEntry, EVENT_CH, typeId, qnameID, 1));
302  TRY(addProtoRule(simpleGrammar, 2, &pRuleEntry));
303  TRY(addEEProduction(pRuleEntry));
304 
305  return EXIP_OK;
306 }
307 
309  boolean isMixedContent, ProtoGrammar* complexGrammar)
310 {
311  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
312  unsigned int i;
313 
314  if(isMixedContent && contentTypeGrammar != NULL)
315  {
316  /* If {content type} is a content model particle with mixed content, add a production for each non-terminal
317  * Content-i,j in Content-i as follows:
318  * Content-i,j : CH [untyped value] Content-i,j
319  */
320  QNameID dummyQId = {URI_MAX, LN_MAX};
321  for(i = 0; i < contentTypeGrammar->count; i++)
322  {
323  TRY(addProduction(&contentTypeGrammar->rule[i], EVENT_CH, INDEX_MAX, dummyQId, i));
324  }
325  }
326 
327  if(attrUseArray->count > 0)
328  {
329  ProtoRuleEntry* pRuleEntry;
330 
331  TRY(createProtoGrammar(10, complexGrammar));
332  TRY(addProtoRule(complexGrammar, 10, &pRuleEntry));
333  TRY(addEEProduction(pRuleEntry));
334 
335  for(i = 0; i < attrUseArray->count; i++)
336  {
337  TRY(concatenateGrammars(complexGrammar, attrUseArray->pg[i]));
338  }
339 
340  complexGrammar->contentIndex = complexGrammar->count - 1;
341 
342  if(contentTypeGrammar != NULL)
343  {
344  TRY(concatenateGrammars(complexGrammar, contentTypeGrammar));
345  }
346  }
347  else
348  {
349  if(contentTypeGrammar != NULL)
350  {
351  TRY(cloneProtoGrammar(contentTypeGrammar, complexGrammar));
352  }
353  complexGrammar->contentIndex = 0;
354  }
355 
356  return EXIP_OK;
357 }
358 
360 {
362 }
363 
364 errorCode createAttributeUseGrammar(boolean required, Index typeId,
365  ProtoGrammar* attrGrammar, QNameID qnameID)
366 {
367  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
368  ProtoRuleEntry* pRuleEntry;
369 
370  TRY(createProtoGrammar(2, attrGrammar));
371 
372  TRY(addProtoRule(attrGrammar, 4, &pRuleEntry));
373  TRY(addProduction(pRuleEntry, EVENT_AT_QNAME, typeId, qnameID, 1));
374 
375  if(!required)
376  {
377  TRY(addEEProduction(pRuleEntry));
378  }
379 
380  TRY(addProtoRule(attrGrammar, 4, &pRuleEntry));
381  TRY(addEEProduction(pRuleEntry));
382 
383  return EXIP_OK;
384 }
385 
386 errorCode createParticleGrammar(int minOccurs, int maxOccurs,
387  ProtoGrammar* termGrammar, ProtoGrammar* particleGrammar)
388 {
389  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
390  ProtoRuleEntry* pRuleEntry;
391  int i;
392 
393  TRY(createProtoGrammar(minOccurs + 10, particleGrammar));
394 
395  TRY(addProtoRule(particleGrammar, 5, &pRuleEntry));
396  TRY(addEEProduction(pRuleEntry));
397 
398  for(i = 0; i < minOccurs; i++)
399  {
400  TRY(concatenateGrammars(particleGrammar, termGrammar));
401  }
402 
403  if(maxOccurs - minOccurs > 0 || maxOccurs < 0) // Only if maxOccurs is unbounded or maxOccurs > minOccurs
404  {
405  boolean prodEEFound = FALSE;
406  for(i = 0; i < (int)termGrammar->rule[0].count; i++)
407  {
408  if(GET_PROD_EXI_EVENT(termGrammar->rule[0].prod[i].content) == EVENT_EE)
409  {
410  prodEEFound = TRUE;
411  break;
412  }
413  }
414  if(prodEEFound == FALSE) // There is no production Gi,0 : EE so add one
415  {
416  TRY(addEEProduction(&termGrammar->rule[0]));
417  }
418 
419  if(maxOccurs >= 0) // {max occurs} is not unbounded
420  {
421  for(i = 0; i < maxOccurs - minOccurs; i++)
422  {
423  TRY(concatenateGrammars(particleGrammar, termGrammar));
424  }
425  }
426  else // {max occurs} is unbounded
427  {
428  Index j = 0;
429  unsigned int currRuleIndex = termGrammar->count;
430 
431  // Excluding the first rule
432  for(i = 1; i < (int)termGrammar->count; i++)
433  {
434  for(j = 0; j < termGrammar->rule[i].count; j++)
435  {
436  if(GET_PROD_EXI_EVENT(termGrammar->rule[i].prod[j].content) == EVENT_EE)
437  {
438  if(!rulesEqual(termGrammar, i, termGrammar, 0))
439  {
440  /* Remove the EE production */
441  delDynEntry(&termGrammar->rule[i].dynArray, j);
442 
443  if(termGrammar->rule[i].count == 0)
444  {
445  Index prodIterR;
446  // Just copy all the production...
447  for(prodIterR = 0; prodIterR < termGrammar->rule[0].count; prodIterR++)
448  {
449  TRY(addProduction(&termGrammar->rule[i],
450  GET_PROD_EXI_EVENT(termGrammar->rule[0].prod[prodIterR].content),
451  termGrammar->rule[0].prod[prodIterR].typeId,
452  termGrammar->rule[0].prod[prodIterR].qnameId,
453  GET_PROD_NON_TERM(termGrammar->rule[0].prod[prodIterR].content)));
454  }
455  }
456  else
457  {
458  /* Merge productions from RHS rule 0 into each left rule */
459  TRY(addProductionsToARule(termGrammar,
460  i,
461  termGrammar,
462  0,
463  &currRuleIndex,
464  0));
465  }
466  }
467  break;
468  }
469  }
470  }
471 
472  TRY(concatenateGrammars(particleGrammar, termGrammar));
473  }
474  }
475 
476  return EXIP_OK;
477 }
478 
480 {
481  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
482  ProtoRuleEntry* pRuleEntry;
483  Index i;
484 
485  assert(qnameGrArr != NULL);
486 
487  TRY(createProtoGrammar(2, elemGrammar));
488  TRY(addProtoRule(elemGrammar, 5, &pRuleEntry));
489  for(i = 0; i < count; i++)
490  {
491  TRY(addProduction(pRuleEntry, EVENT_SE_QNAME, qnameGrArr[i].grIndex, qnameGrArr[i].qnameId, 1));
492  }
493 
494  TRY(addProtoRule(elemGrammar, 3, &pRuleEntry));
495  TRY(addEEProduction(pRuleEntry));
496 
497  return EXIP_OK;
498 }
499 
500 errorCode createWildcardTermGrammar(String* wildcardArray, Index wildcardArraySize, UriTable* uriT, ProtoGrammar* wildcardGrammar)
501 {
502  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
503  ProtoRuleEntry* pRuleEntry;
504  QNameID qnameID;
505 
506  TRY(createProtoGrammar(2, wildcardGrammar));
507 
508  TRY(addProtoRule(wildcardGrammar, wildcardArraySize + 1, &pRuleEntry));
509  if(wildcardArraySize == 0 || // default is "##any"
510  (wildcardArraySize == 1 &&
511  (stringEqualToAscii(wildcardArray[0], "##any") || stringEqualToAscii(wildcardArray[0], "##other"))
512  )
513  )
514  {
515  qnameID.uriId = URI_MAX;
516  qnameID.lnId = LN_MAX;
517  TRY(addProduction(pRuleEntry, EVENT_SE_ALL, INDEX_MAX, qnameID, 1));
518  }
519  else if(wildcardArraySize >= 1)
520  {
521  Index i;
522 
523  qnameID.lnId = LN_MAX;
524  for(i = 0; i < wildcardArraySize; i++)
525  {
526  if(!lookupUri(uriT, wildcardArray[i], &qnameID.uriId))
527  return EXIP_UNEXPECTED_ERROR;
528  TRY(addProduction(pRuleEntry, EVENT_SE_URI, INDEX_MAX, qnameID, 1));
529  }
530  }
531  else
532  return EXIP_UNEXPECTED_ERROR;
533 
534  TRY(addProtoRule(wildcardGrammar, 2, &pRuleEntry));
535  TRY(addEEProduction(pRuleEntry));
536 
537  return EXIP_OK;
538 }
539 
540 errorCode createSequenceModelGroupsGrammar(ProtoGrammar** grArray, unsigned int arrSize, ProtoGrammar* seqGrammar)
541 {
542  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
543  ProtoRuleEntry* pRuleEntry;
544 
545  if(arrSize == 0)
546  {
547  TRY(createProtoGrammar(3, seqGrammar));
548  TRY(addProtoRule(seqGrammar, 3, &pRuleEntry));
549  TRY(addEEProduction(pRuleEntry));
550  }
551  else
552  {
553  unsigned int i;
554 
555  TRY(createProtoGrammar(10, seqGrammar));
556  TRY(addProtoRule(seqGrammar, 5, &pRuleEntry));
557  TRY(addEEProduction(pRuleEntry));
558 
559  for(i = 0; i < arrSize; i++)
560  {
561  TRY(concatenateGrammars(seqGrammar, grArray[i]));
562  }
563  }
564  return EXIP_OK;
565 }
566 
568 {
569  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
570  Index i;
571  unsigned int ruleIterTerm = 0;
572  unsigned int prodIterTerm = 0;
573  unsigned int currRuleIndex;
574  unsigned int initialResultRulesCount;
575  ProtoGrammar* tmpGrammar;
576  ProtoRuleEntry* pRuleEntry;
577 
578  TRY(createProtoGrammar(10, modGrpGrammar));
579 
580  TRY(addProtoRule(modGrpGrammar, 5, &pRuleEntry));
581  TRY(addEEProduction(pRuleEntry));
582 
583  tmpGrammar = pgArray->pg[0];
584  if(tmpGrammar == NULL)
585  return EXIP_NULL_POINTER_REF;
586 
587  TRY(concatenateGrammars(modGrpGrammar, tmpGrammar));
588 
589  for(i = 1; i < pgArray->count; i++)
590  {
591 
592  tmpGrammar = pgArray->pg[i];
593 
594  if(tmpGrammar == NULL)
595  return EXIP_NULL_POINTER_REF;
596 
597  initialResultRulesCount = modGrpGrammar->count;
598 
599  for(ruleIterTerm = 1; ruleIterTerm < tmpGrammar->count; ruleIterTerm++)
600  {
601  TRY(addProtoRule(modGrpGrammar, 5, &pRuleEntry));
602 
603  for(prodIterTerm = 0; prodIterTerm < tmpGrammar->rule[ruleIterTerm].count; prodIterTerm++)
604  {
605  TRY(addProduction(pRuleEntry,
606  GET_PROD_EXI_EVENT(tmpGrammar->rule[ruleIterTerm].prod[prodIterTerm].content),
607  tmpGrammar->rule[ruleIterTerm].prod[prodIterTerm].typeId,
608  tmpGrammar->rule[ruleIterTerm].prod[prodIterTerm].qnameId,
609  GET_PROD_NON_TERM(tmpGrammar->rule[ruleIterTerm].prod[prodIterTerm].content) + ((GET_PROD_EXI_EVENT(tmpGrammar->rule[ruleIterTerm].prod[prodIterTerm].content) == EVENT_EE)?0:(initialResultRulesCount-1))));
610  }
611  }
612 
613  currRuleIndex = modGrpGrammar->count;
614 
615  if(!rulesEqual(modGrpGrammar, 0, tmpGrammar, 0))
616  {
617  if(modGrpGrammar->rule[0].count == 0)
618  {
619  Index prodIterR;
620  // Just copy all the production...
621  for(prodIterR = 0; prodIterR < tmpGrammar->rule[0].count; prodIterR++)
622  {
623  TRY(addProduction(&modGrpGrammar->rule[0],
624  GET_PROD_EXI_EVENT(tmpGrammar->rule[0].prod[prodIterR].content),
625  tmpGrammar->rule[0].prod[prodIterR].typeId,
626  tmpGrammar->rule[0].prod[prodIterR].qnameId,
627  GET_PROD_NON_TERM(tmpGrammar->rule[0].prod[prodIterR].content) + ((GET_PROD_EXI_EVENT(tmpGrammar->rule[0].prod[prodIterR].content) == EVENT_EE)?0:(initialResultRulesCount-1))));
628  }
629  }
630  else
631  {
632  /* Merge productions from RHS rule 0 into each left rule */
633  TRY(addProductionsToARule(modGrpGrammar,
634  0,
635  tmpGrammar,
636  0,
637  &currRuleIndex,
638  initialResultRulesCount - 1));
639  }
640  }
641  }
642 
643  return EXIP_OK;
644 }
645 
646 errorCode createAllModelGroupsGrammar(ProtoGrammar* pTermArray, unsigned int pTermArraySize, ProtoGrammar* modGrpGrammar)
647 {
649 }
650 
652 {
653  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
654  Production *prod;
655  Index prodId;
656 
657  TRY(addEmptyDynEntry(&rule->dynArray, (void**)&prod, &prodId));
658 
660  prod->typeId = INDEX_MAX;
662  prod->qnameId.uriId = URI_MAX;
663  prod->qnameId.lnId = LN_MAX;
664 
665  return EXIP_OK;
666 }
667 
668 int compareQNameID(const void* qnameID1, const void* qnameID2, UriTable* uriTbl)
669 {
674  QNameID* qId1 = (QNameID*) qnameID1;
675  QNameID* qId2 = (QNameID*) qnameID2;
676 
677  if(qId1->uriId == qId2->uriId)
678  {
679  // Within the same namespace
680  if(qId1->lnId < qId2->lnId)
681  {
682  return -1;
683  }
684  else if(qId1->lnId > qId2->lnId)
685  {
686  return 1;
687  }
688  }
689  else
690  {
691  // In different namespaces
692  int i;
693  i = stringCompare(GET_LN_P_URI_P_QNAME(uriTbl, qId1).lnStr, GET_LN_P_URI_P_QNAME(uriTbl, qId2).lnStr);
694  if(i == 0)
695  {
696  if(qId1->uriId < qId2->uriId)
697  {
698  return -1;
699  }
700  else if(qId1->uriId > qId2->uriId)
701  {
702  return 1;
703  }
704  }
705  else
706  return i;
707  }
708 
709  return 0;
710 }
711 
712 static char rulesEqual(ProtoGrammar* g1, Index ruleIndx1, ProtoGrammar* g2, Index ruleIndx2)
713 {
714  Index i, j;
715  boolean prodFound;
716 
717  // TODO: currently it does not follow the right hand side non-terminals to check if the state there is the same...
718  // It might not be needed; if needed there will be a recursive call that might lag a lot
719 
720  if(g1->rule[ruleIndx1].count != g2->rule[ruleIndx2].count)
721  return FALSE;
722 
723  for(i = 0; i < g1->rule[ruleIndx1].count; i++)
724  {
725  prodFound = FALSE;
726  for(j = 0; j < g2->rule[ruleIndx2].count; j++)
727  {
728  if(GET_PROD_EXI_EVENT(g1->rule[ruleIndx1].prod[i].content) == GET_PROD_EXI_EVENT(g2->rule[ruleIndx2].prod[j].content) &&
729  g1->rule[ruleIndx1].prod[i].typeId == g2->rule[ruleIndx2].prod[j].typeId &&
730  g1->rule[ruleIndx1].prod[i].qnameId.uriId == g2->rule[ruleIndx2].prod[j].qnameId.uriId &&
731  g1->rule[ruleIndx1].prod[i].qnameId.lnId == g2->rule[ruleIndx2].prod[j].qnameId.lnId)
732  {
733  prodFound = TRUE;
734  break;
735  }
736  }
737 
738  if(!prodFound)
739  return FALSE;
740  }
741 
742  return TRUE;
743 }