| 1 |
/* |
| 2 |
* Buggy Language (BL) GCC toy Frontend. |
| 3 |
* |
| 4 |
* Copyright (C) 2007 - WAKATSUKI toshihiro <alohakun _AT_ gmail.com> |
| 5 |
* |
| 6 |
* This program is free software; you can redistribute it and/or modify |
| 7 |
* it under the terms of the GNU General Public License as published by |
| 8 |
* the Free Software Foundation; either version 2 of the License, or |
| 9 |
* (at your option) any later version. |
| 10 |
* |
| 11 |
* This program is distributed in the hope that it will be useful, |
| 12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 |
* GNU General Public License for more details. |
| 15 |
* |
| 16 |
* You should have received a copy of the GNU General Public License |
| 17 |
* along with this program; if not, write to the Free Software |
| 18 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 |
*/ |
| 20 |
|
| 21 |
/* Some code and ideas were taken from a hello-world gcc frontend |
| 22 |
* http://svn.gna.org/viewcvs/gsc/branches/hello-world/ |
| 23 |
* and gcc/treelang sample frontend. |
| 24 |
* */ |
| 25 |
|
| 26 |
#include "config.h" |
| 27 |
#include "system.h" |
| 28 |
#include "coretypes.h" |
| 29 |
#include "tm.h" |
| 30 |
#include "toplev.h" |
| 31 |
#include "ggc.h" |
| 32 |
#include "cgraph.h" |
| 33 |
#include "tree-gimple.h" |
| 34 |
#include "langhooks-def.h" |
| 35 |
#include "langhooks.h" |
| 36 |
|
| 37 |
static GTY(()) tree signed_and_unsigned_types[MAX_BITS_PER_WORD + 1][2]; |
| 38 |
|
| 39 |
static tree bl_type_for_size(unsigned precision, int unsignedp) { |
| 40 |
tree t; |
| 41 |
if(precision <= MAX_BITS_PER_WORD |
| 42 |
&& signed_and_unsigned_types[precision][unsignedp] != 0) |
| 43 |
return signed_and_unsigned_types[precision][unsignedp]; |
| 44 |
if(unsignedp) |
| 45 |
t = signed_and_unsigned_types[precision][1] = make_unsigned_type(precision); |
| 46 |
else |
| 47 |
t = signed_and_unsigned_types[precision][0] = make_signed_type(precision); |
| 48 |
return t; |
| 49 |
} |
| 50 |
|
| 51 |
static tree bl_type_for_mode(enum machine_mode mode, int unsignedp) { |
| 52 |
if(SCALAR_INT_MODE_P(mode)) |
| 53 |
return bl_type_for_size(GET_MODE_BITSIZE(mode), unsignedp); |
| 54 |
else |
| 55 |
return NULL_TREE; |
| 56 |
} |
| 57 |
|
| 58 |
struct binding_level { |
| 59 |
tree names; |
| 60 |
tree blocks; |
| 61 |
tree stmts; |
| 62 |
struct binding_level *level_chain; |
| 63 |
}; |
| 64 |
|
| 65 |
static struct binding_level *current_binding_level = NULL; |
| 66 |
static struct binding_level *global_binding_level = NULL; |
| 67 |
static struct binding_level clear_binding_level = {NULL, NULL, NULL, NULL }; |
| 68 |
|
| 69 |
static tree* getstmtlist(void) { |
| 70 |
return ¤t_binding_level->stmts; |
| 71 |
} |
| 72 |
|
| 73 |
/* need for expanding BIND_EXPR */ |
| 74 |
static void insert_block(tree block ATTRIBUTE_UNUSED) { |
| 75 |
puts("enter insert_block()"); |
| 76 |
gcc_unreachable(); |
| 77 |
} |
| 78 |
|
| 79 |
static int global_bindings_p(void) { |
| 80 |
return current_binding_level == global_binding_level ? true : false; |
| 81 |
} |
| 82 |
|
| 83 |
static void push_level(void) { |
| 84 |
struct binding_level *newlevel = xmalloc(sizeof(struct binding_level)); |
| 85 |
*newlevel = clear_binding_level; |
| 86 |
newlevel->level_chain = current_binding_level; |
| 87 |
current_binding_level = newlevel; |
| 88 |
current_binding_level->stmts = alloc_stmt_list (); |
| 89 |
} |
| 90 |
|
| 91 |
static tree pushdecl(tree decl) { |
| 92 |
/* when auto (stack allocated) variable */ |
| 93 |
if(TREE_CODE(decl) == VAR_DECL |
| 94 |
&& !DECL_EXTERNAL(decl) |
| 95 |
&& !TREE_STATIC(decl) |
| 96 |
&& !TREE_PUBLIC(decl)) { |
| 97 |
TREE_CHAIN(decl) = BLOCK_VARS(current_binding_level->blocks); |
| 98 |
BLOCK_VARS(current_binding_level->blocks) = decl; |
| 99 |
tree code = build1(DECL_EXPR, void_type_node, decl); |
| 100 |
TREE_USED(code) = true; |
| 101 |
TREE_SIDE_EFFECTS(code) = true; |
| 102 |
append_to_statement_list(code, getstmtlist()); |
| 103 |
} else |
| 104 |
append_to_statement_list(decl, getstmtlist()); |
| 105 |
return decl; |
| 106 |
} |
| 107 |
|
| 108 |
static tree getdecls(void) { |
| 109 |
return current_binding_level->names; |
| 110 |
} |
| 111 |
|
| 112 |
#define MAX_LINE_SIZE 1024 |
| 113 |
static char current_line[MAX_LINE_SIZE]; |
| 114 |
static unsigned int current_lineno = 1; |
| 115 |
|
| 116 |
static FILE *bl_input_file; |
| 117 |
|
| 118 |
static bool bl_init(void) { |
| 119 |
build_common_tree_nodes(false, false); |
| 120 |
build_common_tree_nodes_2(false); |
| 121 |
|
| 122 |
if(!main_input_filename || |
| 123 |
main_input_filename[0] == ' ' || |
| 124 |
!main_input_filename[0]) { |
| 125 |
return false; |
| 126 |
} |
| 127 |
|
| 128 |
bl_input_file = fopen(main_input_filename, "r"); |
| 129 |
|
| 130 |
if(!bl_input_file) { |
| 131 |
fprintf (stderr, "Unable to open input file %s\n", main_input_filename); |
| 132 |
exit (1); |
| 133 |
} |
| 134 |
|
| 135 |
if(!fgets(current_line, MAX_LINE_SIZE, bl_input_file)) { |
| 136 |
fprintf (stderr, "Input file %s is empty\n", main_input_filename); |
| 137 |
exit (1); |
| 138 |
} |
| 139 |
|
| 140 |
/* create toplevel */ |
| 141 |
push_level(); |
| 142 |
global_binding_level = current_binding_level; |
| 143 |
current_binding_level->level_chain = NULL; |
| 144 |
|
| 145 |
current_function_decl = NULL_TREE; |
| 146 |
return true; |
| 147 |
} |
| 148 |
|
| 149 |
static void bl_finish(void) { |
| 150 |
fclose(bl_input_file); |
| 151 |
} |
| 152 |
|
| 153 |
#include <ctype.h> |
| 154 |
|
| 155 |
static tree parse_integer_value(char* string, unsigned int length) { |
| 156 |
|
| 157 |
long long int val = 0; |
| 158 |
unsigned int i = 0; |
| 159 |
unsigned int signed_p = 0; |
| 160 |
int negative = 1; |
| 161 |
switch(string[0]) { |
| 162 |
case (unsigned char)'-': |
| 163 |
negative = -1; |
| 164 |
signed_p = i = 1; |
| 165 |
break; |
| 166 |
|
| 167 |
case (unsigned char)'+': |
| 168 |
signed_p = i = 1; |
| 169 |
break; |
| 170 |
|
| 171 |
default: |
| 172 |
break; |
| 173 |
} |
| 174 |
for (; i < length; i++) |
| 175 |
val = val * 10 + string[i] - (unsigned char)'0'; |
| 176 |
val = val * negative; |
| 177 |
return build_int_cst_wide (signed_p == 1 ? |
| 178 |
integer_type_node : unsigned_type_node, |
| 179 |
val & 0xffffffff, (val >> 32) & 0xffffffff); |
| 180 |
} |
| 181 |
|
| 182 |
#define BUFSIZE 256 |
| 183 |
|
| 184 |
static tree next_tok(char **string) { |
| 185 |
static char buf[BUFSIZE]; |
| 186 |
char c; |
| 187 |
int i = 0; |
| 188 |
|
| 189 |
while((c = **string) == ' ' || c == '\t' || c == '\r') |
| 190 |
(*string)++; |
| 191 |
|
| 192 |
if((c = **string) == '\n' || c == '\0') |
| 193 |
return NULL_TREE; |
| 194 |
|
| 195 |
if(**string == '(') { |
| 196 |
(*string)++; |
| 197 |
printf("[(] : id\n"); |
| 198 |
return get_identifier("("); |
| 199 |
} |
| 200 |
|
| 201 |
if(**string == ')') { |
| 202 |
(*string)++; |
| 203 |
printf("[)] : id\n"); |
| 204 |
return get_identifier(")"); |
| 205 |
} |
| 206 |
|
| 207 |
if(**string == ',') { |
| 208 |
(*string)++; |
| 209 |
printf("[,] : id\n"); |
| 210 |
return get_identifier(","); |
| 211 |
} |
| 212 |
|
| 213 |
if(**string == '"') { |
| 214 |
(*string)++; |
| 215 |
while(**string != '"') { |
| 216 |
buf[i++] = **string; |
| 217 |
(*string)++; |
| 218 |
} |
| 219 |
(*string)++; |
| 220 |
buf[i] = '\0'; |
| 221 |
printf("\"%s\"\n", buf); |
| 222 |
return build_string_literal(strlen(buf) + 1, buf); |
| 223 |
} else { |
| 224 |
while((c = **string) != ' ' |
| 225 |
&& c != '\n' |
| 226 |
&& c != '\t' |
| 227 |
&& c != '\r' |
| 228 |
&& c != '\0' |
| 229 |
&& c != ',' |
| 230 |
&& c != '(' |
| 231 |
&& c != ')') { |
| 232 |
buf[i++] = **string; |
| 233 |
(*string)++; |
| 234 |
} |
| 235 |
} |
| 236 |
gcc_assert(i < BUFSIZE); |
| 237 |
buf[i] = '\0'; |
| 238 |
printf("[%s]", buf); |
| 239 |
if((((c = buf[0]) == '+' || c == '-') && isdigit(buf[1])) |
| 240 |
|| isdigit(c)) { |
| 241 |
printf(" : integer\n"); |
| 242 |
return parse_integer_value(buf, strlen(buf)); |
| 243 |
} else { |
| 244 |
printf(" : id\n"); |
| 245 |
return get_identifier(buf); |
| 246 |
} |
| 247 |
} |
| 248 |
|
| 249 |
#undef BUFSIZE |
| 250 |
|
| 251 |
static tree tok = NULL_TREE; |
| 252 |
static tree prev_tok = NULL_TREE; |
| 253 |
|
| 254 |
static tree next(void) { |
| 255 |
static char *last = current_line; |
| 256 |
|
| 257 |
if(prev_tok) { |
| 258 |
tok = prev_tok; |
| 259 |
prev_tok = NULL; |
| 260 |
return tok; |
| 261 |
} |
| 262 |
|
| 263 |
tok = next_tok(&last); |
| 264 |
|
| 265 |
if(!tok) { |
| 266 |
while(fgets(current_line, MAX_LINE_SIZE, bl_input_file)) { |
| 267 |
current_lineno++; |
| 268 |
if(current_line[0] == '\n') |
| 269 |
continue; |
| 270 |
last = current_line; |
| 271 |
printf("[EOL] (NULL_TREE)\n"); |
| 272 |
return NULL_TREE; |
| 273 |
} |
| 274 |
printf("[EOF] (id_EOF)\n"); |
| 275 |
return get_identifier("EOF"); |
| 276 |
} |
| 277 |
return tok; |
| 278 |
} |
| 279 |
|
| 280 |
static void pushback(void) { |
| 281 |
prev_tok = tok; |
| 282 |
} |
| 283 |
|
| 284 |
static int check(const char *id) { |
| 285 |
tree t = next(); |
| 286 |
pushback(); |
| 287 |
if(get_identifier(id) == t) |
| 288 |
return true; |
| 289 |
else |
| 290 |
return false; |
| 291 |
} |
| 292 |
|
| 293 |
static int next_p(void) { |
| 294 |
tree t = next(); |
| 295 |
pushback(); |
| 296 |
if(!t || t == get_identifier("EOF")) |
| 297 |
return false; |
| 298 |
return true; |
| 299 |
} |
| 300 |
|
| 301 |
static void expect(const char *tokname) { |
| 302 |
tree t = next(); |
| 303 |
if(get_identifier(tokname) != t) { |
| 304 |
if(TREE_CODE(t) == IDENTIFIER_NODE) { |
| 305 |
fprintf(stderr, "error : expected %s, but %s\n", tokname, |
| 306 |
IDENTIFIER_POINTER(t)); |
| 307 |
} else |
| 308 |
fprintf(stderr, "error : expected %s, but invalid token\n", tokname); |
| 309 |
exit(1); |
| 310 |
} |
| 311 |
} |
| 312 |
|
| 313 |
static tree lookup_variable(tree name) { |
| 314 |
struct binding_level* cl = current_binding_level; |
| 315 |
do { |
| 316 |
tree names = cl->names; |
| 317 |
while(names) { |
| 318 |
if(name == DECL_NAME(names)) |
| 319 |
return names; |
| 320 |
names = TREE_CHAIN(names); |
| 321 |
} |
| 322 |
} while((cl = cl->level_chain)); |
| 323 |
fprintf(stderr, "warning : variable %s can't find in this scope.\n", |
| 324 |
IDENTIFIER_POINTER(name)); |
| 325 |
return NULL_TREE; |
| 326 |
} |
| 327 |
|
| 328 |
static tree eval_value(tree t) { |
| 329 |
if(TREE_CODE(t) == IDENTIFIER_NODE) |
| 330 |
return lookup_variable(t); |
| 331 |
return t; |
| 332 |
} |
| 333 |
|
| 334 |
static enum tree_code get_operator(tree t) { |
| 335 |
if(get_identifier("+") == t) |
| 336 |
return PLUS_EXPR; |
| 337 |
else if(get_identifier("-") == t) |
| 338 |
return MINUS_EXPR; |
| 339 |
else if(get_identifier("*") == t) |
| 340 |
return MULT_EXPR; |
| 341 |
else if(get_identifier("/") == t) |
| 342 |
return TRUNC_DIV_EXPR; |
| 343 |
else if(get_identifier("%") == t) |
| 344 |
return TRUNC_MOD_EXPR; |
| 345 |
else { |
| 346 |
fprintf(stderr, "Invalid operator : %s\n", IDENTIFIER_POINTER(t)); |
| 347 |
gcc_unreachable(); |
| 348 |
} |
| 349 |
} |
| 350 |
|
| 351 |
static void bl_finalize_function(tree fn_decl) { |
| 352 |
struct cgraph_node *cgn = cgraph_node(fn_decl); |
| 353 |
cgraph_finalize_function(fn_decl, false); |
| 354 |
if(cgn) { |
| 355 |
// finalize all nested functions recursively |
| 356 |
for(cgn = cgn->nested; cgn ; cgn = cgn->next_nested) { |
| 357 |
bl_finalize_function(cgn->decl); |
| 358 |
} |
| 359 |
} |
| 360 |
} |
| 361 |
|
| 362 |
/* |
| 363 |
* Program ::= Def* |
| 364 |
* |
| 365 |
* // global definition |
| 366 |
* Def ::= id = Expr ('\n' | EOF) // variable definition |
| 367 |
* | id = fun (argtype id)* -> rettype '\n' // function definition |
| 368 |
* Stmt* |
| 369 |
* nuf ('\n' | EOF) |
| 370 |
* | id :: argtype* -> rettype '\n' // function prototype |
| 371 |
* |
| 372 |
* Stmt ::= return Expr '\n' // return statement |
| 373 |
* | id <- Expr '\n' // assignment statement |
| 374 |
* | Def // local definition |
| 375 |
* | if Expr '\n' // if statement |
| 376 |
* Stmt* |
| 377 |
* else |
| 378 |
* Stmt* |
| 379 |
* if '\n' |
| 380 |
* |
| 381 |
* Expr ::= Term + Term |
| 382 |
* | Term - Term |
| 383 |
* | Term |
| 384 |
* |
| 385 |
* Term ::= Fact * Fact |
| 386 |
* | Fact / Fact |
| 387 |
* | Fact % Fact |
| 388 |
* | Fact |
| 389 |
* |
| 390 |
* Fact ::= id '(' {Expr} (,Expr)* ')' // function call |
| 391 |
* | '(' Expr ')' |
| 392 |
* | id // variable |
| 393 |
* | integer |
| 394 |
* | ! Fact // not |
| 395 |
*/ |
| 396 |
|
| 397 |
static tree parse_expr(void); |
| 398 |
|
| 399 |
static tree parse_fact(void) { |
| 400 |
tree T1 = next(); |
| 401 |
|
| 402 |
// function call : id '(' {Expr} (, Expr)* ')' |
| 403 |
if(TREE_CODE(T1) == IDENTIFIER_NODE && |
| 404 |
T1 != get_identifier("!") && |
| 405 |
check("(")) { |
| 406 |
tree fn_decl = lookup_variable(T1); |
| 407 |
if(TREE_CODE(fn_decl) != FUNCTION_DECL) { |
| 408 |
fprintf(stderr, "error : %s is not function type node.\n", |
| 409 |
IDENTIFIER_POINTER(T1)); |
| 410 |
exit(1); |
| 411 |
} |
| 412 |
tree args = NULL_TREE; |
| 413 |
next(); |
| 414 |
if(!check(")")) { |
| 415 |
args = tree_cons(NULL_TREE, parse_expr(), NULL_TREE); |
| 416 |
while(check(",")) { |
| 417 |
next(); |
| 418 |
args = tree_cons(NULL_TREE, parse_expr(), args); |
| 419 |
} |
| 420 |
expect(")"); |
| 421 |
} |
| 422 |
args = nreverse(args); |
| 423 |
return build_function_call_expr(fn_decl, args); |
| 424 |
} |
| 425 |
|
| 426 |
if(T1 == get_identifier("!")) { |
| 427 |
tree exp = parse_fact(); |
| 428 |
return build1(BIT_NOT_EXPR,TREE_TYPE(exp),exp); |
| 429 |
} |
| 430 |
|
| 431 |
if(T1 == get_identifier("(")) { |
| 432 |
tree t = parse_expr(); |
| 433 |
expect(")"); |
| 434 |
return t; |
| 435 |
} |
| 436 |
|
| 437 |
return eval_value(T1); |
| 438 |
} |
| 439 |
|
| 440 |
static tree parse_term(void) { |
| 441 |
tree T1 = parse_fact(); |
| 442 |
|
| 443 |
while(next_p()) { |
| 444 |
if(!check("*") |
| 445 |
&& !check("/") |
| 446 |
&& !check("%")) { |
| 447 |
break; |
| 448 |
} |
| 449 |
tree op = next(); |
| 450 |
tree T2 = parse_fact(); |
| 451 |
T1 = fold_build2(get_operator(op), integer_type_node, T1,T2); |
| 452 |
} |
| 453 |
return T1; |
| 454 |
} |
| 455 |
|
| 456 |
static tree parse_expr(void) { |
| 457 |
tree T1 = parse_term(); |
| 458 |
|
| 459 |
while(next_p()) { |
| 460 |
if(!check("+") |
| 461 |
&& !check("-")) { |
| 462 |
break; |
| 463 |
} |
| 464 |
tree op = next(); |
| 465 |
tree T2 = parse_term(); |
| 466 |
T1 = fold_build2(get_operator(op), integer_type_node, T1,T2); |
| 467 |
} |
| 468 |
return T1; |
| 469 |
} |
| 470 |
|
| 471 |
static tree parse_stmt(void) { |
| 472 |
tree T1 = next(); |
| 473 |
if(!T1 |
| 474 |
|| T1 == get_identifier("nuf") |
| 475 |
|| T1 == get_identifier("else") |
| 476 |
|| T1 == get_identifier("fi") |
| 477 |
|| T1 == get_identifier("EOF")) |
| 478 |
return NULL_TREE; |
| 479 |
|
| 480 |
if(get_identifier("if") == T1) { |
| 481 |
fprintf(stderr, "enter if statement\n"); |
| 482 |
tree exp = parse_expr(); |
| 483 |
tree cond_exp = fold_build2(NE_EXPR, boolean_type_node, exp, |
| 484 |
fold_build1(CONVERT_EXPR, TREE_TYPE(exp), |
| 485 |
integer_zero_node)); |
| 486 |
|
| 487 |
// allocate new binding level and stmtlist for then stmts |
| 488 |
push_level(); |
| 489 |
while(parse_stmt()) |
| 490 |
; |
| 491 |
next(); // discard EOL |
| 492 |
tree then_stmts = *getstmtlist(); |
| 493 |
current_binding_level = current_binding_level->level_chain; |
| 494 |
|
| 495 |
// allocate new binding level and stmtlist for else stmts |
| 496 |
push_level(); |
| 497 |
while(parse_stmt()) |
| 498 |
; |
| 499 |
next(); // discard EOL |
| 500 |
tree else_stmts = *getstmtlist(); |
| 501 |
current_binding_level = current_binding_level->level_chain; |
| 502 |
|
| 503 |
tree cond = build3(COND_EXPR, void_type_node, cond_exp, |
| 504 |
then_stmts, else_stmts); |
| 505 |
|
| 506 |
append_to_statement_list(cond, getstmtlist()); |
| 507 |
|
| 508 |
fprintf(stderr, "leave if statement\n"); |
| 509 |
|
| 510 |
TREE_CHAIN(cond) = current_binding_level->names; |
| 511 |
current_binding_level->names = cond; |
| 512 |
return cond; |
| 513 |
} |
| 514 |
|
| 515 |
if(get_identifier("return") == T1) { |
| 516 |
fprintf(stderr, "enter return\n"); |
| 517 |
tree value = parse_expr(); |
| 518 |
tree setret = fold_build2(MODIFY_EXPR, integer_type_node, |
| 519 |
DECL_RESULT(current_function_decl), |
| 520 |
fold_build1(CONVERT_EXPR, integer_type_node, value)); |
| 521 |
TREE_SIDE_EFFECTS(setret) = true; |
| 522 |
TREE_USED(setret) = true; |
| 523 |
tree ret = fold_build1(RETURN_EXPR, integer_type_node, setret); |
| 524 |
pushdecl(ret); |
| 525 |
fprintf(stderr, "leave return\n"); |
| 526 |
return ret; |
| 527 |
} |
| 528 |
// DEFINITION EXPR |
| 529 |
if(TREE_CODE(T1) == IDENTIFIER_NODE && check("::")) { |
| 530 |
next(); |
| 531 |
tree id_TYPE = next(); |
| 532 |
tree parm_types = NULL_TREE; |
| 533 |
tree result_type = NULL_TREE; |
| 534 |
|
| 535 |
fprintf(stderr, "enter parse fun protorype\n"); |
| 536 |
while(id_TYPE != get_identifier("->")) { |
| 537 |
tree parm_type = NULL_TREE; |
| 538 |
if(id_TYPE == get_identifier("Int")) { |
| 539 |
parm_type = integer_type_node; |
| 540 |
} |
| 541 |
if(id_TYPE == get_identifier("String")) { |
| 542 |
parm_type = build_pointer_type(char_type_node); |
| 543 |
} |
| 544 |
parm_types = tree_cons(NULL_TREE, parm_type, parm_types); |
| 545 |
|
| 546 |
id_TYPE = next(); |
| 547 |
fprintf(stderr, "type : %s\n", IDENTIFIER_POINTER(id_TYPE)); |
| 548 |
} |
| 549 |
tree id_RES = next(); |
| 550 |
if(id_RES == get_identifier("Int")) { |
| 551 |
result_type = integer_type_node; |
| 552 |
} |
| 553 |
if(id_RES == get_identifier("Void")) { |
| 554 |
result_type = void_type_node; |
| 555 |
} |
| 556 |
next(); |
| 557 |
tree fn_decl = build_fn_decl(IDENTIFIER_POINTER(T1), |
| 558 |
build_function_type(result_type, parm_types)); |
| 559 |
DECL_EXTERNAL(fn_decl) = true; |
| 560 |
TREE_CHAIN(fn_decl) = current_binding_level->names; |
| 561 |
current_binding_level->names = fn_decl; |
| 562 |
fprintf(stderr, "leave parse fun protorype\n"); |
| 563 |
|
| 564 |
rest_of_decl_compilation(fn_decl, /* TOPLEVEL */true, /* AT END */false); |
| 565 |
return fn_decl; |
| 566 |
} |
| 567 |
|
| 568 |
if(TREE_CODE(T1) == IDENTIFIER_NODE && check("=")) { |
| 569 |
next(); |
| 570 |
|
| 571 |
// TYPED VARIABLE DEFINITION BY INITIALIZER (e.g. x = 123) |
| 572 |
if(!check("fun")) { |
| 573 |
fprintf(stderr, "enter init\n"); |
| 574 |
tree value = parse_expr(); |
| 575 |
tree var_decl = build_decl(VAR_DECL, T1, TREE_TYPE(value)); |
| 576 |
DECL_EXTERNAL(var_decl) = false; |
| 577 |
if(global_bindings_p()) { |
| 578 |
TREE_STATIC(var_decl) = true; |
| 579 |
TREE_PUBLIC(var_decl) = true; |
| 580 |
} else { |
| 581 |
TREE_STATIC(var_decl) = false; |
| 582 |
TREE_PUBLIC(var_decl) = false; |
| 583 |
} |
| 584 |
TREE_USED(var_decl) = true; |
| 585 |
DECL_INITIAL(var_decl) = value; |
| 586 |
DECL_CONTEXT(var_decl) = current_function_decl; |
| 587 |
TREE_CHAIN(var_decl) = current_binding_level->names; |
| 588 |
current_binding_level->names = var_decl; |
| 589 |
if(global_bindings_p()) |
| 590 |
rest_of_decl_compilation(var_decl, /* TOP LEVEL */true, |
| 591 |
/* AT END OF COMPILATION */false); |
| 592 |
else |
| 593 |
pushdecl(var_decl); |
| 594 |
fprintf(stderr, "leave init\n"); |
| 595 |
return var_decl; |
| 596 |
} |
| 597 |
|
| 598 |
// FUNCTION DEFINITION |
| 599 |
if(check("fun")) { |
| 600 |
next(); |
| 601 |
fprintf(stderr, "enter fun def\n"); |
| 602 |
tree fn_decl = build_fn_decl(IDENTIFIER_POINTER(T1), NULL_TREE); |
| 603 |
tree arg_types = NULL_TREE; |
| 604 |
tree result_type = NULL_TREE; |
| 605 |
tree parms = NULL_TREE; |
| 606 |
tree id_TYPE = next(); |
| 607 |
tree id_PARM = next(); |
| 608 |
tree id_RES = NULL_TREE; |
| 609 |
tree block = build_block(NULL_TREE, // variables |
| 610 |
NULL_TREE, // subblocks |
| 611 |
NULL_TREE, // supercontext |
| 612 |
NULL_TREE); // next same level block |
| 613 |
|
| 614 |
DECL_EXTERNAL(fn_decl) = false; |
| 615 |
DECL_ARTIFICIAL(fn_decl) = false; |
| 616 |
DECL_CONTEXT(fn_decl) = current_function_decl; |
| 617 |
TREE_STATIC(fn_decl) = true; |
| 618 |
TREE_PUBLIC(fn_decl) = true; |
| 619 |
if(current_function_decl) { |
| 620 |
fprintf(stderr, "enter nested function def\n"); |
| 621 |
TREE_STATIC(fn_decl) = false; |
| 622 |
TREE_PUBLIC(fn_decl) = false; |
| 623 |
BLOCK_SUPERCONTEXT(block) = current_function_decl; |
| 624 |
BLOCK_SUBBLOCKS(current_binding_level->blocks) = block; |
| 625 |
} |
| 626 |
DECL_INITIAL(fn_decl) = block; |
| 627 |
|
| 628 |
TREE_CHAIN(fn_decl) = current_binding_level->names; |
| 629 |
current_binding_level->names = fn_decl; |
| 630 |
|
| 631 |
// enter new scope (in function) |
| 632 |
push_level(); |
| 633 |
tree prev_fn_decl = current_function_decl; |
| 634 |
current_function_decl = fn_decl; |
| 635 |
current_binding_level->blocks = block; |
| 636 |
|
| 637 |
while(id_TYPE != get_identifier("->")) { |
| 638 |
fprintf(stderr, "enter parse fun arg\n"); |
| 639 |
tree parm_type = NULL_TREE; |
| 640 |
if(id_TYPE == get_identifier("Int")) { |
| 641 |
parm_type = integer_type_node; |
| 642 |
} |
| 643 |
tree parm = build_decl(PARM_DECL, id_PARM, parm_type); |
| 644 |
DECL_ARG_TYPE(parm) = parm_type; |
| 645 |
TREE_CHAIN(parm) = parms; |
| 646 |
parms = parm; |
| 647 |
DECL_CONTEXT(parm) = fn_decl; |
| 648 |
TREE_CHAIN(parm) = current_binding_level->names; |
| 649 |
current_binding_level->names = parm; |
| 650 |
arg_types = tree_cons(NULL_TREE, parm_type, arg_types); |
| 651 |
|
| 652 |
id_TYPE = next(); |
| 653 |
id_PARM = next(); |
| 654 |
|
| 655 |
fprintf(stderr, "type : %s, parm : %s\n", IDENTIFIER_POINTER(id_TYPE), |
| 656 |
IDENTIFIER_POINTER(id_PARM)); |
| 657 |
} |
| 658 |
gcc_assert(!next()); |
| 659 |
id_RES = id_PARM; |
| 660 |
if(id_RES == get_identifier("Int")) { |
| 661 |
result_type = integer_type_node; |
| 662 |
fprintf(stderr, "parse result : %s\n", |
| 663 |
IDENTIFIER_POINTER(id_RES)); |
| 664 |
} |
| 665 |
tree result_decl = build_decl(RESULT_DECL, NULL_TREE, result_type); |
| 666 |
DECL_CONTEXT(result_decl) = fn_decl; |
| 667 |
DECL_RESULT(fn_decl) = result_decl; |
| 668 |
|
| 669 |
DECL_ARGUMENTS(fn_decl) = parms; |
| 670 |
TREE_TYPE(fn_decl) = build_function_type(result_type, arg_types); |
| 671 |
|
| 672 |
//debug_tree(fn_decl); |
| 673 |
|
| 674 |
// parse stmts in fun ... nuf |
| 675 |
fprintf(stderr, "enter stmts in %s()\n", IDENTIFIER_POINTER(T1)); |
| 676 |
while(parse_stmt()) |
| 677 |
; |
| 678 |
next(); // discard EOL or EOF |
| 679 |
fprintf(stderr, "leave stmts in %s()\n", IDENTIFIER_POINTER(T1)); |
| 680 |
|
| 681 |
DECL_SAVED_TREE(fn_decl) = build3(BIND_EXPR, void_type_node, |
| 682 |
BLOCK_VARS(block), *(getstmtlist()), block); |
| 683 |
allocate_struct_function(fn_decl); |
| 684 |
gimplify_function_tree(fn_decl); |
| 685 |
|
| 686 |
if(!prev_fn_decl) { |
| 687 |
fprintf(stderr, "enter finalize %s()\n", IDENTIFIER_POINTER(T1)); |
| 688 |
bl_finalize_function(fn_decl); |
| 689 |
fprintf(stderr, "leave finalize %s()\n", IDENTIFIER_POINTER(T1)); |
| 690 |
} else |
| 691 |
fprintf(stderr, "leave nested function def\n"); |
| 692 |
// pop fnction decl |
| 693 |
current_function_decl = prev_fn_decl; |
| 694 |
current_binding_level = current_binding_level->level_chain; |
| 695 |
|
| 696 |
fprintf(stderr, "leave fun def\n"); |
| 697 |
return fn_decl; |
| 698 |
} |
| 699 |
} |
| 700 |
// ASSIGNMENT (e.g. x <- 123) |
| 701 |
if(TREE_CODE(T1) == IDENTIFIER_NODE && |
| 702 |
check("<-")) { |
| 703 |
next(); |
| 704 |
fprintf(stderr, "enter assign\n"); |
| 705 |
tree value = parse_expr(); |
| 706 |
tree assign = fold_build2(MODIFY_EXPR, integer_type_node, eval_value(T1), |
| 707 |
fold_build1(CONVERT_EXPR, integer_type_node, value)); |
| 708 |
TREE_SIDE_EFFECTS(assign) = true; |
| 709 |
TREE_USED(assign) = true; |
| 710 |
pushdecl(assign); |
| 711 |
fprintf(stderr, "leave assign\n"); |
| 712 |
return assign; |
| 713 |
} |
| 714 |
|
| 715 |
debug_tree(T1); |
| 716 |
gcc_unreachable(); |
| 717 |
} |
| 718 |
|
| 719 |
static void bl_parse_file(int debug ATTRIBUTE_UNUSED) { |
| 720 |
|
| 721 |
while(parse_stmt()) |
| 722 |
; |
| 723 |
|
| 724 |
cgraph_finalize_compilation_unit(); |
| 725 |
cgraph_optimize(); |
| 726 |
} |
| 727 |
|
| 728 |
/************************* from treelang **********************************/ |
| 729 |
|
| 730 |
struct lang_identifier GTY(()) { |
| 731 |
struct tree_identifier common; |
| 732 |
}; |
| 733 |
|
| 734 |
union lang_tree_node GTY(( desc("0") )){}; |
| 735 |
struct lang_type GTY(()){}; |
| 736 |
struct lang_decl GTY(()){}; |
| 737 |
struct language_function GTY(()){}; |
| 738 |
|
| 739 |
static tree builtin_function(const char *name, tree type, |
| 740 |
int function_code, enum built_in_class class, |
| 741 |
const char *library_name, tree attrs) { |
| 742 |
tree decl = build_decl(FUNCTION_DECL, get_identifier(name), type); |
| 743 |
DECL_EXTERNAL(decl) = true; |
| 744 |
TREE_PUBLIC(decl) = true; |
| 745 |
if(library_name) |
| 746 |
SET_DECL_ASSEMBLER_NAME(decl, get_identifier(library_name)); |
| 747 |
pushdecl(decl); |
| 748 |
DECL_BUILT_IN_CLASS(decl) = class; |
| 749 |
DECL_FUNCTION_CODE(decl) = function_code; |
| 750 |
if (attrs) |
| 751 |
decl_attributes(&decl, attrs, ATTR_FLAG_BUILT_IN); |
| 752 |
else |
| 753 |
decl_attributes(&decl, NULL_TREE, 0); |
| 754 |
return decl; |
| 755 |
} |
| 756 |
|
| 757 |
static tree bl_signed_type(tree type_node ATTRIBUTE_UNUSED) { |
| 758 |
puts("enter bl_signed_type()"); |
| 759 |
gcc_unreachable(); |
| 760 |
} |
| 761 |
|
| 762 |
static unsigned int bl_init_options (unsigned int argc ATTRIBUTE_UNUSED, |
| 763 |
const char **argv ATTRIBUTE_UNUSED) { |
| 764 |
return CL_bl; |
| 765 |
} |
| 766 |
|
| 767 |
static int bl_handle_option(size_t scode, |
| 768 |
const char *arg ATTRIBUTE_UNUSED, |
| 769 |
int value ATTRIBUTE_UNUSED) { |
| 770 |
enum opt_code code = (enum opt_code) scode; |
| 771 |
|
| 772 |
if(code == OPT_bye) { |
| 773 |
return 1; |
| 774 |
} |
| 775 |
return 0; |
| 776 |
} |
| 777 |
|
| 778 |
tree convert(tree type ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED) { |
| 779 |
puts("enter convert()"); |
| 780 |
gcc_unreachable(); |
| 781 |
} |
| 782 |
|
| 783 |
static bool bl_mark_addressable(tree exp) { |
| 784 |
switch (TREE_CODE(exp)){ |
| 785 |
case STRING_CST: |
| 786 |
break; |
| 787 |
case FUNCTION_DECL: |
| 788 |
TREE_ADDRESSABLE(exp) = true; |
| 789 |
break; |
| 790 |
case ARRAY_REF: |
| 791 |
return bl_mark_addressable(TREE_OPERAND(exp, 0)); |
| 792 |
break; |
| 793 |
default: |
| 794 |
puts("enter bl_marK_adressable()"); |
| 795 |
gcc_unreachable(); |
| 796 |
break; |
| 797 |
} |
| 798 |
return true; |
| 799 |
} |
| 800 |
|
| 801 |
static tree bl_unsigned_type(tree type_node ATTRIBUTE_UNUSED) { |
| 802 |
puts("enter bl_unsigned_type()"); |
| 803 |
gcc_unreachable(); |
| 804 |
} |
| 805 |
|
| 806 |
static tree bl_signed_or_unsigned_type(int unsignedp ATTRIBUTE_UNUSED, |
| 807 |
tree type ATTRIBUTE_UNUSED) { |
| 808 |
puts("enter bl_signed_or_unsigned_type()"); |
| 809 |
gcc_unreachable(); |
| 810 |
} |
| 811 |
|
| 812 |
/*****************************************************************************/ |
| 813 |
|
| 814 |
#undef LANG_HOOKS_NAME |
| 815 |
#define LANG_HOOKS_NAME "bl" |
| 816 |
|
| 817 |
#undef LANG_HOOKS_INIT |
| 818 |
#define LANG_HOOKS_INIT bl_init |
| 819 |
|
| 820 |
#undef LANG_HOOKS_INIT_OPTIONS |
| 821 |
#define LANG_HOOKS_INIT_OPTIONS bl_init_options |
| 822 |
|
| 823 |
#undef LANG_HOOKS_FINISH |
| 824 |
#define LANG_HOOKS_FINISH bl_finish |
| 825 |
|
| 826 |
#undef LANG_HOOKS_HANDLE_OPTION |
| 827 |
#define LANG_HOOKS_HANDLE_OPTION bl_handle_option |
| 828 |
|
| 829 |
#undef LANG_HOOKS_PARSE_FILE |
| 830 |
#define LANG_HOOKS_PARSE_FILE bl_parse_file |
| 831 |
|
| 832 |
#undef LANG_HOOKS_MARK_ADDRESSABLE |
| 833 |
#define LANG_HOOKS_MARK_ADDRESSABLE bl_mark_addressable |
| 834 |
|
| 835 |
#undef LANG_HOOKS_TYPE_FOR_MODE |
| 836 |
#define LANG_HOOKS_TYPE_FOR_MODE bl_type_for_mode |
| 837 |
|
| 838 |
#undef LANG_HOOKS_TYPE_FOR_SIZE |
| 839 |
#define LANG_HOOKS_TYPE_FOR_SIZE bl_type_for_size |
| 840 |
|
| 841 |
#undef LANG_HOOKS_UNSIGNED_TYPE |
| 842 |
#define LANG_HOOKS_UNSIGNED_TYPE bl_unsigned_type |
| 843 |
|
| 844 |
#undef LANG_HOOKS_SIGNED_TYPE |
| 845 |
#define LANG_HOOKS_SIGNED_TYPE bl_signed_type |
| 846 |
|
| 847 |
#undef LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE |
| 848 |
#define LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE bl_signed_or_unsigned_type |
| 849 |
|
| 850 |
#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION |
| 851 |
#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION tree_rest_of_compilation |
| 852 |
|
| 853 |
const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; |
| 854 |
|
| 855 |
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE, |
| 856 |
const enum tree_code_class tree_code_type[] = { |
| 857 |
#include "tree.def" |
| 858 |
tcc_exceptional |
| 859 |
}; |
| 860 |
#undef DEFTREECODE |
| 861 |
|
| 862 |
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH, |
| 863 |
const unsigned char tree_code_length[] = { |
| 864 |
#include "tree.def" |
| 865 |
0 |
| 866 |
}; |
| 867 |
#undef DEFTREECODE |
| 868 |
|
| 869 |
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME, |
| 870 |
const char *const tree_code_name[] = { |
| 871 |
#include "tree.def" |
| 872 |
"@@dummy" |
| 873 |
}; |
| 874 |
#undef DEFTREECODE |
| 875 |
|
| 876 |
#include "gt-bl-bl1.h" |
| 877 |
#include "gtype-bl.h" |