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"
26 #include "optimizer.h"
32 compilers/imcc/parser_util.c
36 ParserUtil - Parser support functions.
42 /* HEADERIZER HFILE: compilers/imcc/imc.h */
44 /* HEADERIZER BEGIN: static */
45 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
47 PARROT_WARN_UNUSED_RESULT
48 static int change_op(PARROT_INTERP
,
49 ARGMOD(IMC_Unit
*unit
),
53 __attribute__nonnull__(1)
54 __attribute__nonnull__(2)
55 __attribute__nonnull__(3)
59 PARROT_CANNOT_RETURN_NULL
60 static void * imcc_compile_file(PARROT_INTERP
,
61 ARGIN(const char *fullname
),
62 ARGOUT(STRING
**error_message
))
63 __attribute__nonnull__(1)
64 __attribute__nonnull__(2)
65 __attribute__nonnull__(3)
66 FUNC_MODIFIES(*error_message
);
68 PARROT_WARN_UNUSED_RESULT
69 static int is_infix(ARGIN(const char *name
), int n
, ARGIN(SymReg
**r
))
70 __attribute__nonnull__(1)
71 __attribute__nonnull__(3);
73 PARROT_WARN_UNUSED_RESULT
74 PARROT_CANNOT_RETURN_NULL
75 static const char * to_infix(PARROT_INTERP
,
76 ARGIN(const char *name
),
80 __attribute__nonnull__(1)
81 __attribute__nonnull__(2)
82 __attribute__nonnull__(3)
83 __attribute__nonnull__(4)
87 PARROT_WARN_UNUSED_RESULT
88 PARROT_CAN_RETURN_NULL
89 static const char * try_rev_cmp(ARGIN(const char *name
), ARGMOD(SymReg
**r
))
90 __attribute__nonnull__(1)
91 __attribute__nonnull__(2)
95 PARROT_CANNOT_RETURN_NULL
96 PARROT_WARN_UNUSED_RESULT
97 static Instruction
* var_arg_ins(PARROT_INTERP
,
98 ARGMOD(IMC_Unit
*unit
),
99 ARGIN(const char *name
),
103 __attribute__nonnull__(1)
104 __attribute__nonnull__(2)
105 __attribute__nonnull__(3)
106 __attribute__nonnull__(4)
110 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
111 /* HEADERIZER END: static */
116 * used in -D20 to print files with the output of every PIR compilation
117 * this can't be attached to the interpreter or packfile because it has to be
118 * absolutely global to prevent the files from being overwritten.
120 * This is not thread safe as is. A mutex needs to be added.
122 * See RT#40010 for more discussion.
124 static INTVAL eval_nr
= 0;
132 =item C<Instruction * iNEW>
134 * P = new type, [init]
137 * is done in the lexer, this is a mess
138 * best would be to have a flag in core.ops, where a PMC type is expected
144 PARROT_WARN_UNUSED_RESULT
145 PARROT_CAN_RETURN_NULL
147 iNEW(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGMOD(SymReg
*r0
),
148 ARGMOD(char *type
), ARGIN_NULLOK(SymReg
*init
), int emit
)
154 const int pmc_num
= pmc_type(interp
,
155 string_from_cstring(interp
, *type
== '.' ? type
+ 1 : type
, 0));
157 snprintf(fmt
, sizeof (fmt
), "%d", pmc_num
);
158 pmc
= mk_const(interp
, fmt
, 'I');
161 IMCC_fataly(interp
, EXCEPTION_SYNTAX_ERROR
, "Unknown PMC type '%s'\n", type
);
163 snprintf(fmt
, sizeof (fmt
), "%%s, %d\t # .%s", pmc_num
, type
);
166 if (STREQ(type
, "Hash"))
167 r0
->usage
|= U_KEYED
;
179 return INS(interp
, unit
, "new", fmt
, regs
, nargs
, 0, emit
);
184 =item C<void op_fullname>
186 Lookup the full opcode given the short name
188 set I0, 5 -> set_i_ic
189 set I0, I1 -> set_i_i
191 Obviously the registers must be examined before returning the correct
194 NOTE: All this nasty IMC_TRACE is for tracking down equally nasty bugs, so
195 if you don't like the looks of it, stay out, but please don't remove it. :)
202 op_fullname(ARGOUT(char *dest
), ARGIN(const char *name
),
203 ARGIN(SymReg
* const *args
), int narg
, int keyvec
)
209 PIO_eprintf(NULL
, "op %s", name
);
214 dest
+= strlen(name
);
216 for (i
= 0; i
< narg
&& args
[i
]; i
++) {
218 if (args
[i
]->type
== VTADDRESS
) {
220 PIO_eprintf(NULL
, " (address)%s", args
[i
]->name
);
226 /* if one ever wants num keys, they go with 'S' */
227 if (keyvec
& KEY_BIT(i
)) {
229 PIO_eprintf(NULL
, " (key)%s", args
[i
]->name
);
232 if (args
[i
]->set
=='S' || args
[i
]->set
=='N' || args
[i
]->set
=='K') {
236 else if (args
[i
]->set
== 'P')
240 if (args
[i
]->set
== 'K')
243 *dest
++ = (char)tolower((unsigned char)args
[i
]->set
);
245 if (args
[i
]->type
& (VTCONST
|VT_CONSTP
)) {
247 PIO_eprintf(NULL
, " (%cc)%s", tolower((unsigned char)args
[i
]->set
), args
[i
]->name
);
253 PIO_eprintf(NULL
, " (%c)%s", tolower((unsigned char)args
[i
]->set
), args
[i
]->name
);
258 PIO_eprintf(NULL
, " -> %s\n", full
);
264 =item C<int check_op>
266 Return opcode value for op name
272 PARROT_WARN_UNUSED_RESULT
274 check_op(PARROT_INTERP
, ARGOUT(char *fullname
), ARGIN(const char *name
),
275 ARGIN(SymReg
* const * r
), int narg
, int keyvec
)
277 op_fullname(fullname
, name
, r
, narg
, keyvec
);
279 return interp
->op_lib
->op_code(fullname
, 1);
286 Is instruction a parrot opcode?
292 PARROT_WARN_UNUSED_RESULT
294 is_op(PARROT_INTERP
, ARGIN(const char *name
))
296 return interp
->op_lib
->op_code(name
, 0) >= 0
297 || interp
->op_lib
->op_code(name
, 1) >= 0
298 || ((name
[0] == 'n' && name
[1] == '_')
299 && (interp
->op_lib
->op_code(name
+ 2, 0) >= 0
300 || interp
->op_lib
->op_code(name
+ 2, 1) >= 0));
305 =item C<static const char * to_infix>
307 sub x, y, z => infix .MMD_SUBTRACT, x, y, z
313 PARROT_WARN_UNUSED_RESULT
314 PARROT_CANNOT_RETURN_NULL
316 to_infix(PARROT_INTERP
, ARGIN(const char *name
), ARGMOD(SymReg
**r
),
317 ARGMOD(int *n
), int mmd_op
)
322 PARROT_ASSERT(*n
>= 2);
324 is_n
= (IMCC_INFO(interp
)->state
->pragmas
& PR_N_OPERATORS
) ||
325 (name
[0] == 'n' && name
[1] == '_') ||
326 (mmd_op
== MMD_LOR
|| mmd_op
== MMD_LAND
|| mmd_op
== MMD_LXOR
);
328 if (*n
== 3 && r
[0] == r
[1] && !is_n
) { /* cvt to inplace */
330 snprintf(buf
, sizeof (buf
), "%d", mmd_op
+ 1); /* XXX */
331 mmd
= mk_const(interp
, buf
, 'I');
336 for (i
= *n
; i
> 0; --i
)
339 snprintf(buf
, sizeof (buf
), "%d", *n
== 2 ? (mmd_op
+ 1) : mmd_op
); /* XXX */
340 mmd
= mk_const(interp
, buf
, 'I');
354 =item C<static int is_infix>
356 TODO: Needs to be documented!!!
362 PARROT_WARN_UNUSED_RESULT
364 is_infix(ARGIN(const char *name
), int n
, ARGIN(SymReg
**r
))
366 if (n
< 2 || r
[0]->set
!= 'P')
369 /* TODO use a generic Parrot interface function,
370 * which handles user infix extensions too
372 if (STREQ(name
, "add"))
374 if (STREQ(name
, "sub"))
376 if (STREQ(name
, "mul"))
378 if (STREQ(name
, "div"))
380 if (STREQ(name
, "fdiv"))
381 return MMD_FLOOR_DIVIDE
;
382 if (STREQ(name
, "mod"))
384 if (STREQ(name
, "cmod"))
386 if (STREQ(name
, "pow"))
389 if (STREQ(name
, "bor"))
391 if (STREQ(name
, "band"))
393 if (STREQ(name
, "bxor"))
395 if (STREQ(name
, "bors"))
397 if (STREQ(name
, "bands"))
399 if (STREQ(name
, "bxors"))
402 if (STREQ(name
, "shl"))
404 if (STREQ(name
, "shr"))
406 if (STREQ(name
, "lsr"))
409 if (STREQ(name
, "concat"))
411 if (STREQ(name
, "repeat"))
414 if (STREQ(name
, "or"))
416 if (STREQ(name
, "and"))
418 if (STREQ(name
, "xor"))
422 if (name
[0] == 'n' && name
[1] == '_')
423 return is_infix(name
+ 2, n
, r
);
430 =item C<static Instruction * var_arg_ins>
432 TODO: Needs to be documented!!!
439 PARROT_CANNOT_RETURN_NULL
440 PARROT_WARN_UNUSED_RESULT
442 var_arg_ins(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
443 ARGMOD(SymReg
**r
), int n
, int emit
)
452 r
[0] = mk_const(interp
, r
[0]->name
, 'P');
453 r
[0]->pmc_type
= enum_class_FixedIntegerArray
;
455 op_fullname(fullname
, name
, r
, 1, 0);
456 op
= interp
->op_lib
->op_code(fullname
, 1);
458 PARROT_ASSERT(op
>= 0);
460 ins
= _mk_instruction(name
, "", n
, r
, dirs
);
465 emitb(interp
, unit
, ins
);
472 =item C<Instruction * INS>
474 Makes an instruction.
477 fmt ... optional format
479 n ... number of params
480 keyvec ... see KEY_BIT()
481 emit ... if true, append to instructions
489 PARROT_IGNORABLE_RESULT
490 PARROT_CAN_RETURN_NULL
492 INS(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
493 ARGIN_NULLOK(const char *fmt
), ARGIN(SymReg
**r
), int n
, int keyvec
,
500 char fullname
[64], format
[128], buf
[10];
502 if ((STREQ(name
, "set_args"))
503 || (STREQ(name
, "get_results"))
504 || (STREQ(name
, "get_params"))
505 || (STREQ(name
, "set_returns")))
506 return var_arg_ins(interp
, unit
, name
, r
, n
, emit
);
508 op
= is_infix(name
, n
, r
);
511 /* sub x, y, z => infix .MMD_SUBTRACT, x, y, z */
512 name
= to_infix(interp
, name
, r
, &n
, op
);
514 else if ((IMCC_INFO(interp
)->state
->pragmas
& PR_N_OPERATORS
)
515 && ((STREQ(name
, "abs"))
516 || (STREQ(name
, "neg"))
517 || (STREQ(name
, "not"))
518 || (STREQ(name
, "bnot"))
519 || (STREQ(name
, "bnots")))) {
526 ins
= multi_keyed(interp
, unit
, name
, r
, n
, keyvec
, emit
);
531 op_fullname(fullname
, name
, r
, n
, keyvec
);
532 op
= interp
->op_lib
->op_code(fullname
, 1);
534 /* maybe we have a fullname */
536 op
= interp
->op_lib
->op_code(name
, 1);
538 /* still wrong, try reverse compare */
540 const char * const n_name
= try_rev_cmp(name
, r
);
543 op_fullname(fullname
, name
, r
, n
, keyvec
);
544 op
= interp
->op_lib
->op_code(fullname
, 1);
548 /* still wrong, try to find an existing op */
550 op
= try_find_op(interp
, unit
, name
, r
, n
, keyvec
, emit
);
555 /* check mixed constants */
556 ins
= IMCC_subst_constants_umix(interp
, unit
, name
, r
, n
+ 1);
560 /* and finally multiple constants */
561 ins
= IMCC_subst_constants(interp
, unit
, name
, r
, n
+ 1, &ok
);
571 strcpy(fullname
, name
);
574 IMCC_fataly(interp
, EXCEPTION_SYNTAX_ERROR
,
575 "The opcode '%s' (%s<%d>) was not found. "
576 "Check the type and number of the arguments",
579 op_info
= &interp
->op_info_table
[op
];
582 /* info->op_count is args + 1
583 * build instruction format
584 * set LV_in / out flags */
585 if (n
!= op_info
->op_count
- 1)
586 IMCC_fataly(interp
, EXCEPTION_SYNTAX_ERROR
,
587 "arg count mismatch: op #%d '%s' needs %d given %d",
588 op
, fullname
, op_info
->op_count
-1, n
);
590 /* XXX Speed up some by keep track of the end of format ourselves */
591 for (i
= 0; i
< n
; i
++) {
592 switch (op_info
->dirs
[i
]) {
593 case PARROT_ARGDIR_INOUT
:
594 dirs
|= 1 << (16 + i
);
596 case PARROT_ARGDIR_IN
:
600 case PARROT_ARGDIR_OUT
:
601 dirs
|= 1 << (16 + i
);
608 if (keyvec
& KEY_BIT(i
)) {
609 /* XXX Assert that len > 2 */
610 len
= strlen(format
) - 2;
611 PARROT_ASSERT(len
>= 0);
613 strcat(format
, "[%s], ");
615 else if (r
[i
]->set
== 'K')
616 strcat(format
, "[%s], ");
618 strcat(format
, "%s, ");
621 len
= strlen(format
);
628 strncpy(format
, fmt
, sizeof (format
) - 1);
629 format
[sizeof (format
) - 1] = '\0';
632 IMCC_debug(interp
, DEBUG_PARSER
, "%s %s\t%s\n", name
, format
, fullname
);
634 /* make the instruction */
635 ins
= _mk_instruction(name
, format
, n
, r
, dirs
);
638 /* fill in oplib's info */
642 /* mark end as absolute branch */
643 if (STREQ(name
, "end") || STREQ(name
, "ret")) {
644 ins
->type
|= ITBRANCH
| IF_goto
;
646 else if (STREQ(name
, "warningson")) {
647 /* emit a debug seg, if this op is seen */
648 PARROT_WARNINGS_on(interp
, PARROT_WARNINGS_ALL_FLAG
);
650 else if (STREQ(name
, "yield")) {
651 if (!IMCC_INFO(interp
)->cur_unit
->instructions
->symregs
[0])
652 IMCC_fataly(interp
, EXCEPTION_SYNTAX_ERROR
,
653 "Cannot yield from non-continuation\n");
655 IMCC_INFO(interp
)->cur_unit
->instructions
->symregs
[0]->pcc_sub
->calls_a_sub
658 else if ((strncmp(name
, "invoke", 6) == 0) ||
659 (strncmp(name
, "callmethod", 10) == 0)) {
660 if (IMCC_INFO(interp
)->cur_unit
->type
& IMC_PCCSUB
)
661 IMCC_INFO(interp
)->cur_unit
->instructions
->symregs
[0]->pcc_sub
->calls_a_sub
|= 1;
664 /* set up branch flags
665 * mark registers that are labels */
666 for (i
= 0; i
< op_info
->op_count
- 1; i
++) {
667 if (op_info
->labels
[i
])
668 ins
->type
|= ITBRANCH
| (1 << i
);
670 if (r
[i
]->type
== VTADDRESS
)
671 IMCC_fataly(interp
, EXCEPTION_SYNTAX_ERROR
,
672 "undefined identifier '%s'\n", r
[i
]->name
);
676 if (op_info
->jump
&& op_info
->jump
!= PARROT_JUMP_ENEXT
) {
677 ins
->type
|= ITBRANCH
;
678 /* TODO use opnum constants */
679 if (STREQ(name
, "branch")
680 || STREQ(name
, "tailcall")
681 || STREQ(name
, "returncc"))
682 ins
->type
|= IF_goto
;
683 else if (STREQ(fullname
, "jump_i")
684 || STREQ(fullname
, "jsr_i")
685 || STREQ(fullname
, "branch_i")
686 || STREQ(fullname
, "bsr_i"))
687 IMCC_INFO(interp
)->dont_optimize
= 1;
689 else if (STREQ(name
, "set") && n
== 2) {
690 /* set Px, Py: both PMCs have the same address */
691 if (r
[0]->set
== r
[1]->set
&& REG_NEEDS_ALLOC(r
[1]))
692 ins
->type
|= ITALIAS
;
694 else if (STREQ(name
, "compile"))
695 ++IMCC_INFO(interp
)->has_compile
;
699 emitb(interp
, unit
, ins
);
704 extern void* yy_scan_string(const char *);
708 =item C<int do_yylex_init>
710 TODO: Needs to be documented!!!
718 do_yylex_init(PARROT_INTERP
, ARGOUT(yyscan_t
* yyscanner
))
720 const int retval
= yylex_init(yyscanner
);
722 /* This way we can get the interpreter via yyscanner */
724 yyset_extra(interp
, *yyscanner
);
731 =item C<PMC * imcc_compile>
733 Compile a pasm or imcc string
735 FIXME as we have separate constants, the old constants in ghash must be deleted.
741 PARROT_WARN_UNUSED_RESULT
742 PARROT_CANNOT_RETURN_NULL
744 imcc_compile(PARROT_INTERP
, ARGIN(const char *s
), int pasm_file
,
745 ARGOUT(STRING
**error_message
))
747 /* imcc always compiles to interp->code
748 * save old cs, make new
751 PackFile_ByteCode
*old_cs
, *new_cs
;
753 struct _imc_info_t
*imc_info
= NULL
;
754 struct parser_state_t
*next
;
756 Parrot_Context
*ignored
;
757 INTVAL regs_used
[4] = {3, 3, 3, 3};
759 do_yylex_init(interp
, &yyscanner
);
761 /* we create not yet anchored PMCs - e.g. Subs: turn off DOD */
762 Parrot_block_GC_mark(interp
);
764 if (IMCC_INFO(interp
)->last_unit
) {
765 /* a reentrant compile */
766 imc_info
= mem_allocate_zeroed_typed(imc_info_t
);
767 imc_info
->ghash
= IMCC_INFO(interp
)->ghash
;
768 imc_info
->prev
= IMCC_INFO(interp
);
769 IMCC_INFO(interp
) = imc_info
;
772 ignored
= Parrot_push_context(interp
, regs_used
);
775 snprintf(name
, sizeof (name
), "EVAL_" INTVAL_FMT
, ++eval_nr
);
776 new_cs
= PF_create_default_segs(interp
, name
, 0);
777 old_cs
= Parrot_switch_to_cs(interp
, new_cs
, 0);
779 IMCC_INFO(interp
)->cur_namespace
= NULL
;
781 /* spit out the sourcefile */
782 if (Interp_debug_TEST(interp
, PARROT_EVAL_DEBUG_FLAG
)) {
783 FILE * const fp
= fopen(name
, "w");
790 IMCC_push_parser_state(interp
);
791 next
= IMCC_INFO(interp
)->state
->next
;
794 IMCC_INFO(interp
)->state
->next
= NULL
;
796 IMCC_INFO(interp
)->state
->pasm_file
= pasm_file
;
797 IMCC_INFO(interp
)->state
->file
= name
;
798 IMCC_INFO(interp
)->expect_pasm
= 0;
800 compile_string(interp
, s
, yyscanner
);
802 Parrot_pop_context(interp
);
805 * compile_string NULLifies frames->next, so that yywrap
806 * doesn't try to continue compiling the previous buffer
807 * This OTOH prevents pop_parser-state ->
809 * set next here and pop
811 IMCC_INFO(interp
)->state
->next
= next
;
812 IMCC_pop_parser_state(interp
, yyscanner
);
814 if (!IMCC_INFO(interp
)->error_code
) {
815 Parrot_sub
*sub_data
;
817 sub
= pmc_new(interp
, enum_class_Eval
);
819 PackFile_fixup_subs(interp
, PBC_MAIN
, sub
);
821 /* restore old byte_code, */
823 (void)Parrot_switch_to_cs(interp
, old_cs
, 0);
828 * TODO if a sub was denoted :main return that instead
830 sub_data
= PMC_sub(sub
);
831 sub_data
->seg
= new_cs
;
832 sub_data
->start_offs
= 0;
833 sub_data
->end_offs
= new_cs
->base
.size
;
834 sub_data
->name
= string_from_cstring(interp
, name
, 0);
837 *error_message
= IMCC_INFO(interp
)->error_message
;
841 IMCC_INFO(interp
) = imc_info
->prev
;
842 mem_sys_free(imc_info
);
843 imc_info
= IMCC_INFO(interp
);
844 IMCC_INFO(interp
)->cur_unit
= imc_info
->last_unit
;
846 if (IMCC_INFO(interp
)->cur_namespace
)
847 free_sym(IMCC_INFO(interp
)->cur_namespace
);
849 IMCC_INFO(interp
)->cur_namespace
= imc_info
->cur_namespace
;
852 imc_cleanup(interp
, yyscanner
);
854 Parrot_unblock_GC_mark(interp
);
856 yylex_destroy(yyscanner
);
863 =item C<PMC * imcc_compile_pasm>
865 TODO: Needs to be documented!!!
867 * Note: This function is provided for backward compatibility. This
868 * function can go away in future.
874 PARROT_WARN_UNUSED_RESULT
875 PARROT_CANNOT_RETURN_NULL
877 imcc_compile_pasm(PARROT_INTERP
, ARGIN(const char *s
))
879 STRING
*error_message
;
880 return imcc_compile(interp
, s
, 1, &error_message
);
885 =item C<PMC * imcc_compile_pir>
887 TODO: Needs to be documented!!!
889 * Note: This function is provided for backward compatibility. This
890 * function can go away in future.
896 PARROT_WARN_UNUSED_RESULT
897 PARROT_CANNOT_RETURN_NULL
899 imcc_compile_pir(PARROT_INTERP
, ARGIN(const char *s
))
901 STRING
*error_message
;
902 return imcc_compile(interp
, s
, 0, &error_message
);
907 =item C<PMC * IMCC_compile_pir_s>
909 TODO: Needs to be documented!!!
915 PARROT_WARN_UNUSED_RESULT
916 PARROT_CANNOT_RETURN_NULL
918 IMCC_compile_pir_s(PARROT_INTERP
, ARGIN(const char *s
),
919 ARGOUT(STRING
**error_message
))
921 return imcc_compile(interp
, s
, 0, error_message
);
926 =item C<PMC * IMCC_compile_pasm_s>
928 TODO: Needs to be documented!!!
934 PARROT_WARN_UNUSED_RESULT
935 PARROT_CANNOT_RETURN_NULL
937 IMCC_compile_pasm_s(PARROT_INTERP
, ARGIN(const char *s
),
938 ARGOUT(STRING
**error_message
))
940 return imcc_compile(interp
, s
, 1, error_message
);
945 =item C<PMC * imcc_compile_pasm_ex>
947 TODO: Needs to be documented!!!
953 PARROT_WARN_UNUSED_RESULT
954 PARROT_CANNOT_RETURN_NULL
956 imcc_compile_pasm_ex(PARROT_INTERP
, ARGIN(const char *s
))
958 STRING
*error_message
;
960 PMC
* const sub
= imcc_compile(interp
, s
, 1, &error_message
);
965 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_SYNTAX_ERROR
, "%Ss",
971 =item C<PMC * imcc_compile_pir_ex>
973 TODO: Needs to be documented!!!
979 PARROT_WARN_UNUSED_RESULT
980 PARROT_CANNOT_RETURN_NULL
982 imcc_compile_pir_ex(PARROT_INTERP
, ARGIN(const char *s
))
984 STRING
*error_message
;
986 PMC
* const sub
= imcc_compile(interp
, s
, 0, &error_message
);
990 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_SYNTAX_ERROR
, "%Ss",
996 =item C<static void * imcc_compile_file>
998 Compile a file by filename (can be either PASM or IMCC code)
1004 PARROT_CANNOT_RETURN_NULL
1006 imcc_compile_file(PARROT_INTERP
, ARGIN(const char *fullname
),
1007 ARGOUT(STRING
**error_message
))
1009 PackFile_ByteCode
* const cs_save
= interp
->code
;
1010 PackFile_ByteCode
*cs
= NULL
;
1011 struct _imc_info_t
*imc_info
= NULL
;
1015 Parrot_Context
*ignored
;
1017 /* need at least 3 regs for compilation of constant math e.g.
1018 * add_i_ic_ic - see also IMCC_subst_constants() */
1019 INTVAL regs_used
[4] = {3, 3, 3, 3};
1021 if (IMCC_INFO(interp
)->last_unit
) {
1022 /* a reentrant compile */
1023 imc_info
= mem_allocate_zeroed_typed(imc_info_t
);
1024 imc_info
->prev
= IMCC_INFO(interp
);
1025 imc_info
->ghash
= IMCC_INFO(interp
)->ghash
;
1026 IMCC_INFO(interp
) = imc_info
;
1029 fs
= string_make(interp
, fullname
, strlen(fullname
), NULL
, 0);
1031 if (Parrot_stat_info_intval(interp
, fs
, STAT_ISDIR
))
1032 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_EXTERNAL_ERROR
,
1033 "imcc_compile_file: '%s' is a directory\n", fullname
);
1035 fp
= fopen(fullname
, "r");
1037 IMCC_fatal(interp
, EXCEPTION_EXTERNAL_ERROR
,
1038 "imcc_compile_file: couldn't open '%s'\n", fullname
);
1041 fprintf(stderr
, "parser_util.c: imcc_compile_file '%s'\n", fullname
);
1044 IMCC_INFO(interp
)->cur_namespace
= NULL
;
1045 interp
->code
= NULL
;
1047 IMCC_push_parser_state(interp
);
1048 IMCC_INFO(interp
)->state
->file
= fullname
;
1049 ext
= strrchr(fullname
, '.');
1050 IMCC_INFO(interp
)->line
= 1;
1053 * the string_compare() called from pmc_type() triggers DOD
1054 * which can destroy packfiles under construction
1056 Parrot_block_GC_mark(interp
);
1057 ignored
= Parrot_push_context(interp
, regs_used
);
1060 if (ext
&& STREQ(ext
, ".pasm")) {
1062 do_yylex_init(interp
, &yyscanner
);
1064 IMCC_INFO(interp
)->state
->pasm_file
= 1;
1066 compile_file(interp
, fp
, yyscanner
);
1068 yylex_destroy(yyscanner
);
1072 do_yylex_init(interp
, &yyscanner
);
1074 IMCC_INFO(interp
)->state
->pasm_file
= 0;
1075 compile_file(interp
, fp
, yyscanner
);
1077 yylex_destroy(yyscanner
);
1080 Parrot_unblock_GC_mark(interp
);
1081 Parrot_pop_context(interp
);
1083 imc_cleanup(interp
, NULL
);
1086 if (!IMCC_INFO(interp
)->error_code
)
1089 *error_message
= IMCC_INFO(interp
)->error_message
;
1092 (void)Parrot_switch_to_cs(interp
, cs_save
, 0);
1095 IMCC_INFO(interp
) = imc_info
->prev
;
1096 mem_sys_free(imc_info
);
1104 =item C<void * IMCC_compile_file>
1106 TODO: Needs to be documented!!!
1108 * Note: This function is provided for backward compatibility. This
1109 * function can go away in future.
1115 PARROT_CANNOT_RETURN_NULL
1117 IMCC_compile_file(PARROT_INTERP
, ARGIN(const char *s
))
1119 STRING
*error_message
;
1120 return imcc_compile_file(interp
, s
, &error_message
);
1125 =item C<void * IMCC_compile_file_s>
1127 TODO: Needs to be documented!!!
1133 PARROT_CANNOT_RETURN_NULL
1135 IMCC_compile_file_s(PARROT_INTERP
, ARGIN(const char *s
),
1136 ARGOUT(STRING
**error_message
))
1138 return imcc_compile_file(interp
, s
, error_message
);
1143 =item C<void register_compilers>
1145 Register additional compilers with the interpreter
1152 register_compilers(PARROT_INTERP
)
1154 Parrot_compreg(interp
, const_string(interp
, "PASM"), imcc_compile_pasm_ex
);
1155 Parrot_compreg(interp
, const_string(interp
, "PIR"), imcc_compile_pir_ex
);
1157 /* It looks like this isn't used anywhere yet */
1158 /* TODO: return a Eval PMC, instead of a packfile */
1159 /* Parrot_compreg(interp,
1160 const_string(interp, "FILE"),
1161 imcc_compile_file ); */
1166 =item C<static int change_op>
1168 TODO: Needs to be documented!!!
1174 PARROT_WARN_UNUSED_RESULT
1176 change_op(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGMOD(SymReg
**r
), int num
, int emit
)
1180 if (r
[num
]->type
& (VTCONST
|VT_CONSTP
)) {
1181 /* make a number const */
1182 const SymReg
*c
= r
[num
];
1184 if (c
->type
& VT_CONSTP
)
1187 r
[num
] = mk_const(interp
, c
->name
, 'N');
1199 rr
[0] = mk_temp_reg(interp
, 'N');
1202 INS(interp
, unit
, "set", NULL
, rr
, 2, 0, 1);
1207 /* need to allocate the temp - run reg_alloc */
1208 IMCC_INFO(interp
)->optimizer_level
|= OPT_PASM
;
1216 =item C<int try_find_op>
1218 Try to find valid op doing the same operation e.g.
1220 add_n_i_n => add_n_n_i
1221 div_n_ic_n => div_n_nc_n
1222 div_n_i_n => set_n_i ; div_n_n_n
1223 ge_n_ic_ic => ge_n_nc_ic
1224 acos_n_i => acos_n_n
1230 PARROT_WARN_UNUSED_RESULT
1232 try_find_op(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
1233 ARGMOD(SymReg
**r
), int n
, int keyvec
, int emit
)
1238 * eq_str, eq_num => eq
1241 if (n
== 3 && r
[2]->type
== VTADDRESS
) {
1242 if (STREQ(name
, "eq_str") || STREQ(name
, "eq_num")) {
1246 else if (STREQ(name
, "ne_str") || STREQ(name
, "ne_num")) {
1250 else if (STREQ(name
, "le_str") || STREQ(name
, "le_num")) {
1254 else if (STREQ(name
, "lt_str") || STREQ(name
, "lt_num")) {
1258 else if (STREQ(name
, "ge_str") || STREQ(name
, "ge_num")) {
1262 else if (STREQ(name
, "gt_str") || STREQ(name
, "gt_num")) {
1267 else if (n
== 3 && (STREQ(name
, "cmp_str") || STREQ(name
, "cmp_num"))) {
1271 if (n
== 3 && r
[0]->set
== 'N') {
1272 if (r
[1]->set
== 'I') {
1273 const SymReg
* const r1
= r
[1];
1274 changed
|= change_op(interp
, unit
, r
, 1, emit
);
1276 /* op Nx, Iy, Iy: reuse generated temp Nz */
1277 if (r
[2]->set
== 'I' && r
[2]->type
!= VTADDRESS
&& r
[2] == r1
)
1281 if (r
[2]->set
== 'I' && r
[2]->type
!= VTADDRESS
)
1282 changed
|= change_op(interp
, unit
, r
, 2, emit
);
1285 /* handle eq_i_n_ic */
1286 else if (n
== 3 && r
[1]->set
== 'N' && r
[0]->set
== 'I' &&
1287 r
[2]->type
== VTADDRESS
) {
1288 changed
|= change_op(interp
, unit
, r
, 0, emit
);
1290 else if (n
== 2 && r
[0]->set
== 'N' && r
[1]->set
== 'I') {
1292 * transcendentals e.g. acos N, I
1294 if (!STREQ(name
, "fact"))
1295 changed
= change_op(interp
, unit
, r
, 1, emit
);
1299 op_fullname(fullname
, name
, r
, n
, keyvec
);
1300 return interp
->op_lib
->op_code(fullname
, 1);
1308 =item C<static const char * try_rev_cmp>
1310 TODO: Needs to be documented!!!
1316 PARROT_WARN_UNUSED_RESULT
1317 PARROT_CAN_RETURN_NULL
1319 try_rev_cmp(ARGIN(const char *name
), ARGMOD(SymReg
**r
))
1321 static struct br_pairs
{
1322 ARGIN(const char * const op
);
1323 ARGIN(const char * const nop
);
1328 { "isgt", "islt", 1 },
1329 { "isge", "isle", 1 },
1334 for (i
= 0; i
< N_ELEMENTS(br_pairs
); i
++) {
1335 if (STREQ(name
, br_pairs
[i
].op
)) {
1336 const int to_swap
= br_pairs
[i
].to_swap
;
1339 if (r
[to_swap
+ 1]->set
== 'P')
1343 r
[to_swap
] = r
[to_swap
+ 1];
1346 return br_pairs
[i
].nop
;
1355 =item C<Instruction * multi_keyed>
1357 TODO: Needs to be documented!!!
1363 PARROT_CAN_RETURN_NULL
1365 multi_keyed(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
1366 ARGIN(SymReg
**r
), int nr
, int keyvec
, int emit
)
1369 SymReg
*preg
[3]; /* px, py, pz */
1371 Instruction
*ins
= 0;
1372 Instruction
*unused_ins
= 0;
1375 /* count keys in keyvec */
1378 for (i
= keyf
= 0; i
< nr
; i
++, kv
>>= 1)
1385 /* XXX what to do, if we don't emit instruction? */
1386 PARROT_ASSERT(emit
);
1389 /* OP _p_k _p_k_p_k =>
1398 for (i
= n
= 0; i
< nr
; i
++, kv
>>= 1, n
++) {
1402 IMCC_fataly(interp
, EXCEPTION_SYNTAX_ERROR
, "illegal key operand\n");
1404 /* make a new P symbol */
1406 snprintf(buf
, sizeof (buf
), "$P%d", ++p
);
1407 } while (get_sym(interp
, buf
));
1409 preg
[n
] = mk_symreg(interp
, buf
, 'P');
1413 /* we have a keyed operand */
1414 if (r
[i
]->set
!= 'P')
1415 IMCC_fataly(interp
, EXCEPTION_SYNTAX_ERROR
, "not an aggregate\n");
1417 /* don't emit LHS yet */
1424 ins
= INS(interp
, unit
, "set", 0, nreg
, 3, KEY_BIT(1), 0);
1432 INS(interp
, unit
, "set", 0, nreg
, 3, KEY_BIT(2), 1);
1444 ins
= INS(interp
, unit
, "set", 0, nreg
, 2, 0, 0);
1451 INS(interp
, unit
, "set", 0, nreg
, 2, 0, 1);
1455 /* make a new undef */
1456 unused_ins
= iNEW(interp
, unit
, preg
[0], str_dup("Undef"), NULL
, 1);
1459 /* emit the operand */
1460 INS(interp
, unit
, name
, 0, preg
, 3, 0, 1);
1462 /* emit the LHS op */
1463 emitb(interp
, unit
, ins
);
1470 =item C<int imcc_fprintf>
1472 TODO: Needs to be documented!!!
1479 imcc_fprintf(PARROT_INTERP
, ARGMOD(FILE *fd
), ARGIN(const char *fmt
), ...)
1485 len
= imcc_vfprintf(interp
, fd
, fmt
, ap
);
1493 =item C<int imcc_vfprintf>
1495 TODO: Needs to be documented!!!
1502 imcc_vfprintf(PARROT_INTERP
, ARGMOD(FILE *fd
), ARGIN(const char *format
), va_list ap
)
1505 const char *fmt
= format
;
1509 const char *cp
= fmt
;
1513 for (n
= 0; (ch
= *fmt
) && ch
!= '%'; fmt
++, n
++);
1515 /* print prev string */
1517 fwrite(cp
, 1, n
, fd
);
1526 /* ok, we have a format spec */
1532 fwrite(fmt
, 1, 1, fd
);
1538 /* look for end of format spec */
1539 for (; ch
&& strchr("diouxXeEfFgGcspI", ch
) == NULL
; ch
= *++fmt
)
1543 /* no fatal here, else we get recursion */
1544 fprintf(stderr
, "illegal format at %s\n", cp
);
1548 /* ok, we have a valid format char */
1560 const int _int
= va_arg(ap
, int);
1561 memcpy(buf
, cp
, n
= (fmt
- cp
));
1563 len
+= fprintf(fd
, buf
, _int
);
1573 const double _double
= va_arg(ap
, double);
1574 memcpy(buf
, cp
, n
= (fmt
- cp
));
1576 len
+= fprintf(fd
, buf
, _double
);
1581 const char * const _string
= va_arg(ap
, char *);
1582 memcpy(buf
, cp
, n
= (fmt
- cp
));
1583 PARROT_ASSERT(n
<128);
1585 len
+= fprintf(fd
, buf
, _string
);
1588 /* this is the reason for the whole mess */
1591 Instruction
* const _ins
= va_arg(ap
, Instruction
*);
1592 len
+= fprintf(fd
, "%s ", _ins
->opname
);
1593 len
+= ins_print(interp
, fd
, _ins
);
1604 /* Utility functions */
1608 =item C<void imcc_init>
1610 TODO: Needs to be documented!!!
1618 imcc_init(PARROT_INTERP
)
1620 PARROT_ASSERT(IMCC_INFO(interp
) == NULL
);
1622 IMCC_INFO(interp
) = mem_allocate_zeroed_typed(imc_info_t
);
1623 /* register PASM and PIR compilers to parrot core */
1624 register_compilers(interp
);
1629 =item C<void imcc_destroy>
1631 TODO: Needs to be documented!!!
1639 imcc_destroy(PARROT_INTERP
)
1641 Hash
* const macros
= IMCC_INFO(interp
)->macros
;
1644 parrot_chash_destroy(interp
, macros
);
1646 mem_sys_free(IMCC_INFO(interp
));
1647 IMCC_INFO(interp
) = NULL
;
1661 * c-file-style: "parrot"
1663 * vim: expandtab shiftwidth=4: