File: compiler.h

package info (click to toggle)
fis-gtm 6.3-014-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 36,680 kB
  • sloc: ansic: 333,039; asm: 5,180; csh: 4,956; sh: 1,924; awk: 291; makefile: 66; sed: 13
file content (785 lines) | stat: -rwxr-xr-x 27,988 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
/****************************************************************
 *								*
 * Copyright (c) 2001-2019 Fidelity National Information	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/
#ifndef COMPILER_H_INCLUDED
#define COMPILER_H_INCLUDED

/* Values for oprclass - Changes made here need to be reflected in cdbg_dump opr_type_names table */
typedef enum
{
	NO_REF,		/* 0 */
	TVAR_REF,	/* 1 */
	TVAL_REF,	/* 2 */
	TINT_REF,	/* 3 */
	TVAD_REF,	/* 4 */
	TCAD_REF,	/* 5  - This and all _REFs before are VALUED_REF_TYPES (see alloc_reg.c) */
	MLIT_REF,	/* 6 */
	MVAR_REF,	/* 7 */
	TRIP_REF,	/* 8 */
	TNXT_REF,	/* 9  */
	TJMP_REF,	/* 10 */
	INDR_REF,	/* 11 */
	MLAB_REF,	/* 12 */
	ILIT_REF,	/* 13 */
	CDLT_REF,	/* 14 - apparently no longer used */
	TEMP_REF,	/* 15 - apparently no longer maintained */
	MFUN_REF,	/* 16 */
	MNXL_REF,	/* 17 refer to internalentry of child line */
	TSIZ_REF,	/* 18 ilit refering to size of given triple codegen */
	OCNT_REF,	/* 19 Offset from Call to Next Triple */
	CDIDX_REF	/* 20 Denotes index into a table containing a code address */
} operclass;
#define VALUED_REF_TYPES 6	/* Types 0-5 are specific types used by alloc_reg() in array references
				 * **** WARNING **** Do NOT reorder
				 */

typedef unsigned int	opctype;

typedef struct	mvarstruct
{
	struct	mvarstruct	*lson,
				*rson;
	int4			mvidx;
	mident			mvname;
	struct	tripletype	*last_fetch;
} mvar;

typedef struct	mvaxstruct
{
	struct	mvaxstruct	*last,
				*next;
	mvar			*var;
	int4			mvidx;
} mvax;

typedef struct	mlinestruct
{
	struct	mlinestruct	*parent,
				*sibling,
				*child;
	struct	tripletype	*externalentry;
	uint4			line_number;	/* ...operation on this line */
	boolean_t		table;		/* put in table or not */
	boolean_t		block_ok;	/* saw argumentless DO or not */
} mline;

typedef struct	mlabstruct
{
	struct	mlabstruct	*lson,
				*rson;
	mline			*ml;
	mident			mvname;
	int			formalcnt;
	boolean_t		gbl;
} mlabel;

typedef struct	mliteralstruct
{
	struct
	{
		struct	mliteralstruct	*fl,
					*bl;
	}			que;
	INTPTR_T       		rt_addr;
	int			reference_count;	/* Used in the hash table to track references */
	mval			v;
} mliteral;

typedef struct	triplesize
{
	struct tripletype	*ct;
	int4			size;
} tripsize;

typedef struct	oprtypestruct
{
	operclass		oprclass;
	union
	{
		struct	oprtypestruct	*indr;
		struct	tripletype	*tref;
		struct	triplesize	*tsize;
		mlabel			*lab;
		mline			*mlin;
		mliteral		*mlit;
		mstr			*cdlt;
		mstr			*cdidx;
		mvar			*vref;
		int4			temp;
		int4			ilit;
		int4			offset;
		unsigned char		vreg;
	} oprval;
} oprtype;

typedef struct	tbptype
{
	struct
	{
		struct	tbptype		*fl,
					*bl;
	}			que;
	struct	tripletype	*bpt;
} tbp;

typedef struct
{
	uint4			line;
	uint4			column;
} source_address;

typedef struct	tripletype
{
	opctype			opcode;
	struct
	{
		struct	tripletype	*fl,
					*bl;
	}			exorder;
	tbp			backptr,	/* triples which reference this triple's value */
				jmplist;	/* triples which jump to this one */
	source_address		src;
	int			rtaddr;		/* relative run time address of triple */
	oprtype			operand[2],
				destination;
} triple;

typedef struct
{
	uint4		octype;
} octabstruct;

/* Values for octype */
#define OCT_NULL	0
#define OCT_MVAL	1
#define OCT_MINT	2
#define OCT_MVADDR	4
#define OCT_CDADDR	8
#define OCT_VALUE	(OCT_MVAL | OCT_MINT | OCT_CDADDR)
#define OCT_BOOL	16
#define OCT_JUMP	32
#define OCT_EXPRLEAF	64
#define OCT_CGSKIP	128
#define OCT_COERCE	256
#define OCT_ARITH	512
#define OCT_UNARY	1024
#define OCT_NEGATED	2048
#define OCT_REL	4096

typedef struct
{
	char			name[20];
	opctype			bo_type;
	char			uo_type;
	unsigned short		opr_type;
} toktabtype;

/* These two structures really belong in glvn_pool.h, but gtmpcat doesn't know to include that file. So put them here for now. */
#include "callg.h"
typedef struct
{
	opctype			sav_opcode;
	uint4			mval_top;			/* mval just beyond ones used by this entry */
	uint4			precursor;			/* index of previous FOR slot at same level */
	mval			*lvname;
	gparam_list		glvn_info;
} glvn_pool_entry;

typedef struct
{
	uint4			capacity;			/* total # allocated entries */
	uint4			top;				/* current available glvn_pool_entry slot */
	uint4			for_slot[MAX_FOR_STACK + 1];	/* indices of most recent FOR slots */
	uint4			share_slot;			/* currently active slot */
	opctype			share_opcode;			/* currently active opcode */
	uint4			mval_capacity;			/* total # allocated mvals */
	uint4			mval_top;			/* current available mval in mval_stack */
	mval			*mval_stack;			/* stack of mvals */
	glvn_pool_entry		slot[1];			/* stack of entries */
} glvn_pool;

#define VMS_OS  01
#define UNIX_OS 02
#define ALL_SYS (VMS_OS | UNIX_OS)
#ifdef UNIX                     /* function and svn validation are a function of the OS */
#	 define VALID_FUN(i) (fun_data[i].os_syst & UNIX_OS)
#	 define VALID_SVN(i) (svn_data[i].os_syst & UNIX_OS)
#	 ifdef __hppa
#	 	 define TRIGGER_OS 0
#	 else
#	 	 define TRIGGER_OS UNIX_OS
#	 endif
#elif defined VMS
#	 define VALID_FUN(i) (fun_data[i].os_syst & VMS_OS)
#	 define VALID_SVN(i) (svn_data[i].os_syst & VMS_OS)
#	 define TRIGGER_OS 0
#else
#	 error UNSUPPORTED PLATFORM
#endif

#define MUMPS_INT	0	/* integer - they only type the compiler handles differently */
#define MUMPS_EXPR	1	/* expression */
#define MUMPS_STR	2	/* string */
#define MUMPS_NUM	3	/* numeric - potentially non-integer */

#define EXPR_FAIL	0	/* expression had syntax error - frequently represented by FALSE*/
#define EXPR_GOOD	1	/* expression ok, no indirection at root - frequently represented by TRUE */
#define EXPR_INDR	2	/* expression ok, indirection at root */
#define EXPR_SHFT	4	/* expression ok, involved shifted GV references */

#define CHARMAXARGS	256
#define MAX_FORARGS	127
#define MAX_SRCLINE	8192	/* maximum length of a program source or indirection line */
#define NO_FORMALLIST	(-1)

/* Some errors should not cause stx_error to issue an rts_error. These are the errors related to
 *	a) Invalid Intrinsic Commands
 *	b) Invalid Intrinsic Function Names
 *	c) Invalid Intrinsic Special Variables
 *	d) Invalid Deviceparameters for IO commands
 * These should cause an error at runtime if and only if that codepath is reached.
 * PostConditionals can cause this path to be avoided in which case we do not want to issue an error at compile time.
 * Therefore issue only a warning at compile-time and proceed with compilation as if this codepath will not be reached at runtime.
 */
error_def(ERR_BOOLSIDEFFECT);
error_def(ERR_DEVPARINAP);
error_def(ERR_DEVPARUNK);
error_def(ERR_DEVPARVALREQ);
error_def(ERR_FNOTONSYS);
error_def(ERR_INVCMD);
error_def(ERR_INVFCN);
error_def(ERR_INVSVN);
error_def(ERR_SVNONEW);
error_def(ERR_SVNOSET);

#define	IS_STX_WARN(errcode)										\
	((ERR_DEVPARINAP == errcode) || (ERR_DEVPARUNK == errcode) || (ERR_DEVPARVALREQ == errcode)	\
		|| (ERR_FNOTONSYS == errcode) || (ERR_INVCMD == errcode) || (ERR_INVFCN == errcode) 	\
		|| (ERR_INVSVN == errcode) || (ERR_SVNONEW == errcode) || (ERR_SVNOSET == errcode))

/* This macro does an "stx_error" of the input errcode but before that it asserts that the input errcode is one
 * of the known error codes that are to be handled as a compile-time warning (instead of an error). It also set
 * the variable "parse_warn" to TRUE which is relied upon by the functions that invoke this macro. Note that when
 * triggers are included, warnings become errors so bypass the warning stuff.
 */
#ifdef GTM_TRIGGER
#	define	STX_ERROR_WARN(errcode)					\
{									\
	if (!TREF(trigger_compile_and_link))				\
		parse_warn = TRUE;					\
	assert(IS_STX_WARN(errcode));					\
	stx_error(errcode);						\
	if (TREF(trigger_compile_and_link))				\
		return FALSE;						\
}
#else
#	define	STX_ERROR_WARN(errcode)					\
{									\
	parse_warn = TRUE;						\
	assert(IS_STX_WARN(errcode));					\
	stx_error(errcode);						\
}
#endif

#ifdef DEBUG
#	 define COMPDBG(x)	if (gtmDebugLevel & GDL_DebugCompiler) {x}
#else
#	 define COMPDBG(x)
#endif

/* Cutover from simple lists to hash table access - tuned by testing compilation
   of 24K+ Vista M source routines.
*/
#include "copy.h"
#define LIT_HASH_CUTOVER DEBUG_ONLY(4) PRO_ONLY(32)
#define SYM_HASH_CUTOVER DEBUG_ONLY(4) PRO_ONLY(16)
#define COMPLITS_HASHTAB_CLEANUP									\
	{												\
		GBLREF hash_table_str		*complits_hashtab;					\
		if (complits_hashtab && complits_hashtab->base)						\
		{	/* Release hash table itself but leave hash table descriptor if exists */ 	\
			free_hashtab_str(complits_hashtab);						\
		}											\
	}
#define COMPSYMS_HASHTAB_CLEANUP									\
	{												\
		GBLREF hash_table_str		*compsyms_hashtab;					\
		if (compsyms_hashtab && compsyms_hashtab->base)						\
		{	/* Release hash table itself but leave hash table descriptor if exists */ 	\
			free_hashtab_str(compsyms_hashtab);						\
			compsyms_hashtab->base = NULL;							\
		}											\
	}
#define COMPILE_HASHTAB_CLEANUP		\
	COMPLITS_HASHTAB_CLEANUP;	\
	COMPSYMS_HASHTAB_CLEANUP;

typedef struct
{
	triple		*expr_start;
	triple		*expr_start_orig;
	boolean_t	shift_side_effects;
	boolean_t	saw_side_effect;
	triple		tmpchain;
} save_se;

#define START_GVBIND_CHAIN(SS, OLDCHAIN)					\
{										\
	(SS)->expr_start = TREF(expr_start);					\
	(SS)->expr_start_orig = TREF(expr_start_orig);				\
	(SS)->shift_side_effects = TREF(shift_side_effects);			\
	(SS)->saw_side_effect = TREF(saw_side_effect);				\
	TREF(expr_start) = NULL;						\
	TREF(expr_start_orig) = NULL;						\
	TREF(shift_side_effects) = FALSE;					\
	TREF(saw_side_effect) = FALSE;						\
	dqinit(&(SS)->tmpchain, exorder);					\
	OLDCHAIN = setcurtchain(&(SS)->tmpchain);				\
}

#define PLACE_GVBIND_CHAIN(SS, OLDCHAIN)					\
{										\
	newtriple(OC_GVSAVTARG);						\
	TREF(expr_start) = (SS)->expr_start;					\
	TREF(expr_start_orig) = (SS)->expr_start_orig;				\
	TREF(shift_side_effects) = (SS)->shift_side_effects;			\
	TREF(saw_side_effect) = (SS)->saw_side_effect;				\
	setcurtchain(OLDCHAIN);							\
	assert(NULL != TREF(expr_start));					\
	dqadd(TREF(expr_start), &(SS)->tmpchain, exorder);			\
	TREF(expr_start) = (SS)->tmpchain.exorder.bl;				\
	assert(OC_GVSAVTARG == (TREF(expr_start))->opcode);			\
	newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start));	\
}

/* note assignment below */
#define SHIFT_SIDE_EFFECTS	((TREF(saw_side_effect) = TREF(shift_side_effects)) && (GTM_BOOL == TREF(gtm_fullbool)))

#define INITIAL_SIDE_EFFECT_DEPTH 33	/* initial allocation for expression nesting to track side effects */

/* note side effect for boolean shifting temporaries */
#define ENCOUNTERED_SIDE_EFFECT										\
{	/* Needs #include "show_source_line" and #include "fullbool.h" */				\
													\
	if (TREF(shift_side_effects))									\
	{												\
		TREF(saw_side_effect) = TRUE;								\
		if (!run_time && (FULL_BOOL_WARN == TREF(gtm_fullbool)))				\
		{	/* warnings requested by by gtm_fullbool and enabled by eval_expr */		\
			show_source_line(TRUE);								\
			dec_err(VARLSTCNT(1) ERR_BOOLSIDEFFECT);					\
		}											\
	}												\
}

#define SE_WARN_ON	(!run_time && (SE_WARN == TREF(side_effect_handling)))

#define ISSUE_SIDEEFFECTEVAL_WARNING(COLUMN)						\
{											\
	TREF(last_source_column) = (COLUMN);						\
	show_source_line(TRUE);								\
	dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL);					\
}

/* maintain array indexed by expr_depth to track side effects - for subscripts, actuallists, binary expressions and functions */
#define INCREMENT_EXPR_DEPTH													\
{																\
	boolean_t	*TMP_BASE;												\
																\
	if (!(TREF(expr_depth))++)												\
		TREF(expr_start) = TREF(expr_start_orig) = NULL;								\
	else															\
	{	/* expansion is unlikely as it's hard to nest expressions deeply, but we don't want a hard limit */		\
		assertpro(TREF(expr_depth));					/* expr_depth doesn't handle rollover */	\
		assert(TREF(expr_depth) <= TREF(side_effect_depth));								\
		if (TREF(expr_depth) == TREF(side_effect_depth))								\
		{														\
			TMP_BASE = TREF(side_effect_base);									\
			(TREF(side_effect_depth))++;										\
			TREF(side_effect_base) = malloc(SIZEOF(boolean_t) * TREF(side_effect_depth));				\
			memcpy(TREF(side_effect_base), TMP_BASE, SIZEOF(boolean_t) * TREF(expr_depth));				\
			free(TMP_BASE);												\
			(TREF(side_effect_base))[TREF(expr_depth)] = FALSE;			 				\
		}														\
	}															\
	assert(FALSE == (TREF(side_effect_base))[TREF(expr_depth)]);								\
}

/* complement of the above increment - uses the macro just below for assertpto and to clear the level we're leaving */
#define DECREMENT_EXPR_DEPTH													\
{																\
	DISABLE_SIDE_EFFECT_AT_DEPTH;												\
	if (!(--(TREF(expr_depth))))												\
		TREF(saw_side_effect) = TREF(shift_side_effects) = FALSE;							\
}

/* clear the current expr_depth level and propagate down */
#define DISABLE_SIDE_EFFECT_AT_DEPTH												\
{																\
	unsigned int	DEPTH;													\
																\
	DEPTH = TREF(expr_depth);												\
	assertpro(DEPTH);								/* expr_depth shouldn't underflow */	\
	(TREF(side_effect_base))[DEPTH - 1] |= (TREF(side_effect_base))[DEPTH];		/* propagate down */			\
	(TREF(side_effect_base))[DEPTH] = FALSE;										\
}

/* The following macro transfers subscripts from an array to the triple chain for gvn, lvn and name_glvn
* it requires includes for fullbool.m, mdq.h, and show_source_line.h, and also GBLREF of runtime
*/
#define SUBS_ARRAY_2_TRIPLES(REF1, SB1, SB2, SUBSCRIPTS, XTRA)									\
{																\
	boolean_t	PROTECT_LVN, SE_NOTIFY;											\
	triple 		*REF2;													\
																\
	if (PROTECT_LVN = (TREF(side_effect_base))[TREF(expr_depth)])	/* NOTE assignment */					\
		SE_NOTIFY = SE_WARN_ON;												\
	while (SB2 < SB1)													\
	{															\
		if (PROTECT_LVN && (SB2 > (SUBSCRIPTS + XTRA)) && ((SB1 - SB2) > 1)						\
				&& ((OC_VAR == SB2->oprval.tref->opcode) || (OC_GETINDX == SB2->oprval.tref->opcode)))		\
		{	/* protect lvns from side effects: skip 1st (unsubscripted name), and last (nothing following) */	\
			assert(OLD_SE != TREF(side_effect_handling));								\
			REF2 = maketriple(OC_STOTEMP);										\
			REF2->operand[0] = *SB2;										\
			dqins(SB2->oprval.tref, exorder, REF2); 		/* NOTE:this violates information hiding */	\
			if (SE_NOTIFY)												\
				ISSUE_SIDEEFFECTEVAL_WARNING(SB2->oprval.tref->src.column + 1);					\
			*SB2 = put_tref(REF2);											\
		}														\
		REF2 = newtriple(OC_PARAMETER);											\
		REF1->operand[1] = put_tref(REF2);										\
		REF1 = REF2;													\
		REF1->operand[0] = *SB2++;											\
	}															\
}

/* the macro below tucks a code reference into the for_stack so a FOR that's done can move on correctly when done */
#define FOR_END_OF_SCOPE(DEPTH, RESULT)										\
{														\
	oprtype	**Ptr;												\
														\
	assert(0 <= DEPTH);											\
	assert(TREF(for_stack_ptr) < (oprtype **)TADR(for_stack) + MAX_FOR_STACK);				\
	Ptr = (oprtype **)TREF(for_stack_ptr) - DEPTH;								\
	assert(Ptr >= (oprtype **)TADR(for_stack));								\
	if (NULL == *Ptr)											\
		*Ptr = (oprtype *)mcalloc(SIZEOF(oprtype));							\
	RESULT = put_indr(*Ptr);										\
}

#define GOOD_FOR  FALSE	/* single level */
#define BLOWN_FOR (!TREF(xecute_literal_parse))	/* all levels, except only one for our funky friend xecute_literal_parse */

/* Marco to decrement or clear the for_stack, clear the for_temp array
 * and generate code to release run-time malloc'd mvals anchored in the for_saved_indx array
 * The corresponding FOR_PUSH macro is in m_for.c but this one is used in stx_error.c for error cases
 */
#define	FOR_POP(ALL)												\
{														\
	assert(TREF(for_stack_ptr) >= (oprtype **)TADR(for_stack));						\
	assert(TREF(for_stack_ptr) <= (oprtype **)TADR(for_stack) + MAX_FOR_STACK);				\
	if (ALL)												\
	{													\
		(TREF(for_stack_ptr)) = (oprtype **)TADR(for_stack);						\
		*(TREF(for_stack_ptr)) = NULL;									\
	} else if (TREF(for_stack_ptr) > (oprtype **)TADR(for_stack))						\
		--(TREF(for_stack_ptr));									\
}

/* The following macro should be used when doing an OC_FETCH other than at the start of a line because
 * it deals with the possibility that there is a preceding FOR, in which case, we use start_for_fetches to
 * be sure the new fetch includes any FOR loop control variable
 */
#define MID_LINE_REFETCH											\
	if (TREF(for_stack_ptr) == TADR(for_stack))								\
		start_fetches(OC_FETCH);									\
	else	/* if in the body of a FOR loop we need to ensure the control variable is refetched */		\
		start_for_fetches();

/* $TEXT(+n^rtn) fetches from the most recently ZLINK'd version of rtn. $TEXT(+n) fetches from the currently executing version.
 * The compiler converts $TEXT(+n) to $TEXT(+n^!), indicating at runtime $TEXT should fetch from the current executing routine.
 * '!' is not a legal routine name character.
 */
#define CURRENT_RTN_STRING		"!"
#define PUT_CURRENT_RTN			put_str(LIT_AND_LEN(CURRENT_RTN_STRING))
/* Do we want the current routine? Return TRUE.
 * Otherwise, return FALSE; we want the latest version of whichever routine name is specified.
 */
#define WANT_CURRENT_RTN_MSTR(S)	((STR_LIT_LEN(CURRENT_RTN_STRING) == (S)->len)	\
						&& (0 == MEMCMP_LIT((S)->addr, CURRENT_RTN_STRING)))
#define WANT_CURRENT_RTN(R)		WANT_CURRENT_RTN_MSTR(&(R)->str)

#define NEWLINE_TO_NULL(C)		\
{					\
	if ('\n' == (char)(C))		\
		C = '\0';		\
}

/* Macro to clear parts of given compiler mval which could end up in an object file (if they are literals). These bits may not
 * be (re)set by the s2n/n2s calls we do. If not, the mval could have random bits in it which, as far as the mval is concerned
 * is not a problem but interferes with getting a consistent object hash value when the same source is (re)compiled.
 */
#define CLEAR_MVAL_BITS(mvalptr) 			\
{							\
	((mval_b *)(mvalptr))->sgne = 0;		\
	(mvalptr)->fnpc_indx = 0xff;			\
	UTF8_ONLY((mvalptr)->utfcgr_indx = 0xff);	\
}

/* Macro to put a literal truth value as an operand */
#define PUT_LITERAL_TRUTH(TV, TRIP_REF)									\
MBSTART {												\
	LITREF mval		literal_zero, literal_one;						\
													\
	mval	*V;											\
													\
	V = (mval *)mcalloc(SIZEOF(mval));								\
	*V = (TV) ? literal_one : literal_zero;								\
	assert((1 == literal_one.str.len) && (1 == literal_zero.str.len));				\
	ENSURE_STP_FREE_SPACE(1);									\
	*(char *)stringpool.free = *V->str.addr;							\
	V->str.addr = (char *)stringpool.free;								\
	stringpool.free += 1;										\
	put_lit_s(V, TRIP_REF);										\
} MBEND

/* Macro to decide whether an invocation of unary tail has any promise */
#define UNARY_TAIL(OPR)											\
MBSTART {												\
	assert(TRIP_REF == (OPR)->oprclass);								\
	if (OCT_UNARY & oc_tab[(OPR)->oprval.tref->opcode].octype)					\
		unary_tail(OPR);									\
} MBEND

/* the following structure and macros save and restore parsing state and as of this writing are only used by m_xecute */
typedef struct
{
	boolean_t	source_error_found;
	int		source_column;
	int		director_ident_len;
	int4		block_level;
	mstr_len_t	source_len;
	mval		director_mval;
	unsigned char	ident_buffer[(MAX_MIDENT_LEN * 2) + 1];
	char		director_token;
	char		*lexical_ptr;
	char		window_token;
	triple		pos_in_chain;
} parse_save_block;

#define SAVE_PARSE_STATE(SAVE_PARSE_PTR)									\
MBSTART {													\
	SAVE_PARSE_PTR->block_level = TREF(block_level);							\
	SAVE_PARSE_PTR->director_ident_len = (TREF(director_ident)).len;					\
	memcpy(SAVE_PARSE_PTR->ident_buffer, (TREF(director_ident)).addr, SAVE_PARSE_PTR->director_ident_len);	\
	SAVE_PARSE_PTR->director_mval = TREF(director_mval);							\
	SAVE_PARSE_PTR->director_token = TREF(director_token);							\
	SAVE_PARSE_PTR->lexical_ptr = TREF(lexical_ptr);							\
	SAVE_PARSE_PTR->source_column = source_column;								\
	SAVE_PARSE_PTR->source_error_found = TREF(source_error_found);						\
	SAVE_PARSE_PTR->source_len = (TREF(source_buffer)).len;							\
	SAVE_PARSE_PTR->window_token = TREF(window_token);							\
	SAVE_PARSE_PTR->pos_in_chain = TREF(pos_in_chain);							\
} MBEND

#define RESTORE_PARSE_STATE(SAVE_PARSE_PTR)								\
MBSTART {													\
	TREF(block_level) = SAVE_PARSE_PTR->block_level;							\
	(TREF(director_ident)).len = SAVE_PARSE_PTR->director_ident_len;					\
	memcpy((TREF(director_ident)).addr, SAVE_PARSE_PTR->ident_buffer, SAVE_PARSE_PTR->director_ident_len);	\
	TREF(director_mval) = SAVE_PARSE_PTR->director_mval;							\
	TREF(director_token) = SAVE_PARSE_PTR->director_token;							\
	TREF(lexical_ptr) = SAVE_PARSE_PTR->lexical_ptr;							\
	(TREF(source_buffer)).addr = (char *)&aligned_source_buffer;						\
	(TREF(source_buffer)).len = SAVE_PARSE_PTR->source_len;							\
	source_column = SAVE_PARSE_PTR->source_column;								\
	TREF(source_error_found) = SAVE_PARSE_PTR->source_error_found;						\
	TREF(window_token) = SAVE_PARSE_PTR->window_token;							\
	TREF(pos_in_chain) = SAVE_PARSE_PTR->pos_in_chain;							\
} MBEND

#define RETURN_IF_RTS_ERROR							\
MBSTART {									\
	if (TREF(rts_error_in_parse))						\
		return;								\
} MBEND

#define RETURN_EXPR_IF_RTS_ERROR						\
MBSTART {									\
	if (TREF(rts_error_in_parse))						\
	{									\
		TREF(rts_error_in_parse) = FALSE;				\
		DECREMENT_EXPR_DEPTH;						\
		return EXPR_FAIL;						\
	}									\
} MBEND

#define ALREADY_RTERROR (OC_RTERROR == (TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl->opcode)

/* Autorelink enabled platforms pass a different argument to glue code when calling a non-local M
 * routine. Use put_cdlt() to pass addresses of the items and use put_cdidx() when passing an ofset
 * into the linkage table where the items reside. Also macroize the opcode to use.
 */
#ifdef AUTORELINK_SUPPORTED
# define PUT_CDREF put_cdidx
# define OC_CDREF OC_CDIDX
# define CDREF_REF CDIDX_REF
#else
# define PUT_CDREF put_cdlt
# define OC_CDREF OC_CDLIT
# define CDREF_REF CDLT_REF
#endif

int		actuallist(oprtype *opr);
int		bool_expr(boolean_t sense, oprtype *addr);
void		bx_boollit(triple *t);
void		bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean_t sense, oprtype *addr);
void		bx_relop(triple *t, opctype cmp, opctype tst, oprtype *addr);
void		bx_tail(triple *t, boolean_t sense, oprtype *addr);
void		chktchain(triple *head);
void		code_gen(void);
void		coerce(oprtype *a, unsigned short new_type);
int		comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, oprtype *dst, mstr_len_t src_len);
void		comp_init(mstr *src, oprtype *dst);
void		comp_indr(mstr *obj);
boolean_t	compiler_startup(void);
void		create_temporaries(triple *sub, opctype put_oc);
triple		*entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_commarg, boolean_t labref, boolean_t textname);
int		eval_expr(oprtype *a);
int		expratom(oprtype *a);
int		exfunc(oprtype *a, boolean_t alias_target);
int		expritem(oprtype *a);
int		expr(oprtype *a, int m_type);
void		ex_tail(oprtype *opr);
int		extern_func(oprtype *a);
int		f_ascii(oprtype *a, opctype op);
int		f_char(oprtype *a, opctype op);
int		f_data(oprtype *a, opctype op);
int		f_extract(oprtype *a, opctype op);
int		f_find(oprtype *a, opctype op);
int		f_fnumber(oprtype *a, opctype op);
int		f_fnzbitfind(oprtype *a, opctype op);
int		f_fnzbitget(oprtype *a, opctype op);
int		f_fnzbitset(oprtype *a, opctype op);
int		f_fnzbitstr(oprtype *a, opctype op);
int		f_get(oprtype *a, opctype op);
int		f_get1(oprtype *a, opctype op);
int		f_incr(oprtype *a, opctype op);
int		f_justify(oprtype *a, opctype op);
int		f_length(oprtype *a, opctype op);
int		f_mint(oprtype *a, opctype op);
int		f_mint_mstr(oprtype *a, opctype op);
int		f_mstr(oprtype *a, opctype op);
int		f_name(oprtype *a, opctype op);
int		f_next(oprtype *a, opctype op);
int		f_one_mval(oprtype *a, opctype op);
int		f_order(oprtype *a, opctype op);
int		f_order1(oprtype *a, opctype op);
int		f_piece(oprtype *a, opctype op);
int		f_qlength(oprtype *a, opctype op);
int		f_qsubscript(oprtype *a, opctype op);
int		f_query (oprtype *a, opctype op);
int		f_reverse(oprtype *a, opctype op);
int		f_select(oprtype *a, opctype op);
int		f_stack(oprtype *a, opctype op);
int		f_text(oprtype *a, opctype op);
int		f_translate(oprtype *a, opctype op);
int		f_two_mstrs(oprtype *a, opctype op);
int		f_two_mval(oprtype *a, opctype op);
int		f_view(oprtype *a, opctype op);
int		f_zahandle(oprtype *a, opctype op);
int		f_zatransform(oprtype *a, opctype op);
int		f_zcall(oprtype *a, opctype op);
int		f_zchar(oprtype *a, opctype op);
int		f_zcollate(oprtype *a, opctype op);
int		f_zconvert(oprtype *a, opctype op);
int		f_zdate(oprtype *a, opctype op);
int		f_zdebug(oprtype *a, opctype op);
int		f_zechar(oprtype *a, opctype op);
int		f_zgetsyi(oprtype *a, opctype op);
int		f_zjobexam(oprtype *a, opctype op);
int		f_zparse(oprtype *a, opctype op);
int		f_zpeek(oprtype *a, opctype op);
int		f_zprevious(oprtype *a, opctype op);
int		f_zqgblmod(oprtype *a, opctype op);
int		f_zrupdate(oprtype *a, opctype op);
int		f_zsearch(oprtype *a, opctype op);
int		f_zsigproc(oprtype *a, opctype op);
int		f_zsocket(oprtype *a, opctype op);
int		f_zsqlexpr (oprtype *a, opctype op);
int		f_zsqlfield (oprtype *a, opctype op);
int		f_zsubstr(oprtype *a, opctype op);
int		f_ztrigger(oprtype *a, opctype op);
int		f_ztrnlnm(oprtype *a, opctype op);
int		f_zwidth(oprtype *a, opctype op);
int		f_zwrite(oprtype *a, opctype op);
mlabel		*get_mladdr(mident *c);
mvar		*get_mvaddr(mident *c);
int		glvn(oprtype *a);
int		gvn(void);
void		ind_code(mstr *obj);
int		indirection(oprtype *a);
void		ins_triple(triple *x);
void		int_label(void);
int		jobparameters (oprtype *c);
boolean_t	line(uint4 *lnc);
int		linetail(void);
int		lkglvn(boolean_t gblvn);
int	lref(oprtype *label, oprtype *offset, boolean_t no_lab_ok, mint commarg_code, boolean_t commarg_ok, boolean_t *got_some);
int		lvn(oprtype *a,opctype index_op,triple *parent);
void		make_commarg(oprtype *x, mint ind);
oprtype		make_gvsubsc(mval *v);
triple		*maketriple(opctype op);
int		name_glvn(boolean_t gblvn, oprtype *a);
triple		*newtriple(opctype op);
int		nref(void);
void		obj_code(uint4 src_lines, void *checksum_ctx);
int		one_job_param(char **parptr);
int		parse_until_rparen_or_space(void);
oprtype		put_ocnt(void);
oprtype		put_tsiz(void);
oprtype		put_cdlt(mstr *x);
oprtype		put_cdidx(mstr *x);
oprtype		put_ilit(mint x);
oprtype		put_indr(oprtype *x);
oprtype		put_lit(mval *x);
oprtype		put_lit_s(mval *x, triple *dst);
oprtype		put_mfun(mident *l);
oprtype		put_mlab(mident *l);
oprtype		put_mnxl(void);
oprtype		put_mvar(mident *x);
oprtype		put_str(char *pt, mstr_len_t n);
oprtype		put_tjmp(triple *x);
oprtype		put_tnxt(triple *x);
oprtype		put_tref(triple *x);
boolean_t	resolve_optimize(triple *curtrip);
int		resolve_ref(int errknt);
void		resolve_tref(triple *, oprtype *);
triple		*setcurtchain(triple *x);
void		unary_tail(oprtype *opr);
/* VMS uses same code generator as USHBIN so treat as USHBIN for these compiler routines */
#		if defined(USHBIN_SUPPORTED) || defined(VMS)
void		shrink_trips(void);
boolean_t	litref_triple_oprcheck(oprtype *operand);
#		else
void		shrink_jmps(void);
#		endif
void		start_fetches(opctype op);
void		start_for_fetches(void);
void		tnxtarg(oprtype *a);
void		tripinit(void);
boolean_t	unuse_literal(mval *x);
void		walktree(mvar *n,void (*f)(),char *arg);
void		wrtcatopt(triple *r, triple ***lpx, triple **lptop);
int		zlcompile(unsigned char len, unsigned char *addr);		/***type int added***/

#endif /* COMPILER_H_INCLUDED */