4 * Intermediate Code Compiler for Parrot.
6 * Copyright (C) 2002 Melvin Smith <melvin.smith@mindspring.com>
7 * Copyright (C) 2002-2008, The Perl Foundation.
9 * parser support functions
22 #include "parrot/dynext.h"
23 #include "parrot/embed.h"
24 #include "parrot/builtin.h"
27 #include "optimizer.h"
33 compilers/imcc/parser_util.c
37 ParserUtil - Parser support functions.
43 /* HEADERIZER HFILE: compilers/imcc/imc.h */
45 /* HEADERIZER BEGIN: static */
46 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
48 PARROT_WARN_UNUSED_RESULT
49 static int change_op(PARROT_INTERP
,
50 ARGMOD(IMC_Unit
*unit
),
54 __attribute__nonnull__(1)
55 __attribute__nonnull__(2)
56 __attribute__nonnull__(3)
60 PARROT_CANNOT_RETURN_NULL
61 static void * imcc_compile_file(PARROT_INTERP
,
62 ARGIN(const char *fullname
),
63 ARGOUT(STRING
**error_message
))
64 __attribute__nonnull__(1)
65 __attribute__nonnull__(2)
66 __attribute__nonnull__(3)
67 FUNC_MODIFIES(*error_message
);
69 PARROT_WARN_UNUSED_RESULT
70 static int is_infix(ARGIN(const char *name
), int n
, ARGIN(SymReg
**r
))
71 __attribute__nonnull__(1)
72 __attribute__nonnull__(3);
74 PARROT_WARN_UNUSED_RESULT
75 PARROT_CAN_RETURN_NULL
76 static Instruction
* maybe_builtin(PARROT_INTERP
,
77 ARGIN(const char *name
),
78 ARGIN(SymReg
* const *r
),
80 __attribute__nonnull__(1)
81 __attribute__nonnull__(2)
82 __attribute__nonnull__(3);
84 PARROT_WARN_UNUSED_RESULT
85 PARROT_CANNOT_RETURN_NULL
86 static const char * to_infix(PARROT_INTERP
,
87 ARGIN(const char *name
),
91 __attribute__nonnull__(1)
92 __attribute__nonnull__(2)
93 __attribute__nonnull__(3)
94 __attribute__nonnull__(4)
98 PARROT_WARN_UNUSED_RESULT
99 PARROT_CAN_RETURN_NULL
100 static const char * try_rev_cmp(ARGIN(const char *name
), ARGMOD(SymReg
**r
))
101 __attribute__nonnull__(1)
102 __attribute__nonnull__(2)
106 PARROT_CANNOT_RETURN_NULL
107 PARROT_WARN_UNUSED_RESULT
108 static Instruction
* var_arg_ins(PARROT_INTERP
,
109 ARGMOD(IMC_Unit
*unit
),
110 ARGIN(const char *name
),
114 __attribute__nonnull__(1)
115 __attribute__nonnull__(2)
116 __attribute__nonnull__(3)
117 __attribute__nonnull__(4)
121 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
122 /* HEADERIZER END: static */
127 * used in -D20 to print files with the output of every PIR compilation
128 * this can't be attached to the interpreter or packfile because it has to be
129 * absolutely global to prevent the files from being overwritten.
131 * This is not thread safe as is. A mutex needs to be added.
133 * See RT#40010 for more discussion.
135 static INTVAL eval_nr
= 0;
143 =item C<Instruction * iNEW>
145 * P = new type, [init]
148 * is done in the lexer, this is a mess
149 * best would be to have a flag in core.ops, where a PMC type is expected
155 PARROT_WARN_UNUSED_RESULT
156 PARROT_CAN_RETURN_NULL
158 iNEW(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGMOD(SymReg
*r0
),
159 ARGMOD(char *type
), ARGIN_NULLOK(SymReg
*init
), int emit
)
165 const int pmc_num
= pmc_type(interp
,
166 string_from_cstring(interp
, *type
== '.' ? type
+ 1 : type
, 0));
168 snprintf(fmt
, sizeof (fmt
), "%d", pmc_num
);
169 pmc
= mk_const(interp
, fmt
, 'I');
172 IMCC_fataly(interp
, E_SyntaxError
,
173 "Unknown PMC type '%s'\n", type
);
175 snprintf(fmt
, sizeof (fmt
), "%%s, %d\t # .%s", pmc_num
, type
);
178 if (STREQ(type
, "Hash"))
179 r0
->usage
|= U_KEYED
;
191 return INS(interp
, unit
, "new", fmt
, regs
, nargs
, 0, emit
);
196 =item C<void op_fullname>
198 Lookup the full opcode given the short name
200 set I0, 5 -> set_i_ic
201 set I0, I1 -> set_i_i
203 Obviously the registers must be examined before returning the correct
206 NOTE: All this nasty IMC_TRACE is for tracking down equally nasty bugs, so
207 if you don't like the looks of it, stay out, but please don't remove it. :)
214 op_fullname(ARGOUT(char *dest
), ARGIN(const char *name
),
215 ARGIN(SymReg
* const *args
), int narg
, int keyvec
)
221 PIO_eprintf(NULL
, "op %s", name
);
226 dest
+= strlen(name
);
228 for (i
= 0; i
< narg
&& args
[i
]; i
++) {
230 if (args
[i
]->type
== VTADDRESS
) {
232 PIO_eprintf(NULL
, " (address)%s", args
[i
]->name
);
238 /* if one ever wants num keys, they go with 'S' */
239 if (keyvec
& KEY_BIT(i
)) {
241 PIO_eprintf(NULL
, " (key)%s", args
[i
]->name
);
244 if (args
[i
]->set
=='S' || args
[i
]->set
=='N' || args
[i
]->set
=='K') {
248 else if (args
[i
]->set
== 'P')
252 if (args
[i
]->set
== 'K')
255 *dest
++ = (char)tolower((unsigned char)args
[i
]->set
);
257 if (args
[i
]->type
& (VTCONST
|VT_CONSTP
)) {
259 PIO_eprintf(NULL
, " (%cc)%s", tolower((unsigned char)args
[i
]->set
), args
[i
]->name
);
265 PIO_eprintf(NULL
, " (%c)%s", tolower((unsigned char)args
[i
]->set
), args
[i
]->name
);
270 PIO_eprintf(NULL
, " -> %s\n", full
);
276 =item C<int check_op>
278 Return opcode value for op name
284 PARROT_WARN_UNUSED_RESULT
286 check_op(PARROT_INTERP
, ARGOUT(char *fullname
), ARGIN(const char *name
),
287 ARGIN(SymReg
* const * r
), int narg
, int keyvec
)
289 op_fullname(fullname
, name
, r
, narg
, keyvec
);
291 return interp
->op_lib
->op_code(fullname
, 1);
296 =item C<static Instruction * maybe_builtin>
298 TODO: Needs to be documented!!!
304 PARROT_WARN_UNUSED_RESULT
305 PARROT_CAN_RETURN_NULL
307 maybe_builtin(PARROT_INTERP
, ARGIN(const char *name
),
308 ARGIN(SymReg
* const *r
), int n
)
311 SymReg
*sub
, *meth
, *rr
[10];
313 int i
, bi
, is_class_meth
, first_arg
, is_void
;
315 PARROT_ASSERT(n
< 15);
317 for (i
= 0; i
< n
; ++i
) {
318 sig
[i
] = (char)r
[i
]->set
;
323 bi
= Parrot_is_builtin(name
, sig
);
329 * create a method see imcc.y target = sub_call
330 * cos Px, Py => Px = Py.cos()
332 is_class_meth
= Parrot_builtin_is_class_method(bi
);
333 is_void
= Parrot_builtin_is_void(bi
);
334 meth
= mk_sub_address(interp
, name
);
336 /* ParrotIO.open() */
338 const char * const ns
= Parrot_builtin_get_c_namespace(bi
);
339 SymReg
* const ns_sym
= mk_const(interp
, ns
, 'S');
341 ins
= IMCC_create_itcall_label(interp
);
342 sub
= ins
->symregs
[0];
344 IMCC_itcall_sub(interp
, meth
);
346 sub
->pcc_sub
->object
= ns_sym
;
349 /* method y = x."cos"() */
351 ins
= IMCC_create_itcall_label(interp
);
352 sub
= ins
->symregs
[0];
354 IMCC_itcall_sub(interp
, meth
);
356 sub
->pcc_sub
->object
= rr
[is_void
? 0 : 1];
360 sub
->pcc_sub
->flags
|= isNCI
;
365 for (i
= first_arg
; i
< n
; ++i
)
366 add_pcc_arg(sub
, rr
[i
]);
369 add_pcc_result(sub
, rr
[0]);
378 Is instruction a parrot opcode?
384 PARROT_WARN_UNUSED_RESULT
386 is_op(PARROT_INTERP
, ARGIN(const char *name
))
388 return interp
->op_lib
->op_code(name
, 0) >= 0
389 || interp
->op_lib
->op_code(name
, 1) >= 0
390 || ((name
[0] == 'n' && name
[1] == '_')
391 && (interp
->op_lib
->op_code(name
+ 2, 0) >= 0
392 || interp
->op_lib
->op_code(name
+ 2, 1) >= 0))
393 || Parrot_is_builtin(name
, NULL
) >= 0;
398 =item C<static const char * to_infix>
400 sub x, y, z => infix .MMD_SUBTRACT, x, y, z
406 PARROT_WARN_UNUSED_RESULT
407 PARROT_CANNOT_RETURN_NULL
409 to_infix(PARROT_INTERP
, ARGIN(const char *name
), ARGMOD(SymReg
**r
),
410 ARGMOD(int *n
), int mmd_op
)
415 PARROT_ASSERT(*n
>= 2);
417 is_n
= (IMCC_INFO(interp
)->state
->pragmas
& PR_N_OPERATORS
) ||
418 (name
[0] == 'n' && name
[1] == '_') ||
419 (mmd_op
== MMD_LOR
|| mmd_op
== MMD_LAND
|| mmd_op
== MMD_LXOR
);
421 if (*n
== 3 && r
[0] == r
[1] && !is_n
) { /* cvt to inplace */
423 snprintf(buf
, sizeof (buf
), "%d", mmd_op
+ 1); /* XXX */
424 mmd
= mk_const(interp
, buf
, 'I');
429 for (i
= *n
; i
> 0; --i
)
432 snprintf(buf
, sizeof (buf
), "%d", *n
== 2 ? (mmd_op
+ 1) : mmd_op
); /* XXX */
433 mmd
= mk_const(interp
, buf
, 'I');
447 =item C<static int is_infix>
449 TODO: Needs to be documented!!!
455 PARROT_WARN_UNUSED_RESULT
457 is_infix(ARGIN(const char *name
), int n
, ARGIN(SymReg
**r
))
459 if (n
< 2 || r
[0]->set
!= 'P')
462 /* TODO use a generic Parrot interface function,
463 * which handles user infix extensions too
465 if (STREQ(name
, "add"))
467 if (STREQ(name
, "sub"))
469 if (STREQ(name
, "mul"))
471 if (STREQ(name
, "div"))
473 if (STREQ(name
, "fdiv"))
474 return MMD_FLOOR_DIVIDE
;
475 if (STREQ(name
, "mod"))
477 if (STREQ(name
, "cmod"))
479 if (STREQ(name
, "pow"))
482 if (STREQ(name
, "bor"))
484 if (STREQ(name
, "band"))
486 if (STREQ(name
, "bxor"))
488 if (STREQ(name
, "bors"))
490 if (STREQ(name
, "bands"))
492 if (STREQ(name
, "bxors"))
495 if (STREQ(name
, "shl"))
497 if (STREQ(name
, "shr"))
499 if (STREQ(name
, "lsr"))
502 if (STREQ(name
, "concat"))
504 if (STREQ(name
, "repeat"))
507 if (STREQ(name
, "or"))
509 if (STREQ(name
, "and"))
511 if (STREQ(name
, "xor"))
515 if (name
[0] == 'n' && name
[1] == '_')
516 return is_infix(name
+ 2, n
, r
);
523 =item C<static Instruction * var_arg_ins>
525 TODO: Needs to be documented!!!
532 PARROT_CANNOT_RETURN_NULL
533 PARROT_WARN_UNUSED_RESULT
535 var_arg_ins(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
536 ARGMOD(SymReg
**r
), int n
, int emit
)
545 r
[0] = mk_const(interp
, r
[0]->name
, 'P');
546 r
[0]->pmc_type
= enum_class_FixedIntegerArray
;
548 op_fullname(fullname
, name
, r
, 1, 0);
549 op
= interp
->op_lib
->op_code(fullname
, 1);
551 PARROT_ASSERT(op
>= 0);
553 ins
= _mk_instruction(name
, "", n
, r
, dirs
);
558 emitb(interp
, unit
, ins
);
565 =item C<Instruction * INS>
570 fmt ... optional format
573 keyvec ... s. KEY_BIT()
574 emit ... if true, append to instructions
576 s. e.g. imc.c for usage
582 PARROT_IGNORABLE_RESULT
583 PARROT_CAN_RETURN_NULL
585 INS(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
586 ARGIN_NULLOK(const char *fmt
), ARGIN(SymReg
**r
), int n
, int keyvec
,
593 char fullname
[64], format
[128], buf
[10];
595 if ((STREQ(name
, "set_args"))
596 || (STREQ(name
, "get_results"))
597 || (STREQ(name
, "get_params"))
598 || (STREQ(name
, "set_returns")))
599 return var_arg_ins(interp
, unit
, name
, r
, n
, emit
);
601 op
= is_infix(name
, n
, r
);
604 /* sub x, y, z => infix .MMD_SUBTRACT, x, y, z */
605 name
= to_infix(interp
, name
, r
, &n
, op
);
607 else if ((IMCC_INFO(interp
)->state
->pragmas
& PR_N_OPERATORS
)
608 && ((STREQ(name
, "abs"))
609 || (STREQ(name
, "neg"))
610 || (STREQ(name
, "not"))
611 || (STREQ(name
, "bnot"))
612 || (STREQ(name
, "bnots")))) {
619 ins
= multi_keyed(interp
, unit
, name
, r
, n
, keyvec
, emit
);
624 op_fullname(fullname
, name
, r
, n
, keyvec
);
625 op
= interp
->op_lib
->op_code(fullname
, 1);
627 /* maybe we have a fullname */
629 op
= interp
->op_lib
->op_code(name
, 1);
631 /* still wrong, try reverse compare */
633 const char * const n_name
= try_rev_cmp(name
, r
);
636 op_fullname(fullname
, name
, r
, n
, keyvec
);
637 op
= interp
->op_lib
->op_code(fullname
, 1);
641 /* still wrong, try to find an existing op */
643 op
= try_find_op(interp
, unit
, name
, r
, n
, keyvec
, emit
);
648 /* check mixed constants */
649 ins
= IMCC_subst_constants_umix(interp
, unit
, name
, r
, n
+ 1);
653 /* and finally multiple constants */
654 ins
= IMCC_subst_constants(interp
, unit
, name
, r
, n
+ 1, &ok
);
664 strcpy(fullname
, name
);
666 if (op
< 0 && emit
) {
667 ins
= maybe_builtin(interp
, name
, r
, n
);
673 IMCC_fataly(interp
, E_SyntaxError
,
674 "The opcode '%s' (%s<%d>) was not found. "
675 "Check the type and number of the arguments",
678 op_info
= &interp
->op_info_table
[op
];
681 /* info->op_count is args + 1
682 * build instruction format
683 * set LV_in / out flags */
684 if (n
!= op_info
->op_count
- 1)
685 IMCC_fataly(interp
, E_SyntaxError
,
686 "arg count mismatch: op #%d '%s' needs %d given %d",
687 op
, fullname
, op_info
->op_count
-1, n
);
689 /* XXX Speed up some by keep track of the end of format ourselves */
690 for (i
= 0; i
< n
; i
++) {
691 switch (op_info
->dirs
[i
]) {
692 case PARROT_ARGDIR_INOUT
:
693 dirs
|= 1 << (16 + i
);
695 case PARROT_ARGDIR_IN
:
699 case PARROT_ARGDIR_OUT
:
700 dirs
|= 1 << (16 + i
);
707 if (keyvec
& KEY_BIT(i
)) {
708 /* XXX Assert that len > 2 */
709 len
= strlen(format
) - 2;
710 PARROT_ASSERT(len
>= 0);
712 strcat(format
, "[%s], ");
714 else if (r
[i
]->set
== 'K')
715 strcat(format
, "[%s], ");
717 strcat(format
, "%s, ");
720 len
= strlen(format
);
727 strncpy(format
, fmt
, sizeof (format
) - 1);
728 format
[sizeof (format
) - 1] = '\0';
732 IMCC_debug(interp
, DEBUG_PARSER
, "%s %s\t%s\n", name
, format
, fullname
);
735 /* make the instruction */
736 ins
= _mk_instruction(name
, format
, n
, r
, dirs
);
739 /* fill in oplib's info */
743 /* mark end as absolute branch */
744 if (STREQ(name
, "end") || STREQ(name
, "ret")) {
745 ins
->type
|= ITBRANCH
| IF_goto
;
747 else if (STREQ(name
, "warningson")) {
748 /* emit a debug seg, if this op is seen */
749 PARROT_WARNINGS_on(interp
, PARROT_WARNINGS_ALL_FLAG
);
751 else if (STREQ(name
, "yield")) {
752 if (!IMCC_INFO(interp
)->cur_unit
->instructions
->symregs
[0])
753 IMCC_fataly(interp
, E_SyntaxError
,
754 "Cannot yield from non-continuation\n");
756 IMCC_INFO(interp
)->cur_unit
->instructions
->symregs
[0]->pcc_sub
->calls_a_sub
759 else if ((strncmp(name
, "invoke", 6) == 0) ||
760 (strncmp(name
, "callmethod", 10) == 0)) {
761 if (IMCC_INFO(interp
)->cur_unit
->type
& IMC_PCCSUB
)
762 IMCC_INFO(interp
)->cur_unit
->instructions
->symregs
[0]->pcc_sub
->calls_a_sub
|= 1;
765 /* set up branch flags
766 * mark registers that are labels */
767 for (i
= 0; i
< op_info
->op_count
- 1; i
++) {
768 if (op_info
->labels
[i
])
769 ins
->type
|= ITBRANCH
| (1 << i
);
771 if (r
[i
]->type
== VTADDRESS
)
772 IMCC_fataly(interp
, E_SyntaxError
,
773 "undefined identifier '%s'\n", r
[i
]->name
);
777 if (op_info
->jump
&& op_info
->jump
!= PARROT_JUMP_ENEXT
) {
778 ins
->type
|= ITBRANCH
;
779 /* TODO use opnum constants */
780 if (STREQ(name
, "branch")
781 || STREQ(name
, "tailcall")
782 || STREQ(name
, "returncc"))
783 ins
->type
|= IF_goto
;
784 else if (STREQ(fullname
, "jump_i")
785 || STREQ(fullname
, "jsr_i")
786 || STREQ(fullname
, "branch_i")
787 || STREQ(fullname
, "bsr_i"))
788 IMCC_INFO(interp
)->dont_optimize
= 1;
790 else if (STREQ(name
, "set") && n
== 2) {
791 /* set Px, Py: both PMCs have the same address */
792 if (r
[0]->set
== r
[1]->set
&& REG_NEEDS_ALLOC(r
[1]))
793 ins
->type
|= ITALIAS
;
795 else if (STREQ(name
, "compile"))
796 ++IMCC_INFO(interp
)->has_compile
;
800 emitb(interp
, unit
, ins
);
805 extern void* yy_scan_string(const char *);
809 =item C<int do_yylex_init>
811 TODO: Needs to be documented!!!
819 do_yylex_init(PARROT_INTERP
, ARGOUT(yyscan_t
* yyscanner
))
821 const int retval
= yylex_init(yyscanner
);
823 /* This way we can get the interpreter via yyscanner */
825 yyset_extra(interp
, *yyscanner
);
832 =item C<PMC * imcc_compile>
834 Compile a pasm or imcc string
836 FIXME as we have separate constants, the old constants in ghash must be deleted.
842 PARROT_WARN_UNUSED_RESULT
843 PARROT_CANNOT_RETURN_NULL
845 imcc_compile(PARROT_INTERP
, ARGIN(const char *s
), int pasm_file
,
846 ARGOUT(STRING
**error_message
))
848 /* imcc always compiles to interp->code
849 * save old cs, make new
852 PackFile_ByteCode
*old_cs
, *new_cs
;
854 struct _imc_info_t
*imc_info
= NULL
;
855 struct parser_state_t
*next
;
857 Parrot_Context
*ignored
;
858 INTVAL regs_used
[4] = {3, 3, 3, 3};
860 do_yylex_init(interp
, &yyscanner
);
862 /* we create not yet anchored PMCs - e.g. Subs: turn off DOD */
863 Parrot_block_GC_mark(interp
);
865 if (IMCC_INFO(interp
)->last_unit
) {
866 /* a reentrant compile */
867 imc_info
= mem_allocate_zeroed_typed(imc_info_t
);
868 imc_info
->ghash
= IMCC_INFO(interp
)->ghash
;
869 imc_info
->prev
= IMCC_INFO(interp
);
870 IMCC_INFO(interp
) = imc_info
;
873 snprintf(name
, sizeof (name
), "EVAL_" INTVAL_FMT
, ++eval_nr
);
874 new_cs
= PF_create_default_segs(interp
, name
, 0);
875 old_cs
= Parrot_switch_to_cs(interp
, new_cs
, 0);
877 IMCC_INFO(interp
)->cur_namespace
= NULL
;
879 /* spit out the sourcefile */
880 if (Interp_debug_TEST(interp
, PARROT_EVAL_DEBUG_FLAG
)) {
881 FILE * const fp
= fopen(name
, "w");
888 IMCC_push_parser_state(interp
);
889 next
= IMCC_INFO(interp
)->state
->next
;
892 IMCC_INFO(interp
)->state
->next
= NULL
;
894 IMCC_INFO(interp
)->state
->pasm_file
= pasm_file
;
895 IMCC_INFO(interp
)->state
->file
= name
;
896 IMCC_INFO(interp
)->expect_pasm
= 0;
898 ignored
= Parrot_push_context(interp
, regs_used
);
901 compile_string(interp
, s
, yyscanner
);
903 Parrot_pop_context(interp
);
906 * compile_string NULLifies frames->next, so that yywrap
907 * doesn't try to continue compiling the previous buffer
908 * This OTOH prevents pop_parser-state ->
910 * set next here and pop
912 IMCC_INFO(interp
)->state
->next
= next
;
913 IMCC_pop_parser_state(interp
, yyscanner
);
915 if (!IMCC_INFO(interp
)->error_code
) {
916 Parrot_sub
*sub_data
;
918 sub
= pmc_new(interp
, enum_class_Eval
);
920 PackFile_fixup_subs(interp
, PBC_MAIN
, sub
);
922 /* restore old byte_code, */
924 (void)Parrot_switch_to_cs(interp
, old_cs
, 0);
929 * TODO if a sub was denoted :main return that instead
931 sub_data
= PMC_sub(sub
);
932 sub_data
->seg
= new_cs
;
933 sub_data
->start_offs
= 0;
934 sub_data
->end_offs
= new_cs
->base
.size
;
935 sub_data
->name
= string_from_cstring(interp
, name
, 0);
938 *error_message
= IMCC_INFO(interp
)->error_message
;
942 IMCC_INFO(interp
) = imc_info
->prev
;
943 mem_sys_free(imc_info
);
944 imc_info
= IMCC_INFO(interp
);
945 IMCC_INFO(interp
)->cur_unit
= imc_info
->last_unit
;
947 if (IMCC_INFO(interp
)->cur_namespace
)
948 free_sym(IMCC_INFO(interp
)->cur_namespace
);
950 IMCC_INFO(interp
)->cur_namespace
= imc_info
->cur_namespace
;
953 imc_cleanup(interp
, yyscanner
);
955 Parrot_unblock_GC_mark(interp
);
957 yylex_destroy(yyscanner
);
964 =item C<PMC * imcc_compile_pasm>
966 TODO: Needs to be documented!!!
968 * Note: This function is provided for backward compatibility. This
969 * function can go away in future.
975 PARROT_WARN_UNUSED_RESULT
976 PARROT_CANNOT_RETURN_NULL
978 imcc_compile_pasm(PARROT_INTERP
, ARGIN(const char *s
))
980 STRING
*error_message
;
981 return imcc_compile(interp
, s
, 1, &error_message
);
986 =item C<PMC * imcc_compile_pir>
988 TODO: Needs to be documented!!!
990 * Note: This function is provided for backward compatibility. This
991 * function can go away in future.
997 PARROT_WARN_UNUSED_RESULT
998 PARROT_CANNOT_RETURN_NULL
1000 imcc_compile_pir(PARROT_INTERP
, ARGIN(const char *s
))
1002 STRING
*error_message
;
1003 return imcc_compile(interp
, s
, 0, &error_message
);
1008 =item C<PMC * IMCC_compile_pir_s>
1010 TODO: Needs to be documented!!!
1016 PARROT_WARN_UNUSED_RESULT
1017 PARROT_CANNOT_RETURN_NULL
1019 IMCC_compile_pir_s(PARROT_INTERP
, ARGIN(const char *s
),
1020 ARGOUT(STRING
**error_message
))
1022 return imcc_compile(interp
, s
, 0, error_message
);
1027 =item C<PMC * IMCC_compile_pasm_s>
1029 TODO: Needs to be documented!!!
1035 PARROT_WARN_UNUSED_RESULT
1036 PARROT_CANNOT_RETURN_NULL
1038 IMCC_compile_pasm_s(PARROT_INTERP
, ARGIN(const char *s
),
1039 ARGOUT(STRING
**error_message
))
1041 return imcc_compile(interp
, s
, 1, error_message
);
1046 =item C<PMC * imcc_compile_pasm_ex>
1048 TODO: Needs to be documented!!!
1054 PARROT_WARN_UNUSED_RESULT
1055 PARROT_CANNOT_RETURN_NULL
1057 imcc_compile_pasm_ex(PARROT_INTERP
, ARGIN(const char *s
))
1059 STRING
*error_message
;
1061 PMC
* const sub
= imcc_compile(interp
, s
, 1, &error_message
);
1066 real_exception(interp
, NULL
, E_Exception
, "%Ss", error_message
);
1071 =item C<PMC * imcc_compile_pir_ex>
1073 TODO: Needs to be documented!!!
1079 PARROT_WARN_UNUSED_RESULT
1080 PARROT_CANNOT_RETURN_NULL
1082 imcc_compile_pir_ex(PARROT_INTERP
, ARGIN(const char *s
))
1084 STRING
*error_message
;
1086 PMC
* const sub
= imcc_compile(interp
, s
, 0, &error_message
);
1090 real_exception(interp
, NULL
, E_Exception
, "%Ss", error_message
);
1095 =item C<static void * imcc_compile_file>
1097 Compile a file by filename (can be either PASM or IMCC code)
1103 PARROT_CANNOT_RETURN_NULL
1105 imcc_compile_file(PARROT_INTERP
, ARGIN(const char *fullname
),
1106 ARGOUT(STRING
**error_message
))
1108 PackFile_ByteCode
* const cs_save
= interp
->code
;
1109 PackFile_ByteCode
*cs
= NULL
;
1110 struct _imc_info_t
*imc_info
= NULL
;
1114 Parrot_Context
*ignored
;
1116 /* need at least 3 regs for compilation of constant math e.g.
1117 * add_i_ic_ic - see also IMCC_subst_constants() */
1118 INTVAL regs_used
[4] = {3, 3, 3, 3};
1120 if (IMCC_INFO(interp
)->last_unit
) {
1121 /* a reentrant compile */
1122 imc_info
= mem_allocate_zeroed_typed(imc_info_t
);
1123 imc_info
->prev
= IMCC_INFO(interp
);
1124 imc_info
->ghash
= IMCC_INFO(interp
)->ghash
;
1125 IMCC_INFO(interp
) = imc_info
;
1128 fs
= string_make(interp
, fullname
, strlen(fullname
), NULL
, 0);
1130 if (Parrot_stat_info_intval(interp
, fs
, STAT_ISDIR
))
1131 real_exception(interp
, NULL
, E_IOError
,
1132 "imcc_compile_file: '%s' is a directory\n", fullname
);
1134 fp
= fopen(fullname
, "r");
1136 IMCC_fatal(interp
, E_IOError
,
1137 "imcc_compile_file: couldn't open '%s'\n", fullname
);
1140 fprintf(stderr
, "parser_util.c: imcc_compile_file '%s'\n", fullname
);
1143 IMCC_INFO(interp
)->cur_namespace
= NULL
;
1144 interp
->code
= NULL
;
1146 IMCC_push_parser_state(interp
);
1147 IMCC_INFO(interp
)->state
->file
= fullname
;
1148 ext
= strrchr(fullname
, '.');
1149 IMCC_INFO(interp
)->line
= 1;
1152 * the string_compare() called from pmc_type() triggers DOD
1153 * which can destroy packfiles under construction
1155 Parrot_block_GC_mark(interp
);
1156 ignored
= Parrot_push_context(interp
, regs_used
);
1159 if (ext
&& STREQ(ext
, ".pasm")) {
1161 do_yylex_init(interp
, &yyscanner
);
1163 IMCC_INFO(interp
)->state
->pasm_file
= 1;
1165 compile_file(interp
, fp
, yyscanner
);
1167 yylex_destroy(yyscanner
);
1171 do_yylex_init(interp
, &yyscanner
);
1173 IMCC_INFO(interp
)->state
->pasm_file
= 0;
1174 compile_file(interp
, fp
, yyscanner
);
1176 yylex_destroy(yyscanner
);
1179 Parrot_unblock_GC_mark(interp
);
1180 Parrot_pop_context(interp
);
1182 imc_cleanup(interp
, NULL
);
1185 if (!IMCC_INFO(interp
)->error_code
)
1188 *error_message
= IMCC_INFO(interp
)->error_message
;
1191 (void)Parrot_switch_to_cs(interp
, cs_save
, 0);
1194 IMCC_INFO(interp
) = imc_info
->prev
;
1195 mem_sys_free(imc_info
);
1203 =item C<void * IMCC_compile_file>
1205 TODO: Needs to be documented!!!
1207 * Note: This function is provided for backward compatibility. This
1208 * function can go away in future.
1214 PARROT_CANNOT_RETURN_NULL
1216 IMCC_compile_file(PARROT_INTERP
, ARGIN(const char *s
))
1218 STRING
*error_message
;
1219 return imcc_compile_file(interp
, s
, &error_message
);
1224 =item C<void * IMCC_compile_file_s>
1226 TODO: Needs to be documented!!!
1232 PARROT_CANNOT_RETURN_NULL
1234 IMCC_compile_file_s(PARROT_INTERP
, ARGIN(const char *s
),
1235 ARGOUT(STRING
**error_message
))
1237 return imcc_compile_file(interp
, s
, error_message
);
1242 =item C<void register_compilers>
1244 Register additional compilers with the interpreter
1251 register_compilers(PARROT_INTERP
)
1253 Parrot_compreg(interp
, const_string(interp
, "PASM"), imcc_compile_pasm_ex
);
1254 Parrot_compreg(interp
, const_string(interp
, "PIR"), imcc_compile_pir_ex
);
1256 /* It looks like this isn't used anywhere yet */
1257 /* TODO: return a Eval PMC, instead of a packfile */
1258 /* Parrot_compreg(interp,
1259 const_string(interp, "FILE"),
1260 imcc_compile_file ); */
1265 =item C<static int change_op>
1267 TODO: Needs to be documented!!!
1273 PARROT_WARN_UNUSED_RESULT
1275 change_op(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGMOD(SymReg
**r
), int num
, int emit
)
1279 if (r
[num
]->type
& (VTCONST
|VT_CONSTP
)) {
1280 /* make a number const */
1281 const SymReg
*c
= r
[num
];
1283 if (c
->type
& VT_CONSTP
)
1286 r
[num
] = mk_const(interp
, c
->name
, 'N');
1298 rr
[0] = mk_temp_reg(interp
, 'N');
1301 INS(interp
, unit
, "set", NULL
, rr
, 2, 0, 1);
1306 /* need to allocate the temp - run reg_alloc */
1307 IMCC_INFO(interp
)->optimizer_level
|= OPT_PASM
;
1315 =item C<int try_find_op>
1317 Try to find valid op doing the same operation e.g.
1319 add_n_i_n => add_n_n_i
1320 div_n_ic_n => div_n_nc_n
1321 div_n_i_n => set_n_i ; div_n_n_n
1322 ge_n_ic_ic => ge_n_nc_ic
1323 acos_n_i => acos_n_n
1329 PARROT_WARN_UNUSED_RESULT
1331 try_find_op(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
1332 ARGMOD(SymReg
**r
), int n
, int keyvec
, int emit
)
1337 * eq_str, eq_num => eq
1340 if (n
== 3 && r
[2]->type
== VTADDRESS
) {
1341 if (STREQ(name
, "eq_str") || STREQ(name
, "eq_num")) {
1345 else if (STREQ(name
, "ne_str") || STREQ(name
, "ne_num")) {
1349 else if (STREQ(name
, "le_str") || STREQ(name
, "le_num")) {
1353 else if (STREQ(name
, "lt_str") || STREQ(name
, "lt_num")) {
1357 else if (STREQ(name
, "ge_str") || STREQ(name
, "ge_num")) {
1361 else if (STREQ(name
, "gt_str") || STREQ(name
, "gt_num")) {
1366 else if (n
== 3 && (STREQ(name
, "cmp_str") || STREQ(name
, "cmp_num"))) {
1370 if (n
== 3 && r
[0]->set
== 'N') {
1371 if (r
[1]->set
== 'I') {
1372 const SymReg
* const r1
= r
[1];
1373 changed
|= change_op(interp
, unit
, r
, 1, emit
);
1375 /* op Nx, Iy, Iy: reuse generated temp Nz */
1376 if (r
[2]->set
== 'I' && r
[2]->type
!= VTADDRESS
&& r
[2] == r1
)
1380 if (r
[2]->set
== 'I' && r
[2]->type
!= VTADDRESS
)
1381 changed
|= change_op(interp
, unit
, r
, 2, emit
);
1384 /* handle eq_i_n_ic */
1385 else if (n
== 3 && r
[1]->set
== 'N' && r
[0]->set
== 'I' &&
1386 r
[2]->type
== VTADDRESS
) {
1387 changed
|= change_op(interp
, unit
, r
, 0, emit
);
1389 else if (n
== 2 && r
[0]->set
== 'N' && r
[1]->set
== 'I') {
1391 * transcendentals e.g. acos N, I
1393 if (!STREQ(name
, "fact"))
1394 changed
= change_op(interp
, unit
, r
, 1, emit
);
1398 op_fullname(fullname
, name
, r
, n
, keyvec
);
1399 return interp
->op_lib
->op_code(fullname
, 1);
1407 =item C<static const char * try_rev_cmp>
1409 TODO: Needs to be documented!!!
1415 PARROT_WARN_UNUSED_RESULT
1416 PARROT_CAN_RETURN_NULL
1418 try_rev_cmp(ARGIN(const char *name
), ARGMOD(SymReg
**r
))
1420 static struct br_pairs
{
1421 ARGIN(const char * const op
);
1422 ARGIN(const char * const nop
);
1427 { "isgt", "islt", 1 },
1428 { "isge", "isle", 1 },
1433 for (i
= 0; i
< N_ELEMENTS(br_pairs
); i
++) {
1434 if (STREQ(name
, br_pairs
[i
].op
)) {
1435 const int to_swap
= br_pairs
[i
].to_swap
;
1438 if (r
[to_swap
+ 1]->set
== 'P')
1442 r
[to_swap
] = r
[to_swap
+ 1];
1445 return br_pairs
[i
].nop
;
1454 =item C<Instruction * multi_keyed>
1456 TODO: Needs to be documented!!!
1462 PARROT_CAN_RETURN_NULL
1464 multi_keyed(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
1465 ARGIN(SymReg
**r
), int nr
, int keyvec
, int emit
)
1468 SymReg
*preg
[3]; /* px, py, pz */
1470 Instruction
*ins
= 0;
1471 Instruction
*unused_ins
= 0;
1474 /* count keys in keyvec */
1477 for (i
= keyf
= 0; i
< nr
; i
++, kv
>>= 1)
1484 /* XXX what to do, if we don't emit instruction? */
1485 PARROT_ASSERT(emit
);
1488 /* OP _p_k _p_k_p_k =>
1497 for (i
= n
= 0; i
< nr
; i
++, kv
>>= 1, n
++) {
1501 IMCC_fataly(interp
, E_SyntaxError
, "illegal key operand\n");
1503 /* make a new P symbol */
1505 snprintf(buf
, sizeof (buf
), "$P%d", ++p
);
1506 } while (get_sym(interp
, buf
));
1508 preg
[n
] = mk_symreg(interp
, buf
, 'P');
1512 /* we have a keyed operand */
1513 if (r
[i
]->set
!= 'P')
1514 IMCC_fataly(interp
, E_SyntaxError
, "not an aggregate\n");
1516 /* don't emit LHS yet */
1523 ins
= INS(interp
, unit
, "set", 0, nreg
, 3, KEY_BIT(1), 0);
1531 INS(interp
, unit
, "set", 0, nreg
, 3, KEY_BIT(2), 1);
1543 ins
= INS(interp
, unit
, "set", 0, nreg
, 2, 0, 0);
1550 INS(interp
, unit
, "set", 0, nreg
, 2, 0, 1);
1554 /* make a new undef */
1555 unused_ins
= iNEW(interp
, unit
, preg
[0], str_dup("Undef"), NULL
, 1);
1558 /* emit the operand */
1559 INS(interp
, unit
, name
, 0, preg
, 3, 0, 1);
1561 /* emit the LHS op */
1562 emitb(interp
, unit
, ins
);
1569 =item C<int imcc_fprintf>
1571 TODO: Needs to be documented!!!
1578 imcc_fprintf(PARROT_INTERP
, ARGMOD(FILE *fd
), ARGIN(const char *fmt
), ...)
1584 len
= imcc_vfprintf(interp
, fd
, fmt
, ap
);
1592 =item C<int imcc_vfprintf>
1594 TODO: Needs to be documented!!!
1601 imcc_vfprintf(PARROT_INTERP
, ARGMOD(FILE *fd
), ARGIN(const char *format
), va_list ap
)
1604 const char *fmt
= format
;
1608 const char *cp
= fmt
;
1612 for (n
= 0; (ch
= *fmt
) && ch
!= '%'; fmt
++, n
++);
1614 /* print prev string */
1616 fwrite(cp
, 1, n
, fd
);
1625 /* ok, we have a format spec */
1631 fwrite(fmt
, 1, 1, fd
);
1637 /* look for end of format spec */
1638 for (; ch
&& strchr("diouxXeEfFgGcspI", ch
) == NULL
; ch
= *++fmt
)
1642 /* no fatal here, else we get recursion */
1643 fprintf(stderr
, "illegal format at %s\n", cp
);
1647 /* ok, we have a valid format char */
1659 const int _int
= va_arg(ap
, int);
1660 memcpy(buf
, cp
, n
= (fmt
- cp
));
1662 len
+= fprintf(fd
, buf
, _int
);
1672 const double _double
= va_arg(ap
, double);
1673 memcpy(buf
, cp
, n
= (fmt
- cp
));
1675 len
+= fprintf(fd
, buf
, _double
);
1680 const char * const _string
= va_arg(ap
, char *);
1681 memcpy(buf
, cp
, n
= (fmt
- cp
));
1682 PARROT_ASSERT(n
<128);
1684 len
+= fprintf(fd
, buf
, _string
);
1687 /* this is the reason for the whole mess */
1690 Instruction
* const _ins
= va_arg(ap
, Instruction
*);
1691 len
+= fprintf(fd
, "%s ", _ins
->opname
);
1692 len
+= ins_print(interp
, fd
, _ins
);
1703 /* Utility functions */
1707 =item C<void imcc_init>
1709 TODO: Needs to be documented!!!
1717 imcc_init(PARROT_INTERP
)
1719 PARROT_ASSERT(IMCC_INFO(interp
) == NULL
);
1721 IMCC_INFO(interp
) = mem_allocate_zeroed_typed(imc_info_t
);
1722 /* register PASM and PIR compilers to parrot core */
1723 register_compilers(interp
);
1728 =item C<void imcc_destroy>
1730 TODO: Needs to be documented!!!
1738 imcc_destroy(PARROT_INTERP
)
1740 Hash
* const macros
= IMCC_INFO(interp
)->macros
;
1743 parrot_chash_destroy(interp
, macros
);
1745 mem_sys_free(IMCC_INFO(interp
));
1746 IMCC_INFO(interp
) = NULL
;
1760 * c-file-style: "parrot"
1762 * vim: expandtab shiftwidth=4: