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 regina_t.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
= (ttree
*)Malloc_TSD(parser_data
.TSD
, sizeof(ttree
));
99 CurrentT
= parser_data
.nodes
;
102 else /* current bucket is full */
104 CurrentT
->next
= (ttree
*)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
= (treenode
*)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
.srclines
= (otree
*)Malloc_TSD(parser_data
.TSD
, sizeof(otree
));
162 CurrentO
= parser_data
.srclines
;
165 else /* current bucket is full */
167 CurrentO
->next
= (otree
*)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
= (offsrcline
*)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
= (otree
*)MallocTSD(sizeof(otree
));
364 ipt
.srclines
->sum
= 0;
365 ipt
.srclines
->next
= NULL
;
366 ipt
.srclines
->max
= ept
->NumberOfSourceLines
;
367 ipt
.srclines
->num
= ipt
.srclines
->max
;
368 ipt
.srclines
->elems
= (offsrcline
*)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
= (ttree
*)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
= (treenode
*)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 thisptr
= ipt
.nodes
->elems
+ i
;
402 es
= (extstring
*) ((char *) ept
+ (unsigned long) thisptr
->name
);
403 thisptr
->name
= Str_makeTSD(es
->length
);
404 thisptr
->name
->len
= es
->length
;
405 memcpy(thisptr
->name
->value
,
406 es
+ 1 /* position of string content */,
411 * Do things the parsing step would have do. Simple values in thisptr->u
412 * are copied already.
416 * See also several places in this file and in debug.c where this
417 * switch list must be changed. Seek for X_CEXPRLIST.
419 switch ( thisptr
->type
)
422 if ( thisptr
->u
.strng
)
424 es
= (extstring
*) ((char *) ept
+ (unsigned long) thisptr
->u
.strng
);
425 thisptr
->u
.strng
= Str_makeTSD( es
->length
);
426 thisptr
->u
.strng
->len
= es
->length
;
427 memcpy( thisptr
->u
.strng
->value
,
428 es
+ 1 /* position of string content */,
434 newlabel(TSD
, &ipt
, thisptr
);
441 if (thisptr
->next
== (nodeptr
) (unsigned long) -1)
442 thisptr
->next
= NULL
;
444 thisptr
->next
= ipt
.nodes
->elems
+ (unsigned long) thisptr
->next
;
445 for (j
= 0;j
< sizeof(thisptr
->p
) / sizeof(thisptr
->p
[0]);j
++)
447 if (thisptr
->p
[j
] == (nodeptr
) (unsigned long) -1)
448 thisptr
->p
[j
] = NULL
;
450 thisptr
->p
[j
] = ipt
.nodes
->elems
+ (unsigned long) thisptr
->p
[j
];
453 size
= size
; /* keep compiler happy */
458 /* We must take care of the alignment of structure. We may get a SIGBUS in
459 * the following if we don't do it. We assume that an alignment for an
460 * unsigned long is sufficient for all types including structures. We also
461 * assume a power of two for an unsigned's size.
463 #define USIZ sizeof(unsigned long)
464 #define USIZ_1 (USIZ-1)
465 /* Wastes one byte in average but is much faster */
466 #define StringSize(s) (((sizeof(extstring)+s->len)|USIZ_1)+1)
468 static unsigned long ComputeExternalSize(const internal_parser_type
*ipt
,
469 unsigned long *SourceLines
,
470 unsigned long *Nodes
)
475 unsigned long size
= sizeof(external_parser_type
);
476 unsigned long i
, elems
, bufchars
;
478 /* sourceline table */
480 if ((otp
= ipt
->srclines
) == NULL
)
482 if (ipt
->last_source_line
)
484 elems
= ipt
->last_source_line
->lineno
;
491 elems
= otp
->sum
+ otp
->num
;
493 *SourceLines
= elems
;
494 size
+= elems
* sizeof(offsrcline
); /* the table */
497 elems
= bufchars
= 0;
501 for (i
= 0;i
< ttp
->num
;i
++)
506 bufchars
+= StringSize(np
->name
);
509 * Add all sizes of strings that have been generated at the parsing
514 * See also several places in this file and in debug.c where this
515 * switch list must be changed. Seek for X_CEXPRLIST.
521 bufchars
+= StringSize( np
->u
.strng
);
531 size
+= elems
* sizeof(treenode
);
534 size
+= sizeof(((external_parser_type
*)0)->Magic
);
538 /* FillStrings copies all offsrclines from the otree to base+start
540 * The index just beyond the last copied byte is returned.
542 static unsigned long FillStrings(char *base
, unsigned long start
,
549 memcpy(base
+ start
, otp
->elems
, otp
->num
* sizeof(offsrcline
));
550 start
+= otp
->num
* sizeof(offsrcline
);
557 /* FillTree copies all treenodes of the ttree to base+buf in a relocatable
558 * manner. Look at ExpandTinnedTree() or regina_t.h for a description.
559 * Each treenode is copied to the table and the containing strings are copied
560 * as extstrings to base+start which is incremented.
561 * The table must be large enough.
562 * The index just beyond the last copied character is returned.
564 static unsigned long FillTree(treenode
*table
, char *base
, unsigned long start
,
573 for (i
= 0;i
< ttp
->num
;i
++)
575 np
= (cnodeptr
) (ttp
->elems
+ i
);
576 *table
= *np
; /* Full copy includes unnecessary stuff but is fast */
580 table
->name
= (streng
*) start
;
581 e
= (extstring
*) (base
+ start
);
582 e
->length
= np
->name
->len
;
583 memcpy(e
+ 1 /* just beyond the head */, np
->name
->value
, e
->length
);
584 start
+= StringSize(np
->name
);
588 * Remove all "flags" from the target and copy only approved values
589 * the parser computes already.
591 memset( &table
->u
, 0, sizeof( table
->u
) );
594 * See also several places in this file and in debug.c where this
595 * switch list must be changed. Seek for X_CEXPRLIST.
605 table
->u
.flags
= np
->u
.flags
;
612 table
->u
.parseflags
= np
->u
.parseflags
;
616 table
->u
.nonansi
= np
->u
.nonansi
;
622 table
->u
.strng
= (streng
*) start
;
623 e
= (extstring
*) (base
+ start
);
624 e
->length
= np
->u
.strng
->len
;
625 memcpy(e
+ 1, np
->u
.strng
->value
, e
->length
);
626 start
+= StringSize(np
->u
.strng
);
631 table
->u
.trace_only
= np
->u
.trace_only
;
635 if ( !np
->p
[0] && !np
->p
[1] && !np
->p
[2] )
636 table
->u
.of
= np
->u
.of
;
643 if (table
->next
== NULL
)
644 table
->next
= (nodeptr
) (unsigned long) -1;
646 table
->next
= (nodeptr
) np
->next
->nodeindex
;
647 for (j
= 0;j
< sizeof(np
->p
) / sizeof(np
->p
[0]);j
++)
649 if (table
->p
[j
] == NULL
)
650 table
->p
[j
] = (nodeptr
) (unsigned long) -1;
652 table
->p
[j
] = (nodeptr
) np
->p
[j
]->nodeindex
;
662 /* TinTree "tins" a tree into an external structure. The complete structure
663 * is allocated by one call to IfcAllocateMemory. The returned value shall
664 * be used as an instore macro for RexxStart.
665 * *length is set to the allocated size of the memory block on return.
666 * ExpandedTinnedTree can expand the returned value and IsValidTin checks it.
668 external_parser_type
*TinTree(const tsd_t
*TSD
,
669 const internal_parser_type
*ipt
,
670 unsigned long *length
)
672 external_parser_type
*retval
;
673 unsigned long srclines
, nodecount
, len
;
675 *length
= ComputeExternalSize(ipt
, &srclines
, &nodecount
);
677 retval
= (external_parser_type
*)IfcAllocateMemory(*length
);
680 memset(retval
, 0, sizeof(external_parser_type
));
682 /* Build the envelope */
683 len
= sizeof(MagicHeader
); /* includes a terminating 0 */
684 if (len
> sizeof(retval
->Magic
))
685 len
= sizeof(retval
->Magic
);
686 memcpy(retval
->Magic
, MagicHeader
, len
);
687 len
= sizeof(PARSE_VERSION_STRING
);
688 if (len
> sizeof(retval
->ReginaVersion
))
689 len
= sizeof(retval
->ReginaVersion
);
690 memcpy(retval
->ReginaVersion
, PARSE_VERSION_STRING
, len
);
692 retval
->arch_detector
.s
.one
= 1;
693 retval
->arch_detector
.s
.two
= 2;
694 retval
->arch_detector
.s
.ptr3
= (void *)3;
695 retval
->arch_detector
.s
.ptr4
= (void *)4;
696 retval
->OverallSize
= (unsigned long) *length
;
697 retval
->NumberOfSourceLines
= srclines
;
698 retval
->version
= INSTORE_VERSION
;
699 retval
->NumberOfTreeElements
= nodecount
;
701 retval
->source
= sizeof(external_parser_type
);
702 len
= FillStrings((char *) retval
,
703 sizeof(external_parser_type
),
707 retval
->TreeStart
= ipt
->root
->nodeindex
;
708 len
= FillTree((treenode
*) ((char *) retval
+ len
),
710 len
+ nodecount
*sizeof(treenode
),
713 memcpy((char *) retval
+ len
, retval
->Magic
, sizeof(retval
->Magic
));
715 assert((unsigned long) len
+ sizeof(retval
->Magic
) == *length
);
717 /* DEBUGGING: return NULL if you don't want tinned trees */
718 TSD
= TSD
; /* keep compiler happy */
722 /* IsValidTin returns 1 if the structure ept if of length eptlen and seems
723 * to contain a valid parsing tree. 0 is returned if this is not the case.
725 int IsValidTin(const external_parser_type
*ept
, unsigned long eptlen
)
727 char Magic
[sizeof(((external_parser_type
*)0)->Magic
)];
730 /* Some paranoia tests first: */
731 if ((ept
== NULL
) || (eptlen
< sizeof(external_parser_type
)))
734 /* Be sure to fill Magic as described */
735 memset(Magic
, 0, sizeof(Magic
));
736 len
= sizeof(MagicHeader
); /* includes a terminating 0 */
737 if (len
> sizeof(ept
->Magic
))
738 len
= sizeof(ept
->Magic
);
739 memcpy(Magic
, MagicHeader
, len
);
741 if (memcmp(Magic
, ept
->Magic
, sizeof(Magic
)) != 0)
744 if ((ept
->arch_detector
.s
.one
!= 1) ||
745 (ept
->arch_detector
.s
.two
!= 2) ||
746 (ept
->arch_detector
.s
.ptr3
!= (void *)3) ||
747 (ept
->arch_detector
.s
.ptr4
!= (void *)4))
750 if (ept
->OverallSize
!= eptlen
)
753 if (ept
->version
!= INSTORE_VERSION
)
757 (char *) ept
+ eptlen
- sizeof(Magic
),