1 /* This files solves the problems with instore macros.
2 * While parsing a special tree of type tnode is created
3 * and fold together with containing strings to one big
4 * beast (called a tinned tree, american: canned heat :-) ).
5 * Then we have two objects: a special tree and the tinned tree.
6 * There is a one to one releationship between them.
7 * The tinned tree may be expanded to a tree by ExpandTinnedTree().
8 * The tree is tinned by TinTree() which should only be called from
9 * the lexical analyser.
10 * We are protected against multithreading while normal parsing.
11 * Destroying the tree and tinning/expanding is done in
19 /* We begin with some odd tricks. We want a fast but memory
20 * saving routine to build the tree. We don't want to copy
21 * tree leaves more than one. Thus we pack them into buckets.
22 * This allows a very fast kind of searching. Keep in mind
23 * that we must create a pointerless list which is included
26 * This structure is called ttree, have a look at types.h.
28 * DEFAULT_TTREE_ELEMS defines the normal number of elements in the ttree.
29 * The more elements the better is the performance in searching. The less
30 * elements the better is the memory waste overhead. We want some more space
31 * than MAX_INTERNAL_SIZE in memory.c. This leads to "normal" memory
32 * allocation and can be freed without problems if we parse a nested
33 * Rexx program. This is currently 2048. We allocate nearly 8K. This
34 * will give a reasonable performance and a slight overhead for
35 * external(!) functions, 4K in the middle.
37 #define DEFAULT_TTREE_ELEMS (8192 / sizeof(treenode))
39 /* Same as before but for offsrclines: */
40 #define DEFAULT_OTREE_ELEMS (4096 / sizeof(offsrcline))
42 static ttree
*CurrentT
= NULL
;
43 static otree
*CurrentO
= NULL
;
44 static nodeptr Reused
= NULL
;
45 static const char MagicHeader
[] = MAGIC
;
47 /* NewProg indicates the start of a new parsing sequence. We don't allow
48 * a nesting call. In case of an error is is the job of fetch_... to do the
53 CurrentT
= NULL
; /* Trivial */
54 CurrentO
= NULL
; /* Trivial */
55 Reused
= NULL
; /* Can't reuse stuff of another parsing process */
58 /* EndProg is called at the end of the parsing process. Start is the
59 * starting element of the later interpreter tree.
60 * parser_data.root is assigned.
62 void EndProg(nodeptr Start
)
64 parser_data
.root
= Start
; /* trivial, too */
67 Reused
= NULL
; /* Can't reuse stuff of another parsing process */
70 /* FreshNode returns a new ttree element. Call only within a NewProg/EndProg
72 * If you don't want the returned node WHILE PARSING because you want to do
73 * some tricks the the node at a later time, you are allowed to call
74 * RejectNode(). Rejected nodes are tried to be passed back to the used
77 nodeptr
FreshNode(void)
81 if (Reused
!= NULL
) /* This should be put back first */
84 Reused
= Reused
->next
;
85 h
->next
= NULL
; /* Everything except nodeindex is 0 now */
89 if (CurrentT
&& (CurrentT
->num
< CurrentT
->max
)) /* bucket not full */
91 memset(CurrentT
->elems
+ CurrentT
->num
, 0, sizeof(treenode
));
92 CurrentT
->elems
[CurrentT
->num
].nodeindex
= CurrentT
->sum
+ CurrentT
->num
;
93 return(CurrentT
->elems
+ CurrentT
->num
++);
96 if (CurrentT
== NULL
) /* First call */
98 parser_data
.nodes
= Malloc_TSD(parser_data
.TSD
, sizeof(ttree
));
99 CurrentT
= parser_data
.nodes
;
102 else /* current bucket is full */
104 CurrentT
->next
= Malloc_TSD(parser_data
.TSD
, sizeof(ttree
));
105 CurrentT
->next
->sum
= CurrentT
->sum
+ CurrentT
->num
;
106 CurrentT
= CurrentT
->next
;
110 CurrentT
->next
= NULL
;
111 CurrentT
->max
= DEFAULT_TTREE_ELEMS
;
113 CurrentT
->elems
= Malloc_TSD(parser_data
.TSD
,
114 CurrentT
->max
* sizeof(treenode
));
116 memset(CurrentT
->elems
, 0, sizeof(treenode
));
117 CurrentT
->elems
[0].nodeindex
= CurrentT
->sum
;
118 return(CurrentT
->elems
);
121 /* RejectNode gives the argument back to the pool of unused treenode entries
122 * which are managed and passed back by FreshNode().
123 * You should use the function ONLY IF YOU ARE WITHING THE PARSING PROCESS!
124 * It is not guaranteed that the memory of the entry is freed. It can only
126 * Note that the content of the entry is NOT FREED in any kind.
128 void RejectNode(nodeptr NoLongerUsed
)
132 assert(CurrentT
!= NULL
);
133 /* CurrentT == NULL can't happen, since CurrentT is only set within the
134 * parsing process while at least one treenode has been returned.
136 if (CurrentT
== NULL
) /* In case of no assertion we return simply */
139 /* Save exactly the nodeindex and destroy everything else */
140 idx
= NoLongerUsed
->nodeindex
;
141 memset(NoLongerUsed
, 0, sizeof(treenode
)); /* Clean it up */
142 NoLongerUsed
->nodeindex
= idx
;
144 NoLongerUsed
->next
= Reused
;
145 Reused
= NoLongerUsed
;
148 /* FreshLine returns a new otree element. Call only within a NewProg/EndProg
151 offsrcline
*FreshLine(void)
153 if (CurrentO
&& (CurrentO
->num
< CurrentO
->max
)) /* bucket not full */
155 memset(CurrentO
->elems
+ CurrentO
->num
, 0, sizeof(offsrcline
));
156 return(CurrentO
->elems
+ CurrentO
->num
++);
159 if (CurrentO
== NULL
) /* First call */
161 parser_data
.nodes
= Malloc_TSD(parser_data
.TSD
, sizeof(otree
));
162 CurrentO
= parser_data
.srclines
;
165 else /* current bucket is full */
167 CurrentO
->next
= Malloc_TSD(parser_data
.TSD
, sizeof(otree
));
168 CurrentO
->next
->sum
= CurrentO
->sum
+ CurrentO
->num
;
169 CurrentO
= CurrentO
->next
;
173 CurrentO
->next
= NULL
;
174 CurrentO
->max
= DEFAULT_OTREE_ELEMS
;
176 CurrentO
->elems
= Malloc_TSD(parser_data
.TSD
,
177 CurrentO
->max
* sizeof(offsrcline
));
179 memset(CurrentO
->elems
, 0, sizeof(offsrcline
));
180 return(CurrentO
->elems
);
183 /*****************************************************************************
184 *****************************************************************************
185 * start of the multithreaded part *******************************************
186 *****************************************************************************
187 *****************************************************************************/
190 /* DestroyNode kills all allocated elements within a nodeptr
191 * without freeing the node itself.
193 static void DestroyNode(const tsd_t
*TSD
, nodeptr p
)
198 Free_stringTSD( p
->name
) ;
204 if (type
== X_CON_SYMBOL
|| type
== X_STRING
)
208 FreeTSD( p
->u
.number
->num
) ;
209 FreeTSD( p
->u
.number
) ;
212 if (type
==X_SIM_SYMBOL
|| type
==X_STEM_SYMBOL
|| type
==X_HEAD_SYMBOL
||
213 type
==X_CTAIL_SYMBOL
|| type
==X_VTAIL_SYMBOL
)
217 detach( TSD
, p
->u
.varbx
) ;
221 if (type
== X_CEXPRLIST
)
224 Free_stringTSD( p
->u
.strng
) ;
228 /* DestroyInternalParsingTree frees all allocated memory used by a parsing
229 * tree. The structure itself is not freed.
231 void DestroyInternalParsingTree(const tsd_t
*TSD
, internal_parser_type
*ipt
)
242 /* Cleanup all the nodes */
243 if (ipt
->nodes
!= NULL
)
249 for (i
= 0; i
< tr
->num
; i
++)
250 DestroyNode(TSD
, tr
->elems
+ i
);
259 ipt
->root
= NULL
; /* not really needed */
261 /* Cleanup all the lineboxes */
262 if (ipt
->first_source_line
!= NULL
)
264 lr
= ipt
->first_source_line
;
269 Free_stringTSD(lr
->line
);
274 ipt
->first_source_line
= ipt
->last_source_line
= NULL
;
277 /* Cleanup all the labelboxes */
278 if (ipt
->first_label
!= NULL
)
280 ar
= ipt
->first_label
;
289 ipt
->first_label
= ipt
->last_label
= NULL
;
292 if (ipt
->sort_labels
!= NULL
)
294 FreeTSD(ipt
->sort_labels
);
296 ipt
->sort_labels
= NULL
;
299 /* Cleanup the incore sourceline informations */
300 /* Cleanup all the nodes */
301 if (ipt
->srclines
!= NULL
)
313 ipt
->srclines
= NULL
;
316 Free_stringTSD(ipt
->kill
);
320 /* ExpandTinnedTree expands the external tree from a former parsing operation
321 * to a fully usable tree. All allocations and relacations are done to fake
322 * a normal parsing operation.
323 * The external tree won't be used any longer after this operation but the
324 * external tree must have been checked before this operation.
325 * The freshly allocated tree is returned.
327 internal_parser_type
ExpandTinnedTree(const tsd_t
*TSD
,
328 const external_parser_type
*ept
,
330 const char *incore_source
,
331 unsigned long incore_source_length
)
333 internal_parser_type ipt
;
336 const offsrcline
*lastsrcline
;
339 memset(&ipt
, 0, sizeof(ipt
));
341 /* We build the sourcelines first *****************************************/
342 if (incore_source_length
== 0)
343 incore_source
= NULL
;
344 if (ept
->NumberOfSourceLines
== 0)
345 incore_source
= NULL
;
346 if (incore_source
) /* Its worth to check exactly */
348 lastsrcline
= (const offsrcline
*) ((char *) ept
+ ept
->source
);
349 lastsrcline
+= ept
->NumberOfSourceLines
- 1;
350 j
= lastsrcline
->length
+ lastsrcline
->offset
;
351 /* j shall be very close to the end of the source string. It may
352 * follow a linefeed (or carriage return/linefeed) and probably a
353 * ^Z for CP/M descendents which includes Microsoft products. It's
354 * fais to assume the following check:
356 if ((j
> incore_source_length
) ||
357 (j
+ 3 < incore_source_length
))
358 incore_source
= NULL
;
360 if (incore_source
) /* We are sure enough to use the source string */
362 ipt
.incore_source
= incore_source
;
363 ipt
.srclines
= MallocTSD(sizeof(otree
));
364 ipt
.srclines
->sum
= 0;
365 ipt
.srclines
->next
= NULL
;
366 ipt
.srclines
->max
= ept
->NumberOfSourceLines
;
367 ipt
.srclines
->num
= ipt
.nodes
->max
;
368 ipt
.srclines
->elems
= MallocTSD(ipt
.srclines
->num
* sizeof(offsrcline
));
369 memcpy(ipt
.srclines
->elems
,
370 (char *) ept
+ ept
->source
,
371 ipt
.srclines
->num
* sizeof(offsrcline
));
373 /**************************************************************************/
375 ipt
.tline
= -1; /* unused */
376 ipt
.tstart
= -1; /* unused */
377 ipt
.result
= 0; /* unused */
378 ipt
.first_label
= ipt
.last_label
= NULL
; /* initialize it for newlabel() */
379 ipt
.numlabels
= 0; /* initialize it for newlabel() */
380 ipt
.sort_labels
= NULL
; /* initialize it for newlabel() */
382 ipt
.nodes
= MallocTSD(sizeof(ttree
));
384 ipt
.nodes
->next
= NULL
;
385 ipt
.nodes
->max
= ept
->NumberOfTreeElements
;
386 ipt
.nodes
->num
= ipt
.nodes
->max
;
387 ipt
.nodes
->elems
= MallocTSD(ipt
.nodes
->num
* sizeof(treenode
));
389 memcpy(ipt
.nodes
->elems
,
390 (char *) ept
+ ept
->tree
,
391 ipt
.nodes
->num
* sizeof(treenode
));
392 ipt
.root
= ipt
.nodes
->elems
+ ept
->TreeStart
;
394 /* Everything is ready for a relocation step. Don't forget to *************
395 * create the labelboxes as necessary.
397 for (i
= 0;i
< ept
->NumberOfTreeElements
;i
++)
399 this = ipt
.nodes
->elems
+ i
;
402 es
= (extstring
*) ((char *) ept
+ (unsigned long) this->name
);
403 this->name
= Str_makeTSD(es
->length
);
404 this->name
->len
= es
->length
;
405 memcpy(this->name
->value
,
406 es
+ 1 /* position of string content */,
411 es
= (extstring
*) ((char *) ept
+ (unsigned long) this->u
.strng
);
412 this->u
.strng
= Str_makeTSD(es
->length
);
413 this->u
.strng
->len
= es
->length
;
414 memcpy(this->u
.strng
->value
,
415 es
+ 1 /* position of string content */,
419 if (this->type
== X_LABEL
)
420 newlabel(TSD
, &ipt
, this);
422 if (this->next
== (nodeptr
) (unsigned long) -1)
425 this->next
= ipt
.nodes
->elems
+ (unsigned long) this->next
;
426 for (j
= 0;j
< sizeof(this->p
) / sizeof(this->p
[0]);j
++)
428 if (this->p
[j
] == (nodeptr
) (unsigned long) -1)
431 this->p
[j
] = ipt
.nodes
->elems
+ (unsigned long) this->p
[j
];
434 size
= size
; /* keep compiler happy */
439 /* We must take care of the alignment of structure. We may get a SIGBUS in
440 * the following if we don't do it. We assume that an alignment for an
441 * unsigned long is sufficient for all types including structures. We also
442 * assume a power of two for an unsigned's size.
444 #define USIZ sizeof(unsigned long)
445 #define USIZ_1 (USIZ-1)
446 /* Wastes one byte in average but is much faster */
447 #define StringSize(s) (((sizeof(extstring)+s->len)|USIZ_1)+1)
449 static unsigned long ComputeExternalSize(const internal_parser_type
*ipt
,
450 unsigned long *SourceLines
,
451 unsigned long *Nodes
)
456 unsigned long size
= sizeof(external_parser_type
);
457 unsigned long i
, elems
, bufchars
;
459 /* sourceline table */
467 *SourceLines
= elems
;
468 size
+= elems
* sizeof(offsrcline
); /* the table */
471 elems
= bufchars
= 0;
474 for (i
= 0;i
< ttp
->num
;i
++)
479 bufchars
+= StringSize(np
->name
);
481 if ((np
->type
== X_CEXPRLIST
) && np
->u
.strng
)
482 /* should be save, since it isn't computed after the parsing step.*/
483 bufchars
+= StringSize(np
->u
.strng
);
488 size
+= elems
* sizeof(treenode
);
491 size
+= sizeof(((external_parser_type
*)0)->Magic
);
495 /* FillStrings copies all offsrclines from the otree to base+start
497 * The index just beyond the last copied byte is returned.
499 static unsigned long FillStrings(char *base
, unsigned long start
, const otree
*otp
)
503 memcpy(base
+ start
, otp
->elems
, otp
->num
* sizeof(offsrcline
));
504 start
+= otp
->num
* sizeof(offsrcline
);
510 /* FillTree copies all treenodes of the ttree to base+buf in a relocatable
511 * manner. Look at ExpandTinnedTree() or types.h for a description.
512 * Each treenode is copied to the table and the containing strings are copied
513 * as extstrings to base+start which is incremented.
514 * The table must be large enough.
515 * The index just beyond the last copied character is returned.
517 static unsigned long FillTree(treenode
*table
, char *base
, unsigned long start
,
526 for (i
= 0;i
< ttp
->num
;i
++)
528 np
= (cnodeptr
) (ttp
->elems
+ i
);
529 *table
= *np
; /* Full copy includes unnecessary stuff but is fast */
533 table
->name
= (streng
*) start
;
534 e
= (extstring
*) (base
+ start
);
535 e
->length
= np
->name
->len
;
536 memcpy(e
+ 1 /* just beyond the head */, np
->name
->value
, e
->length
);
537 start
+= StringSize(np
->name
);
540 if ((np
->type
== X_CEXPRLIST
) && np
->u
.strng
)
542 table
->u
.strng
= (streng
*) start
;
543 e
= (extstring
*) (base
+ start
);
544 e
->length
= np
->u
.strng
->len
;
545 memcpy(e
+ 1, np
->u
.strng
->value
, e
->length
);
546 start
+= StringSize(np
->u
.strng
);
549 table
->u
.strng
= 0; /* Be sure not to run into troubles */
551 if (table
->next
== NULL
)
552 table
->next
= (nodeptr
) (unsigned long) -1;
554 table
->next
= (nodeptr
) np
->next
->nodeindex
;
555 for (j
= 0;j
< sizeof(np
->p
) / sizeof(np
->p
[0]);j
++)
557 if (table
->p
[j
] == NULL
)
558 table
->p
[j
] = (nodeptr
) (unsigned long) -1;
560 table
->p
[j
] = (nodeptr
) np
->p
[j
]->nodeindex
;
570 /* TinTree "tins" a tree into an external structure. The complete structure
571 * is allocated by one call to IfcAllocateMemory. The returned value shall
572 * be used as an instore macro for RexxStart.
573 * *length is set to the allocated size of the memory block on return.
574 * ExpandedTinnedTree can expand the returned value and IaValidTin checks it.
576 external_parser_type
*TinTree(const tsd_t
*TSD
,
577 const internal_parser_type
*ipt
,
578 unsigned long *length
)
580 external_parser_type
*retval
;
581 unsigned long srclines
, nodecount
, len
;
583 *length
= ComputeExternalSize(ipt
, &srclines
, &nodecount
);
585 retval
= IfcAllocateMemory(*length
);
588 memset(retval
, 0, sizeof(external_parser_type
));
590 /* Build the envelope */
591 len
= sizeof(MagicHeader
); /* includes a terminating 0 */
592 if (len
> sizeof(retval
->Magic
))
593 len
= sizeof(retval
->Magic
);
594 memcpy(retval
->Magic
, MagicHeader
, len
);
595 len
= sizeof(PARSE_VERSION_STRING
);
596 if (len
> sizeof(retval
->ReginaVersion
))
597 len
= sizeof(retval
->ReginaVersion
);
598 memcpy(retval
->ReginaVersion
, PARSE_VERSION_STRING
, len
);
600 retval
->arch_detector
.s
.one
= 1;
601 retval
->arch_detector
.s
.two
= 2;
602 retval
->arch_detector
.s
.ptr3
= (void *)3;
603 retval
->arch_detector
.s
.ptr4
= (void *)4;
604 retval
->OverallSize
= (unsigned long) *length
;
605 retval
->NumberOfSourceLines
= srclines
;
606 retval
->version
= INSTORE_VERSION
;
607 retval
->NumberOfTreeElements
= nodecount
;
609 retval
->source
= sizeof(external_parser_type
);
610 len
= FillStrings((char *) retval
,
611 sizeof(external_parser_type
),
615 retval
->TreeStart
= ipt
->root
->nodeindex
;
616 len
= FillTree((treenode
*) ((char *) retval
+ len
),
618 len
+ nodecount
*sizeof(treenode
),
621 memcpy((char *) retval
+ len
, retval
->Magic
, sizeof(retval
->Magic
));
623 assert((unsigned long) len
+ sizeof(retval
->Magic
) == *length
);
625 /* DEBUGGING: return NULL if you don't want tinned trees */
626 TSD
= TSD
; /* keep compiler happy */
630 /* IsValidTin returns 1 if the structure ept if of length eptlen and seems
631 * to contain a valid parsing tree. 0 is returned if this is not the case.
633 int IsValidTin(const external_parser_type
*ept
, unsigned long eptlen
)
635 char Magic
[sizeof(((external_parser_type
*)0)->Magic
)];
638 /* Some paranoia tests first: */
639 if ((ept
== NULL
) || (eptlen
< sizeof(external_parser_type
)))
642 /* Be sure to fill Magic as described */
643 memset(Magic
, 0, sizeof(Magic
));
644 len
= sizeof(MagicHeader
); /* includes a terminating 0 */
645 if (len
> sizeof(ept
->Magic
))
646 len
= sizeof(ept
->Magic
);
647 memcpy(Magic
, MagicHeader
, len
);
649 if (memcmp(Magic
, ept
->Magic
, sizeof(Magic
)) != 0)
652 if ((ept
->arch_detector
.s
.one
!= 1) ||
653 (ept
->arch_detector
.s
.two
!= 2) ||
654 (ept
->arch_detector
.s
.ptr3
!= (void *)3) ||
655 (ept
->arch_detector
.s
.ptr4
!= (void *)4))
658 if (ept
->OverallSize
!= eptlen
)
661 if (ept
->version
!= INSTORE_VERSION
)
665 (char *) ept
+ eptlen
- sizeof(Magic
),