Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

1531 lines (1221 sloc) 43.674 kb
%top{
/* ex: set ro ft=c: -*- buffer-read-only:t -*-
* !!!!!!! DO NOT EDIT THIS FILE !!!!!!!
*
* This file is generated automatically by the Parrot build process
* from the file compilers/imcc/imcc.l.
*
* Any changes made here will be lost!
*
*/
/* HEADERIZER HFILE: none */
/* HEADERIZER STOP */
#ifndef __STDC_VERSION__
# define __STDC_VERSION__ 0
#endif
#include "imc.h"
#include "parser.h"
}
%{
/*
* imcc.l
*
* Intermediate Code Compiler for Parrot
*
* Copyright (C) 2002 Melvin Smith <melvin.smith@mindspring.com>
* Copyright (C) 2002-2008, Parrot Foundation.
*
* The tokenizer.
*
*
*/
/* static function declarations */
static void pop_parser_state(ARGMOD(imc_info_t *imcc), ARGMOD(void *yyscanner));
static struct macro_frame_t *new_frame(ARGMOD(imc_info_t *imcc));
static void define_macro(ARGMOD(imc_info_t *imcc), ARGIN(const char *name), ARGIN(const params_t *params),
ARGIN(const char *expansion), int start_line);
static macro_t *find_macro(ARGMOD(imc_info_t *imcc), ARGIN(const char *name));
static void scan_string(macro_frame_t *frame, ARGIN(const char *expansion),
ARGMOD(void *yyscanner));
static void scan_file(ARGMOD(imc_info_t *imcc), ARGIN(struct macro_frame_t *frame), PIOHANDLE file,
ARGMOD(void *yyscanner));
static int destroy_frame(macro_frame_t *frame, ARGMOD(void *yyscanner));
static int yylex_skip(YYSTYPE *valp, ARGMOD(imc_info_t *imcc), ARGIN(const char *skip),
ARGMOD(void *yyscanner));
static int read_macro(YYSTYPE *valp, ARGMOD(imc_info_t *imcc), ARGMOD(void *yyscanner));
static int expand_macro(ARGMOD(imc_info_t *imcc), ARGIN(const char *name), ARGMOD(void *yyscanner));
static void include_file(ARGMOD(imc_info_t *imcc), ARGIN(STRING *file_name), ARGMOD(void *yyscanner));
static int handle_identifier(ARGMOD(imc_info_t *imcc), YYSTYPE *valp, ARGIN(const char *id));
#define YY_DECL int yylex(YYSTYPE *valp, yyscan_t yyscanner, ARGMOD(imc_info_t *imcc))
#define YYCHOP() (yytext[--yyleng] = '\0')
#define SET_LINE_NUMBER (imcc->line = yylineno)
#define DUP_AND_RET(valp, token) \
do { \
if (valp) (valp)->s = mem_sys_strndup(yytext, yyleng); \
return (token); \
} while (0)
#define DUP_AND_RET_FREE(valp, token) \
do { \
if (valp) { \
mem_sys_free((valp)->s); \
(valp)->s = mem_sys_strndup(yytext, yyleng); \
return (token); \
} \
} while (0)
#define YY_INPUT(buf, result, max_size) \
(result) = Parrot_io_internal_read(yyextra->interp, (PIOHANDLE)yyin, (buf), (max_size))
%}
%option reentrant
%option never-interactive
%option stack
%option yylineno
LETTER [a-zA-Z_@]
DIGIT [0-9]
DIGITS {DIGIT}+
HEX 0[xX][0-9A-Fa-f]+
OCT 0[oO][0-7]+
BIN 0[bB][01]+
DOT [.]
SIGN [-+]
FLOATNUM {SIGN}?(({DIGITS}{DOT}{DIGIT}*|{DOT}{DIGITS})([eE]{SIGN}?{DIGITS})?|{DIGITS}[eE]{SIGN}?{DIGITS})
LETTERDIGIT [a-zA-Z0-9_]
LABELLETTERDIGIT([a-zA-Z0-9_@])
ID {LETTER}{LABELLETTERDIGIT}*
DQ_STRING \"(\\.|[^"\\\n])*\"
ENCCHAR {LETTER}|{DIGIT}|"-"
ENCCHARS {ENCCHAR}*
ENC {LETTER}{ENCCHARS}":"
UNICODE {ENC}{DQ_STRING}
STRINGCONSTANT {SQ_STRING}|{DQ_STRING}
SQ_STRING \'[^'\n]*\'
EOL \r?\n
WS [\t\f\r\x1a ]
SP [ ]
%x emit
%x macro
%x pod
%x cmt1
%x cmt2
%x cmt3
%x cmt4
%x cmt5
%x heredoc1
%x heredoc2
%%
/* for emacs "*/
if (imcc->expect_pasm == 1 && !imcc->in_pod) {
imcc->expect_pasm = 2;
BEGIN(emit);
}
if (imcc->frames->s.pasm_file && YYSTATE == INITIAL &&
!imcc->in_pod)
{
if (imcc->frames->s.pasm_file == 1) {
BEGIN(emit);
return EMIT;
}
return 0;
}
<*>^{WS}* { SET_LINE_NUMBER; }
<heredoc1>.*{EOL} {
SET_LINE_NUMBER;
imcc->frames->heredoc_rest = mem_sys_strndup(yytext, yyleng);
BEGIN(heredoc2);
}
<heredoc2>{EOL} {
/* heredocs have highest priority
* arrange them before all wildcard state matches */
/* Newline in the heredoc. Realloc and cat on. */
imcc->heredoc_content =
(char*)mem_sys_realloc(imcc->heredoc_content,
strlen(imcc->heredoc_content) + 3);
strcpy(imcc->heredoc_content +
strlen(imcc->heredoc_content), "\n");
}
<heredoc2>([^\r\n]|\r[^\n])* {
SET_LINE_NUMBER;
/* Are we at the end of the heredoc? */
if (STREQ(imcc->heredoc_end, yytext)) {
/* End of the heredoc. */
/*yyguts_t * const yyg = (yyguts_t *)yyscanner;*/
const int len = strlen(imcc->heredoc_content);
/* delim */
imcc->heredoc_content[len] =
imcc->heredoc_content[0];
imcc->heredoc_content[len + 1] = 0;
mem_sys_free(imcc->heredoc_end);
imcc->heredoc_end = NULL;
imcc->frames->buffer = YY_CURRENT_BUFFER;
valp->s =
imcc->heredoc_content;
yy_pop_state(yyscanner);
yy_scan_string(imcc->frames->heredoc_rest, yyscanner);
return STRINGC;
}
else {
/* Part of the heredoc. Realloc and cat the line on. */
imcc->heredoc_content =
(char *)mem_sys_realloc(imcc->heredoc_content,
strlen(imcc->heredoc_content) +
strlen(yytext) + 2);
strcpy(imcc->heredoc_content +
strlen(imcc->heredoc_content), yytext);
}
}
<cmt2>[^"]+ {
STRING *str;
yy_pop_state(yyscanner);
yy_push_state(cmt3, yyscanner);
str = Parrot_str_new(imcc->interp, yytext, 0);
imcc->frames->s.file = str;
imcc->cur_unit->file = str;
return FILECOMMENT;
}
<cmt3>["] {
yy_pop_state(yyscanner);
yy_push_state(cmt4, yyscanner);
}
<cmt1>{DIGITS} {
yylineno = imcc->line = atoi(yytext);
yy_pop_state(yyscanner);
yy_push_state(cmt4, yyscanner);
return LINECOMMENT;
}
<cmt4>.*{EOL} {
yy_pop_state(yyscanner);
}
<INITIAL,emit>{EOL} {
if (imcc->expect_pasm == 2)
BEGIN(INITIAL);
imcc->expect_pasm = 0;
return '\n';
}
<INITIAL,emit># {
yy_push_state(cmt5, yyscanner);
}
<cmt5>.*{EOL} {
if (imcc->expect_pasm == 2)
BEGIN(INITIAL);
else
yy_pop_state(yyscanner);
imcc->expect_pasm = 0;
return '\n';
}
<INITIAL,emit,macro>^"=cut"{EOL} {
/* this is a stand-alone =cut, but we're not in POD mode, so ignore. */
SET_LINE_NUMBER;
}
<INITIAL,emit,macro>^"=".*{EOL} {
SET_LINE_NUMBER;
imcc->in_pod = 1;
yy_push_state(pod, yyscanner);
}
<pod>^"=cut"{EOL} {
SET_LINE_NUMBER;
imcc->in_pod = 0;
yy_pop_state(yyscanner);
}
<pod>.* { SET_LINE_NUMBER; }
<pod>{EOL} { /* ignore */ }
<INITIAL,emit>".annotate" return ANNOTATE;
<INITIAL,emit>".lex" return LEXICAL;
".set_arg" return ARG;
".sub" { SET_LINE_NUMBER; return SUB; }
".end" return ESUB;
".begin_call" return PCC_BEGIN;
".end_call" return PCC_END;
".call" return PCC_CALL;
".invocant" return INVOCANT;
<emit,INITIAL>".pcc_sub" return PCC_SUB;
".begin_return" return PCC_BEGIN_RETURN;
".end_return" return PCC_END_RETURN;
".begin_yield" return PCC_BEGIN_YIELD;
".end_yield" return PCC_END_YIELD;
<emit,INITIAL>":method" return METHOD;
<emit,INITIAL>":multi" return MULTI;
<emit,INITIAL>":main" return MAIN;
<emit,INITIAL>":load" return LOAD;
<emit,INITIAL>":init" return INIT;
<emit,INITIAL>":immediate" return IMMEDIATE;
<emit,INITIAL>":postcomp" return POSTCOMP;
<emit,INITIAL>":tag" return SUBTAG;
<emit,INITIAL>":anon" return ANON;
<emit,INITIAL>":outer" return OUTER;
<emit,INITIAL>":lex" return NEED_LEX;
<emit,INITIAL>":vtable" return VTABLE_METHOD;
<emit,INITIAL>":nsentry" return NS_ENTRY;
":instanceof" return SUB_INSTANCE_OF;
":subid" return SUBID;
".get_result" return RESULT;
".get_results" return GET_RESULTS;
".yield" return YIELDT;
".set_yield" return SET_YIELD;
".return" return RETURN;
".set_return" return SET_RETURN;
".tailcall" return TAILCALL;
<emit,INITIAL>".loadlib" return LOADLIB;
":flat" return ADV_FLAT;
":slurpy" return ADV_SLURPY;
":optional" return ADV_OPTIONAL;
":opt_flag" return ADV_OPT_FLAG;
":named" return ADV_NAMED;
"=>" return ADV_ARROW;
":invocant" return ADV_INVOCANT;
":call_sig" return ADV_CALL_SIG;
<emit,INITIAL>".namespace" return NAMESPACE;
<emit,INITIAL>".HLL" return HLL;
".local" return LOCAL;
<emit,INITIAL>".const" return CONST;
".globalconst" return GLOBAL_CONST;
".param" return PARAM;
"goto" return GOTO;
"if" return IF;
"unless" return UNLESS;
"null" return PNULL;
"int" return INTV;
"num" return FLOATV;
"pmc" return PMCV;
"string" return STRINGV;
"<<" return SHIFT_LEFT;
">>" return SHIFT_RIGHT;
">>>" return SHIFT_RIGHT_U;
"&&" return LOG_AND;
"||" return LOG_OR;
"~~" return LOG_XOR;
"<" return RELOP_LT;
"<=" return RELOP_LTE;
">" return RELOP_GT;
">=" return RELOP_GTE;
"==" return RELOP_EQ;
"!=" return RELOP_NE;
"**" return POW;
{WS}+"."{WS}+ return CONCAT;
"." return DOT;
"+=" return PLUS_ASSIGN;
"-=" return MINUS_ASSIGN;
"*=" return MUL_ASSIGN;
"/=" return DIV_ASSIGN;
"%=" return MOD_ASSIGN;
"//" return FDIV;
"//=" return FDIV_ASSIGN;
"&=" return BAND_ASSIGN;
"|=" return BOR_ASSIGN;
"~=" return BXOR_ASSIGN;
">>=" return SHR_ASSIGN;
"<<=" return SHL_ASSIGN;
">>>=" return SHR_U_ASSIGN;
".=" return CONCAT_ASSIGN;
<emit,INITIAL>".macro_const" {
char *macro_name = NULL;
int start_cond = YY_START;
int macro_exists = 0;
int c;
int start_line;
BEGIN(macro);
c = yylex_skip(valp, imcc, " ", yyscanner);
if (c != IDENTIFIER)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"Constant names must be identifiers");
imcc->cur_macro_name = macro_name = valp->s;
start_line = imcc->line;
c = yylex_skip(valp, imcc, " ", yyscanner);
if (c != INTC && c != FLOATC && c != STRINGC && c != REG)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"Constant '%s' value must be a number, "
"stringliteral or register", macro_name);
/* macro_name becomes a hash key
* the first one needs to remain; destroying the hash frees it
* subsequent macro_names need destruction here to avoid leaks */
if (find_macro(imcc, macro_name))
macro_exists = 1;
define_macro(imcc, macro_name, NULL, valp->s, start_line);
mem_sys_free(valp->s);
/* don't leak these */
if (macro_exists)
mem_sys_free(macro_name);
imcc->cur_macro_name = NULL;
BEGIN(start_cond);
return MACRO;
}
<emit,INITIAL>".macro" {
/* the initial whitespace catcher misses this one */
SET_LINE_NUMBER;
return read_macro(valp, imcc, yyscanner);
}
<emit,INITIAL>".include" {
const int c = yylex(valp, yyscanner, imcc);
STRING *filename;
if (c != STRINGC)
return c;
/* STRINGCs have a mem_sys_strdup()ed valp->s */
mem_sys_free(valp->s);
YYCHOP();
filename = Parrot_str_new(imcc->interp, yytext + 1, 0);
include_file(imcc, filename, yyscanner);
}
<emit,INITIAL>{ID}"$:" {
if (valp) {
char *label;
size_t len;
YYCHOP();
YYCHOP();
if (!imcc->frames || !imcc->frames->label)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR, "missing space?");
len = yyleng + 10;
label = (char *)mem_sys_allocate(len);
snprintf(label, len, "%s%d", yytext, imcc->frames->label);
/* XXX: free valp->s if it exists? */
valp->s = label;
}
return LABEL;
}
<emit,INITIAL>{ID}"$" {
if (valp) {
char *label;
size_t len;
YYCHOP();
if (!imcc->frames || !imcc->frames->label)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR, "missing space?");
len = yyleng + 10;
label = (char *)mem_sys_allocate(len);
snprintf(label, len, "%s%d", yytext, imcc->frames->label);
/* XXX: free valp->s if it exists? */
valp->s = label;
}
return IDENTIFIER;
}
<emit,INITIAL>"," return COMMA;
<emit,INITIAL>{ID}":" {
/* trim last ':' */
YYCHOP();
if (valp)
valp->s = mem_sys_strndup(yytext, yyleng);
return LABEL;
}
<emit,INITIAL>{DOT}{LETTER}{LETTERDIGIT}* {
char * const macro_name = mem_sys_strndup(yytext + 1, yyleng - 1);
int failed = expand_macro(imcc, macro_name, yyscanner);
mem_sys_free(macro_name);
if (!failed) {
yyless(1);
return DOT;
}
}
<*>{FLOATNUM} DUP_AND_RET(valp, FLOATC);
<*>{SIGN}?{DIGIT}+ DUP_AND_RET(valp, INTC);
<*>{HEX} DUP_AND_RET(valp, INTC);
<*>{BIN} DUP_AND_RET(valp, INTC);
<*>{OCT} DUP_AND_RET(valp, INTC);
<*>{STRINGCONSTANT} {
valp->s = mem_sys_strndup(yytext, yyleng);
return STRINGC;
}
<*>"<<"{STRINGCONSTANT} {
macro_frame_t *frame;
/* Save the string we want to mark the end of the heredoc and snip
off newline and quote. */
if (imcc->frames->heredoc_rest)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR, "nested heredoc not supported");
imcc->heredoc_end = mem_sys_strndup(yytext + 3, yyleng - 3);
imcc->heredoc_end[strlen(imcc->heredoc_end) - 1] = 0;
if (!strlen(imcc->heredoc_end))
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR, "empty heredoc delimiter");
frame = new_frame(imcc);
frame->s.next = (parser_state_t *)imcc->frames;
imcc->frames = frame;
/* Start slurping up the heredoc. */
imcc->heredoc_content = (char *)mem_sys_allocate(2);
/* preserve delim */
imcc->heredoc_content[0] = yytext[2];
/* eos */
imcc->heredoc_content[1] = 0;
yy_push_state(heredoc1, yyscanner);
}
<*>{UNICODE} {
/* charset:"..." */
valp->s = mem_sys_strndup(yytext, yyleng);
/* this is actually not unicode but a string with a charset */
return USTRINGC;
}
<emit,INITIAL>\$I[0-9]+ {
if (valp) (valp)->s = yytext;
if (imcc->state->pasm_file)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"'%s' is not a valid register name in pasm mode", yytext);
return IREG;
}
<emit,INITIAL>\$N[0-9]+ {
if (valp)
(valp)->s = yytext;
if (imcc->state->pasm_file)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"'%s' is not a valid register name in pasm mode", yytext);
return NREG;
}
<emit,INITIAL>\$S[0-9]+ {
if (valp)
(valp)->s = yytext;
if (imcc->state->pasm_file)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"'%s' is not a valid register name in pasm mode", yytext);
return SREG;
}
<emit,INITIAL>\$P[0-9]+ {
if (valp)
(valp)->s = yytext;
if (imcc->state->pasm_file)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"'%s' is not a valid register name in pasm mode", yytext);
return PREG;
}
<emit,INITIAL>\$[a-zA-Z0-9]+ {
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"'%s' is not a valid register name", yytext);
}
<emit,INITIAL>[ISNP]{DIGIT}{DIGIT}? {
if (imcc->state->pasm_file == 0)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"'%s' is only a valid register name in PASM mode", yytext);
if (valp)
valp->s = mem_sys_strndup(yytext, yyleng);
return REG;
}
<emit,INITIAL>{ID} { return handle_identifier(imcc, valp, yytext); }
<emit,INITIAL>{WS}+ /* skip */;
<emit,cmt1,cmt2,cmt3,cmt4,cmt5,INITIAL>. {
/* catch all except for state macro */
return yytext[0];
}
<emit><<EOF>> {
BEGIN(INITIAL);
if (imcc->frames->s.pasm_file) {
imcc->frames->s.pasm_file = 2;
return EOM;
}
return 0;
}
<INITIAL><<EOF>> yyterminate();
<macro>".endm" {
/* the initial whitespace catcher misses this one */
SET_LINE_NUMBER;
DUP_AND_RET(valp, ENDM);
}
<macro>{WS}*{EOL} {
DUP_AND_RET(valp, '\n');
}
<macro>"$"{ID}":" return LABEL;
<macro>".label"{WS}+ {
if (yylex(valp, yyscanner, imcc) != LABEL)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR, "LABEL expected");
if (valp) {
char *label;
size_t len;
YYCHOP();
len = strlen(imcc->cur_macro_name) + yyleng + 15;
label = (char *)mem_sys_allocate(len);
snprintf(label, len, "local__%s__%s__$:",
imcc->cur_macro_name, yytext+1);
if (valp->s)
mem_sys_free(valp->s);
valp->s = label;
}
return LABEL;
}
<macro>".$"{ID} {
if (valp) {
if (!imcc->cur_macro_name) {
if (valp->s)
mem_sys_free(valp->s);
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"Invalid LABEL outside of macro");
}
else {
const char * const fmt = "local__%s__%s__$";
const size_t fmtlen = strlen(fmt) - (2 * strlen("%s"));
const size_t len = strlen(imcc->cur_macro_name)
+ yyleng + fmtlen;
char * const label = (char *)mem_sys_allocate(len);
/* skip over ".$" prefix with the +2 */
snprintf(label, len, fmt,
imcc->cur_macro_name, yytext + 2);
if (valp->s)
mem_sys_free(valp->s);
valp->s = label;
}
}
return IDENTIFIER;
}
<macro>{WS}+ DUP_AND_RET(valp, ' ');
<macro>[SNIP]{DIGITS} DUP_AND_RET(valp, REG);
<macro>"$"[SNIP]{DIGITS} DUP_AND_RET(valp, REG);
<macro>{ID} DUP_AND_RET(valp, IDENTIFIER);
<macro>{DOT}{ID} DUP_AND_RET(valp, MACRO);
<macro>. DUP_AND_RET(valp, yytext[0]);
<macro><<EOF>> yyterminate();
%%
#ifdef yywrap
# undef yywrap
#endif
int yywrap(void* yyscanner) {
/* Add code here to open next source file and start scanning
* yywrap returns 0 if scanning is to continue */
imc_info_t * imcc = yyget_extra(yyscanner);
yyguts_t * const yyg = (yyguts_t *)yyscanner;
if (!imcc->interp) {
fprintf(stderr, "Argh, interp not found\n");
exit(1);
}
yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner);
/* pop old frame */
if (imcc->frames->s.next) {
pop_parser_state(imcc, yyscanner);
if (YYSTATE == INITIAL || YYSTATE == emit)
BEGIN(imcc->frames->s.pasm_file ? emit : INITIAL);
return 0;
}
return 1;
}
static macro_frame_t *
new_frame(ARGMOD(imc_info_t *imcc)) {
macro_frame_t * const tmp = mem_gc_allocate_zeroed_typed(imcc->interp, macro_frame_t);
tmp->label = imcc->unique_count;
imcc->unique_count++;
tmp->s.line = imcc->line;
tmp->s.handle = PIO_INVALID_HANDLE;
if (imcc->frames) {
tmp->s.pasm_file = imcc->frames->s.pasm_file;
if (imcc->frames->s.file)
tmp->s.file = imcc->frames->s.file;
}
tmp->s.interp = imcc->interp;
return tmp;
}
static void
scan_string(macro_frame_t *frame, ARGIN(const char *expansion), void *yyscanner)
{
yyguts_t * const yyg = (yyguts_t *)yyscanner;
imc_info_t * imcc = yyget_extra(yyscanner);
frame->buffer = YY_CURRENT_BUFFER;
frame->s.next = (parser_state_t *)imcc->frames;
imcc->frames = frame;
/* start at the effective *starting line* of the macro */
imcc->line = frame->s.line - 2;
yy_scan_string(expansion, yyscanner);
}
static int
destroy_frame(struct macro_frame_t *frame, void *yyscanner)
{
YY_BUFFER_STATE buffer = frame->buffer;
int ret = 0;
int i;
for (i = 0; i < frame->expansion.num_param; i++) {
mem_sys_free(frame->expansion.name[i]);
frame->expansion.name[i] = NULL;
}
if (frame->heredoc_rest) {
mem_sys_free(frame->heredoc_rest);
frame->heredoc_rest = NULL;
}
else {
ret = frame->s.line;
}
mem_sys_free(frame);
if (buffer != NULL)
yy_switch_to_buffer(buffer, yyscanner);
return ret;
}
static int
yylex_skip(YYSTYPE *valp, ARGMOD(imc_info_t *imcc), const char *skip, void *yyscanner)
{
int c;
const char *p;
yyguts_t * const yyg = (yyguts_t *)yyscanner;
do {
c = yylex(valp, yyscanner, imcc);
p = skip;
while (*p && c != *p)
p++;
/* leave loop early if it gets found */
if (*p == '\0')
break;
/* free any mem_sys_strdup()ed strings */
if (yytext)
mem_sys_free(valp->s);
} while (*p != '\0');
if (c)
DUP_AND_RET_FREE(valp, c);
return c;
}
static char*
read_braced(YYSTYPE *valp, ARGMOD(imc_info_t *imcc), const char *macro_name,
char *current, void *yyscanner)
{
YYSTYPE val;
size_t len = strlen(current);
int c = yylex(&val, yyscanner, imcc);
int count = 0;
while (c != '}' || count > 0) {
if (c == '}')
count--;
else if (c == '{')
count++;
if (c <= 0)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"End of file reached while reading arguments in '%s'",
macro_name);
len += strlen(val.s);
current = (char *)mem_sys_realloc(current, len + 1);
strcat(current,val.s);
mem_sys_free(val.s);
val.s = NULL;
c = yylex(&val, yyscanner, imcc);
}
if (valp) {
if (valp->s)
mem_sys_free(valp->s);
*valp = val;
}
else
mem_sys_free(val.s);
return current;
}
static int
read_params(YYSTYPE *valp, ARGMOD(imc_info_t *imcc), params_t *params,
ARGIN(const char *macro_name), int need_id, void *yyscanner)
{
YYSTYPE val;
size_t len = 0;
char *current = mem_sys_strndup("", 0);
yyguts_t *yyg = (yyguts_t *)yyscanner;
int c = yylex_skip(&val, imcc, " \n", yyscanner);
params->num_param = 0;
while (c != ')') {
if (YYSTATE == heredoc2)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"Heredoc in macro '%s' not allowed", macro_name);
if (c <= 0)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"End of file reached while reading arguments in '%s'",
macro_name);
else if (c == ',') {
if (params->num_param == MAX_PARAM)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"More than %d params in '%s'",
MAX_PARAM, macro_name);
params->name[params->num_param++] = current;
current = mem_sys_strndup("", 0);
len = 0;
if (val.s)
mem_sys_free(val.s);
c = yylex_skip(&val, imcc, " \n", yyscanner);
}
else if (need_id && (*current || c != IDENTIFIER) && c != ' ') {
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"Parameter definition in '%s' must be IDENTIFIER",
macro_name);
}
else if (c == '{') {
current = read_braced(&val, imcc, macro_name, current, yyscanner);
mem_sys_free(val.s);
c = yylex_skip(&val, imcc, " \n", yyscanner);
len = strlen(current);
}
else {
if (!need_id || c != ' ') {
len += strlen(val.s);
current = (char *)mem_sys_realloc(current, len + 1);
strcat(current, val.s);
}
mem_sys_free(val.s);
val.s = NULL;
c = yylex(&val, yyscanner, imcc);
}
}
params->name[params->num_param++] = current;
if (valp)
*valp = val;
else
mem_sys_free(val.s);
return c;
}
static int
read_macro(YYSTYPE *valp, ARGMOD(imc_info_t *imcc), void *yyscanner)
{
int c, start_line;
params_t params;
yyguts_t * const yyg = (yyguts_t *)yyscanner;
int start_cond = YY_START;
size_t buffer_size = 0;
size_t buffer_used = 0;
BEGIN(macro);
c = yylex_skip(valp, imcc, " ", yyscanner);
if (c != IDENTIFIER)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR, "Macro names must be identifiers");
imcc->cur_macro_name = valp->s;
start_line = imcc->line;
memset(&params, 0, sizeof (params_t));
/* white space is allowed between macro and opening paren) */
c = yylex_skip(valp, imcc, " ", yyscanner);
if (c == '(') {
mem_sys_free(valp->s);
valp->s = NULL;
c = read_params(NULL, imcc, &params,
imcc->cur_macro_name, 1, yyscanner);
c = yylex(valp, yyscanner, imcc);
}
while (c != ENDM) {
int elem_len;
if (c <= 0) {
mem_sys_free(valp->s);
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"File ended before macro '%s' was complete",
imcc->cur_macro_name);
}
if (valp->s) {
elem_len = strlen(valp->s);
if (buffer_used) {
if (buffer_used + elem_len > buffer_size) {
buffer_size += elem_len;
buffer_size <<= 1;
imcc->macro_buffer =
(char *)mem_sys_realloc(imcc->macro_buffer,
buffer_size);
}
}
else {
buffer_size = (elem_len << 1) > 1024 ? elem_len << 1 : 1024;
imcc->macro_buffer =
(char *)mem_sys_allocate_zeroed(buffer_size);
}
strcat(imcc->macro_buffer, valp->s);
buffer_used += elem_len;
mem_sys_free(valp->s);
valp->s = NULL;
}
c = yylex(valp, yyscanner, imcc);
}
mem_sys_free(valp->s);
valp->s = NULL;
BEGIN(start_cond);
define_macro(imcc, imcc->cur_macro_name,
&params, imcc->macro_buffer, start_line);
mem_sys_free(imcc->macro_buffer);
imcc->macro_buffer = NULL;
imcc->cur_macro_name = NULL;
return MACRO;
}
static char *
find_macro_param(ARGMOD(imc_info_t *imcc), const char *name)
{
macro_frame_t *f;
for (f = imcc->frames; f; f = (macro_frame_t *)f->s.next) {
if (f->params) {
int i;
for (i = 0; i < f->params->num_param; i++) {
if (STREQ(f->params->name[i], name))
return f->expansion.name[i];
}
}
}
return NULL;
}
static void
define_macro(ARGMOD(imc_info_t *imcc), ARGIN(const char *name),
ARGIN(const params_t *params), ARGIN(const char *expansion), int start_line)
{
DECL_CONST_CAST;
macro_t *m = find_macro(imcc, name);
if (m) {
mem_sys_free(m->expansion);
m->expansion = NULL;
}
else {
m = mem_gc_allocate_zeroed_typed(imcc->interp, macro_t);
if (!imcc->macros)
imcc->macros = Parrot_hash_new_cstring_hash(imcc->interp);
Parrot_hash_put(imcc->interp, imcc->macros,
PARROT_const_cast(char *, name), m);
}
if (params)
m->params = *params;
else
memset(&m->params, 0, sizeof (params_t));
m->expansion = mem_sys_strdup(expansion);
m->line = start_line;
}
static macro_t *
find_macro(ARGMOD(imc_info_t *imcc), const char *name)
{
if (!imcc->macros)
return NULL;
return (macro_t *)Parrot_hash_get(imcc->interp, imcc->macros, name);
}
static int
expand_macro(ARGMOD(imc_info_t *imcc), ARGIN(const char *name), void *yyscanner)
{
yyguts_t * const yyg = (yyguts_t *)yyscanner;
const char * const expansion = find_macro_param(imcc, name);
macro_t *m;
if (expansion) {
macro_frame_t * const frame = new_frame(imcc);
/* When an error occurs, then report it as being in a macro */
frame->is_macro = 1;
scan_string(frame, expansion, yyscanner);
return 1;
}
m = find_macro(imcc, name);
if (m) {
int i, c, start_cond;
macro_frame_t * frame = new_frame(imcc);
frame->params = &m->params;
/* When an error occurs, then report it as being in a macro */
frame->is_macro = 1;
frame->s.file = Parrot_str_new(imcc->interp, name, 0);
/* whitespace can be safely ignored */
do {
#ifdef __cplusplus
c = yyinput(yyscanner);
#else
c = input(yyscanner);
#endif
} while (c == ' ' || c == '\t');
if (c != '(') {
if (m->params.num_param != 0)
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"Macro '%s' needs %d arguments",
name, m->params.num_param);
unput(c);
scan_string(frame, m->expansion, yyscanner);
return 1;
}
start_cond = YY_START;
BEGIN(macro);
read_params(NULL, imcc, &frame->expansion, name, 0, yyscanner);
BEGIN(start_cond);
if (frame->expansion.num_param == 0 && m->params.num_param == 1) {
frame->expansion.name[0] = mem_sys_strndup("", 0);
frame->expansion.num_param = 1;
}
if (frame->expansion.num_param != m->params.num_param) {
IMCC_fataly(imcc, EXCEPTION_SYNTAX_ERROR,
"Macro '%s' requires %d arguments, but %d given",
name, m->params.num_param, frame->expansion.num_param);
}
/* expand arguments */
for (i = 0; i < frame->expansion.num_param; i++) {
char * const current = frame->expansion.name[i];
/* parameter of outer macro */
if (current[0] == '.') {
const char * const s = find_macro_param(imcc, current + 1);
if (s) {
frame->expansion.name[i] = mem_sys_strdup(s);
mem_sys_free(current);
}
}
else {
const size_t len = strlen(current);
if (len && (current[len - 1] == '$')) { /* local label */
const size_t slen = len + 10;
char * const s = (char *)mem_sys_allocate(slen);
current[len - 1] = '\0';
snprintf(s, slen, "%s%d", current, imcc->frames->label);
frame->expansion.name[i] = s;
mem_sys_free(current);
}
}
}
scan_string(frame, m->expansion, yyscanner);
return 1;
}
return 0;
}
static void
include_file(ARGMOD(imc_info_t *imcc), ARGIN(STRING *file_name), void *yyscanner)
{
yyguts_t * const yyg = (yyguts_t *)yyscanner;
macro_frame_t * const frame = new_frame(imcc);
STRING *s = Parrot_locate_runtime_file_str(imcc->interp,
file_name, PARROT_RUNTIME_FT_INCLUDE);
PIOHANDLE file;
if (STRING_IS_NULL(s)
|| (file = Parrot_io_internal_open(imcc->interp, s, PIO_F_READ)) == PIO_INVALID_HANDLE) {
IMCC_fataly(imcc, EXCEPTION_EXTERNAL_ERROR,
"No such file or directory '%Ss'", file_name);
}
frame->s.file = file_name;
frame->s.handle = file;
/* TODO: We do checks like this elsewhere. Create a utility function to
check file type */
if (imcc_string_ends_with(imcc, file_name, ".pasm")) {
frame->s.pasm_file = 1;
BEGIN(emit);
}
else if (imcc_string_ends_with(imcc, file_name, ".pir")) {
frame->s.pasm_file = 0;
BEGIN(INITIAL);
}
scan_file(imcc, frame, file, yyscanner);
}
static void
scan_file(ARGMOD(imc_info_t *imcc), macro_frame_t *frame, PIOHANDLE file,
void *yyscanner)
{
yyguts_t * const yyg = (yyguts_t *)yyscanner;
const int oldline = imcc->line;
frame->buffer = YY_CURRENT_BUFFER;
frame->s.next = (parser_state_t *)imcc->frames;
imcc->frames = frame;
imcc->state = (parser_state_t *)imcc->frames;
/* let the start of line rule increment this to 1 */
imcc->line = 0;
yy_switch_to_buffer(yy_create_buffer((FILE *)file, YY_BUF_SIZE, yyscanner),
yyscanner);
imcc->line = oldline;
}
void
IMCC_push_parser_state(ARGMOD(imc_info_t *imcc), STRING *filename,
int is_file, int is_pasm)
{
macro_frame_t * const frame = new_frame(imcc);
frame->s.next = (parser_state_t *)imcc->frames;
imcc->frames = frame;
frame->s.line = imcc->line = 1;
imcc->state = (parser_state_t *)imcc->frames;
if (is_file)
imcc->state->file = filename;
else
imcc->state->file = Parrot_str_new_constant(imcc->interp, "(file unknown)");
imcc->state->pasm_file = is_pasm;
}
static void
pop_parser_state(ARGMOD(imc_info_t *imcc), void *yyscanner)
{
macro_frame_t * const tmp = imcc->frames;
if (tmp) {
int l;
if (tmp->s.handle != PIO_INVALID_HANDLE)
Parrot_io_internal_close(imcc->interp, tmp->s.handle);
imcc->frames =
(macro_frame_t *)imcc->frames->s.next;
l = destroy_frame(tmp, yyscanner);
if (l)
imcc->line = l;
}
imcc->state = (parser_state_t *)imcc->frames;
}
void
IMCC_pop_parser_state(ARGMOD(imc_info_t *imcc), void *yyscanner)
{
pop_parser_state(imcc, yyscanner);
}
PIOHANDLE
determine_input_file_type(ARGMOD(imc_info_t * imcc), ARGIN(STRING *sourcefile))
{
PIOHANDLE handle;
if (!STRING_length(sourcefile))
IMCC_fatal_standalone(imcc, 1, "main: No source file specified.\n");
if (STRING_length(sourcefile) == 1
&& STRING_ord(imcc->interp, sourcefile, 0) == '-') {
handle = Parrot_io_internal_std_os_handle(imcc->interp, PIO_STDIN_FILENO);
if ((FILE *)handle == NULL) {
/*
* We have to dup the handle because the stdin fd is 0 on UNIX and
* lex would think it's a NULL FILE pointer and reset it to the
* stdin FILE pointer.
*/
handle = Parrot_io_internal_dup(imcc->interp, handle);
}
}
else {
if (Parrot_file_stat_intval(imcc->interp, sourcefile, STAT_ISDIR))
Parrot_ex_throw_from_c_args(imcc->interp, NULL, EXCEPTION_EXTERNAL_ERROR,
"imcc_compile_file: '%Ss' is a directory", sourcefile);
handle = Parrot_io_internal_open(imcc->interp, sourcefile, PIO_F_READ);
if (handle == PIO_INVALID_HANDLE)
IMCC_fatal_standalone(imcc, EXCEPTION_EXTERNAL_ERROR,
"Error reading source file %Ss.\n",
sourcefile);
if (imcc_string_ends_with(imcc, sourcefile, ".pasm"))
SET_STATE_PASM_FILE(imcc);
}
if (imcc->verbose) {
IMCC_info(imcc, 1, "debug = 0x%x, optim = 0x%x\n", imcc->debug,
imcc->optimizer_level);
IMCC_info(imcc, 1, "Reading %Ss\n", sourcefile);
}
return handle;
}
static PIOHANDLE
imcc_setup_input(ARGMOD(imc_info_t * imcc), yyscan_t yyscanner,
ARGIN(STRING *source), ARGIN(const char *source_c), int is_file)
{
if (is_file) {
PIOHANDLE file = determine_input_file_type(imcc, source);
imc_yyin_set(file, yyscanner);
yy_switch_to_buffer(
yy_create_buffer((FILE *)file, YY_BUF_SIZE, yyscanner),
yyscanner);
return file;
}
else {
yy_scan_string(source_c, yyscanner);
return PIO_INVALID_HANDLE;
}
}
static void
imcc_cleanup_input(ARGMOD(imc_info_t * imcc), PIOHANDLE file,
ARGIN(char *source_c), int is_file)
{
if (is_file)
Parrot_io_internal_close(imcc->interp, file);
Parrot_str_free_cstring(source_c);
}
INTVAL
imcc_compile_buffer_safe(ARGMOD(imc_info_t *imcc), yyscan_t yyscanner,
ARGIN(STRING *source), int is_file, SHIM(int is_pasm))
{
yyguts_t * const yyg = (yyguts_t *)yyscanner;
YY_BUFFER_STATE volatile buffer;
char * source_c = Parrot_str_to_cstring(imcc->interp, source);
PIOHANDLE file;
INTVAL success = 0;
imcc->frames->s.next = NULL;
buffer = YY_CURRENT_BUFFER;
file = imcc_setup_input(imcc, yyscanner, source, source_c, is_file);
emit_open(imcc);
success = imcc_run_compilation(imcc, yyscanner);
imcc_cleanup_input(imcc, file, source_c, is_file);
if (buffer)
yy_switch_to_buffer(buffer, yyscanner);
return success;
}
#if 0
static void
do_a_better_error_message(imc_info_t * imcc, SHIM(void * yyscanner))
{
STRING * loc;
imcc->error_code = IMCC_PARSEFAIL_EXCEPTION;
if (imcc->frames && imcc->frames->is_macro)
loc = Parrot_sprintf_c(imcc->interp, "in macro '.%Ss' line %d",
imcc->frames->s.file, imcc->line);
else
loc = Parrot_sprintf_c(imcc->interp, "in file '%Ss' line %d",
imcc->frames->s.file, imcc->line);
imcc->error_message = Parrot_sprintf_c(imcc->interp,
"Unexpected parser exit. Unknown syntax error.\n"
"\tLast line reported is %d\n"
"\tLast file reported is %S", imcc->line, loc);
}
#endif
INTVAL
imcc_run_compilation(ARGMOD(imc_info_t *imcc), void *yyscanner) {
/* TODO: Kill this stuff and use Parrot exceptions exclusively */
IMCC_TRY(imcc->jump_buf, imcc->error_code) {
if (yyparse(yyscanner, imcc)) {
imcc->error_code = IMCC_PARSEFAIL_EXCEPTION;
return 0;
}
imc_compile_all_units(imcc);
return 1;
}
IMCC_CATCH(IMCC_FATAL_EXCEPTION) {
imcc->error_code = IMCC_FATAL_EXCEPTION;
}
IMCC_CATCH(IMCC_FATALY_EXCEPTION) {
imcc->error_code = IMCC_FATALY_EXCEPTION;
}
IMCC_END_TRY;
return 0;
}
void
IMCC_print_inc(ARGMOD(imc_info_t *imcc))
{
macro_frame_t *f;
STRING *old = imcc->frames->s.file;
if (imcc->frames && imcc->frames->is_macro)
IMCC_warning(imcc, "\n\tin macro '.%Ss' line %d\n",
imcc->frames->s.file, imcc->line);
else
IMCC_warning(imcc, "\n\tin file '%Ss' line %d\n",
imcc->frames->s.file, imcc->line);
for (f = imcc->frames; f; f = (macro_frame_t *)f->s.next) {
if (!STRING_equal(imcc->interp, f->s.file, old)) {
IMCC_warning(imcc, "\tincluded from '%Ss' line %d\n",
f->s.file, f->s.line);
}
old = f->s.file;
}
}
/*
void
set_filename(ARGMOD(imc_info_t *imcc), char * const filename)
Function to set the C<filename> as specified using the C<.line> directive.
The parser needs to call back into the lexer (this file), because the
parser does not have access to the lexer's private bits.
*/
void
set_filename(ARGMOD(imc_info_t *imcc), char * const filename)
{
STRING *str = Parrot_str_new(imcc->interp, filename, 0);
imcc->frames->s.file = str;
/* in case .line is used outside a .sub, then this
* can't be done; hence the check.
* The mem_sys_strdup() is done, as the original #line implementation
* duplicated the string twice as well; one for the
* frames->s.file and one for cur_unit->file.
* During the parse, the STRINGC is already mem_sys_strdup()ed once.
*/
if (imcc->cur_unit)
imcc->cur_unit->file = str;
}
/* Functions to set and get yyin, as we can't decorate it for export
(since it is defined in a file generated by yacc/bison). */
void imc_yyin_set(PIOHANDLE new_yyin, void *yyscanner)
{
yyguts_t * const yyg = (yyguts_t *)yyscanner;
yyg->yyin_r = (FILE *)new_yyin;
}
PIOHANDLE imc_yyin_get(void *yyscanner)
{
const yyguts_t * const yyg = (yyguts_t *)yyscanner;
return (PIOHANDLE)yyg->yyin_r;
}
/* return true if scanner is at EOF */
int at_eof(yyscan_t yyscanner)
{
yyguts_t * const yyg = (yyguts_t *)yyscanner;
return yyg->yy_hold_char == '\0';
}
static int
handle_identifier(ARGMOD(imc_info_t *imcc), YYSTYPE *valp, const char *text)
{
if (!imcc->is_def) {
SymReg *r = find_sym(imcc, text);
if (r && (r->type & (VTIDENTIFIER|VT_CONSTP))) {
valp->sr = r;
return VAR;
}
if (imcc->cur_unit
&& imcc->cur_unit->instructions
&& (r = imcc->cur_unit->instructions->symregs[0])
&& r->pcc_sub)
{
if (((r->pcc_sub->pragma & P_METHOD)
|| (imcc->cur_unit->is_vtable_method))
&& !strcmp(text, "self")) {
valp->sr = mk_ident(imcc, "self", 'P', VTIDENTIFIER);
imcc->cur_unit->type |= IMC_HAS_SELF;
return VAR;
}
}
}
valp->s = mem_sys_strdup(text);
return (!imcc->is_def && is_op(imcc, valp->s) ? PARROT_OP : IDENTIFIER);
}
/*
* Local variables:
* mode: c
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/
Jump to Line
Something went wrong with that request. Please try again.