HVO7VLDMVEQEJOCLSKHWAICBXRYKCGKEDKXZOI44ITYTCDJBZ4UAC
// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: https://pvs-studio.com
/*********************************************************************
Intermediate code generator for COOL: SKELETON
Read the comments carefully and add code to build an LLVM program
*********************************************************************/
#define EXTERN
#include "cgen.h"
#include <cmath>
#include <sstream>
#include <string>
#include <llvm/Support/FileSystem.h>
// special assert that allows debugging to continue
// https://nullprogram.com/blog/2024/01/28/
#ifdef _MSC_VER
#undef assert
#define assert(c) do if (!(c)) { fprintf(stderr, "Assertion %s failed [%d]\n", #c, __LINE__); __debugbreak(); } while (0)
#define assertm(c, msg) do if (!(c)) { fprintf(stderr, "Assertion %s failed [%d]: %s\n", #c, __LINE__, msg); __debugbreak(); } while (0)
#elif defined __x86_64__
#undef assert
#define assert(c) do if (!(c)) { fprintf(stderr, "Assertion %s failed [%d]\n", #c, __LINE__); asm ("int3; nop"); } while (0)
#define assertm(c, msg) do if (!(c)) { fprintf(stderr, "Assertion %s failed [%d]: %s\n", #c, __LINE__, msg); asm ("int3; nop"); } while (0)
#endif
extern int cgen_debug, curr_lineno;
using namespace llvm;
/*********************************************************************
For convenience, a large number of symbols are predefined here.
These symbols include the primitive type and method names, as well
as fixed names used by the runtime system. Feel free to add your
own definitions as you see fit.
*********************************************************************/
EXTERN Symbol
// required classes
Object,
IO, String, Int, Bool, Main,
// class methods
cool_abort, type_name, cool_copy, out_string, out_int, in_string, in_int,
length, concat, substr,
// class members
val,
// special symbols
No_class, // symbol that can't be the name of any user-defined class
No_type, // If e : No_type, then no code is generated for e.
SELF_TYPE, // Special code is generated for new SELF_TYPE.
self, // self generates code differently than other references
// extras
arg, arg2, newobj, Mainmain, prim_string, prim_int, prim_bool;
namespace
{
std::string as_string(Symbol) __attribute((pure));
std::vector<Expression> unfuck(Expressions) __attribute((pure));
std::vector<Formal> unfuck(Formals) __attribute((pure));
std::vector<Feature> unfuck(Features) __attribute((pure));
std::pair<Type*, Value*> resolve_opaque(Value*) __attribute((pure));
std::pair<std::string, std::string> split(const std::string&, char) __attribute((pure));
template<class T, class R>
std::vector<R> map(std::vector<T> src, std::function<R(T const &)> mapper) __attribute((pure, optimize("O3")));
// Initializing the predefined symbols.
void initialize_constants()
{
Object = idtable.add_string("Object");
IO = idtable.add_string("IO");
String = idtable.add_string("String");
Int = idtable.add_string("Int");
Bool = idtable.add_string("Bool");
Main = idtable.add_string("Main");
cool_abort = idtable.add_string("abort");
type_name = idtable.add_string("type_name");
cool_copy = idtable.add_string("copy");
out_string = idtable.add_string("out_string");
out_int = idtable.add_string("out_int");
in_string = idtable.add_string("in_string");
in_int = idtable.add_string("in_int");
length = idtable.add_string("length");
::concat = idtable.add_string("concat");
substr = idtable.add_string("substr");
val = idtable.add_string("val");
No_class = idtable.add_string("_no_class");
No_type = idtable.add_string("_no_type");
SELF_TYPE = idtable.add_string("SELF_TYPE");
self = idtable.add_string("self");
arg = idtable.add_string("arg");
arg2 = idtable.add_string("arg2");
newobj = idtable.add_string("_newobj");
Mainmain = idtable.add_string("main");
prim_string = idtable.add_string("sbyte*");
prim_int = idtable.add_string("int");
prim_bool = idtable.add_string("bool");
}
}
#pragma region "CgenClassTable"
// CgenClassTable constructor orchestrates all code generation
CgenClassTable::CgenClassTable(Classes classes)
: nds(), current_tag(0), context(), builder(this->context),
the_module(stringtable.get_file(), this->context), di_builder(the_module)
{
if (cgen_debug)
std::cerr << "Building CgenClassTable" << std::endl;
i1 = Type::getInt1Ty(this->context);
i8 = Type::getInt8Ty(this->context);
i32 = Type::getInt32Ty(this->context);
ptr = i8->getPointerTo();
void_ = Type::getVoidTy(this->context);
#ifdef EMIT_DBG
the_module.addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION);
di_file = di_builder.createFile(stringtable.get_file(), ".");
di_cu = di_builder.createCompileUnit(dwarf::DW_LANG_C, di_file, "ibn222_ece479k_lab2",
false, (cgen_debug) ? "-d" : "", 0);
di1 = di_builder.createBasicType("bool", 1, dwarf::DW_ATE_signed);
di8 = di_builder.createBasicType("cbool", 8, dwarf::DW_ATE_signed);
di32 = di_builder.createBasicType("int", 32, dwarf::DW_ATE_signed);
dptr = di_builder.createPointerType(di8, 64, 0, std::nullopt, "opaque_ptr");
dvoid = di_builder.createNullPtrType();
#endif
// Make sure we have a scope, both for classes and for constants
enterscope();
// Create an inheritance tree with one CgenNode per class.
install_basic_classes();
install_classes(classes);
build_inheritance_tree();
// First pass
setup();
// Second pass
code_module();
// Done with code generation: exit scopes
exitscope();
#ifdef EMIT_DBG
// finalize debug info
di_builder.finalize();
#endif
}
// Creates AST nodes for the basic classes and installs them in the class list
void CgenClassTable::install_basic_classes()
{
// The tree package uses these globals to annotate the classes built below.
curr_lineno = 0;
Symbol filename = stringtable.add_string("<basic class>");
//
// A few special class names are installed in the lookup table but not
// the class list. Thus, these classes exist, but are not part of the
// inheritance hierarchy.
// No_class serves as the parent of Object and the other special classes.
Class_ noclasscls = class_(No_class, No_class, nil_Features(), filename);
install_special_class(new CgenNode(noclasscls, CgenNode::Basic, this));
delete noclasscls;
// SELF_TYPE is the self class; it cannot be redefined or inherited.
Class_ selftypecls = class_(SELF_TYPE, No_class, nil_Features(), filename);
install_special_class(new CgenNode(selftypecls, CgenNode::Basic, this));
delete selftypecls;
//
// Primitive types masquerading as classes. This is done so we can
// get the necessary Symbols for the innards of String, Int, and Bool
//
Class_ primstringcls =
class_(prim_string, No_class, nil_Features(), filename);
install_special_class(new CgenNode(primstringcls, CgenNode::Basic, this));
delete primstringcls;
Class_ primintcls = class_(prim_int, No_class, nil_Features(), filename);
install_special_class(new CgenNode(primintcls, CgenNode::Basic, this));
delete primintcls;
Class_ primboolcls = class_(prim_bool, No_class, nil_Features(), filename);
install_special_class(new CgenNode(primboolcls, CgenNode::Basic, this));
delete primboolcls;
//
// The Object class has no parent class. Its methods are
// cool_abort() : Object aborts the program
// type_name() : Str returns a string representation of class name
// copy() : SELF_TYPE returns a copy of the object
//
// There is no need for method bodies in the basic classes---these
// are already built in to the runtime system.
//
Class_ objcls = class_(
Object, No_class,
append_Features(
append_Features(single_Features(method(cool_abort, nil_Formals(),
Object, no_expr())),
single_Features(method(type_name, nil_Formals(),
String, no_expr()))),
single_Features(
method(cool_copy, nil_Formals(), SELF_TYPE, no_expr()))),
filename);
install_class(new CgenNode(objcls, CgenNode::Basic, this));
delete objcls;
//
// The Int class has no methods and only a single attribute, the
// "val" for the integer.
//
Class_ intcls = class_(
Int, Object, single_Features(attr(val, prim_int, no_expr())), filename);
install_class(new CgenNode(intcls, CgenNode::Basic, this));
delete intcls;
//
// Bool also has only the "val" slot.
//
Class_ boolcls = class_(
Bool, Object, single_Features(attr(val, prim_bool, no_expr())),
filename);
install_class(new CgenNode(boolcls, CgenNode::Basic, this));
delete boolcls;
//
// The class String has a number of slots and operations:
// val the string itself
// length() : Int length of the string
// concat(arg: Str) : Str string concatenation
// substr(arg: Int, arg2: Int): Str substring
//
Class_ stringcls =
class_(String, Object,
append_Features(
append_Features(
append_Features(
single_Features(
attr(val, prim_string, no_expr())),
single_Features(
method(length, nil_Formals(), Int,
no_expr()))),
single_Features(method(::concat,
single_Formals(
formal(arg, String)),
String, no_expr()))),
single_Features(
method(substr,
append_Formals(
single_Formals(formal(arg, Int)),
single_Formals(formal(arg2, Int))),
String, no_expr()))),
filename);
install_class(new CgenNode(stringcls, CgenNode::Basic, this));
delete stringcls;
//
// The IO class inherits from Object. Its methods are
// out_string(Str) : SELF_TYPE writes a string to the output
// out_int(Int) : SELF_TYPE " an int " " "
// in_string() : Str reads a string from the input
// in_int() : Int " an int " " "
//
Class_ iocls = class_(
IO, Object,
append_Features(
append_Features(
append_Features(
single_Features(method(out_string,
single_Formals(formal(arg, String)),
SELF_TYPE, no_expr())),
single_Features(method(out_int,
single_Formals(formal(arg, Int)),
SELF_TYPE, no_expr()))),
single_Features(
method(in_string, nil_Formals(), String, no_expr()))),
single_Features(method(in_int, nil_Formals(), Int, no_expr()))),
filename);
install_class(new CgenNode(iocls, CgenNode::Basic, this));
delete iocls;
}
// install_classes enters a list of classes in the symbol table.
void CgenClassTable::install_classes(Classes cs)
{
for (auto cls: cs) {
install_class(new CgenNode(cls, CgenNode::NotBasic, this));
}
}
// Add this CgenNode to the class list and the lookup table
void CgenClassTable::install_class(CgenNode* nd)
{
Symbol name = nd->get_name();
if (!this->find(name)) {
// The class name is legal, so add it to the list of classes
// and the symbol table.
nds.push_back(nd);
this->insert(name, nd);
}
// Prevent circular dependency issues when using this CgenNode later
nd->premake_type();
// nd->premake_debug_type();
}
// Add this CgenNode to the special class list and the lookup table
void CgenClassTable::install_special_class(CgenNode* nd)
{
Symbol name = nd->get_name();
if (!this->find(name)) {
// The class name is legal, so add it to the list of special classes
// and the symbol table.
special_nds.push_back(nd);
this->insert(name, nd);
}
}
// CgenClassTable::build_inheritance_tree
void CgenClassTable::build_inheritance_tree()
{
for (auto node: nds)
set_relations(node);
}
// CgenClassTable::set_relations
// Takes a CgenNode and locates its, and its parent's, inheritance nodes
// via the class table. Parent and child pointers are added as appropriate.
//
void CgenClassTable::set_relations(CgenNode* nd)
{
Symbol parent = nd->get_parent();
auto parent_node = this->find(parent);
if (!parent_node) {
throw std::runtime_error("Class " + nd->get_name()->get_string() +
" inherits from an undefined class " +
parent->get_string());
}
nd->set_parent(parent_node);
}
// Sets up declarations for extra functions needed for code generation
// You should not need to modify this code for Lab1
void CgenClassTable::setup_external_functions()
{
// setup function: external int strcmp(ptr, ptr)
create_llvm_function("strcmp", i32, {ptr, ptr}, false);
// setup function: external int printf(ptr, ...)
create_llvm_function("printf", i32, {ptr}, true);
// setup function: external void abort(void)
create_llvm_function("abort", void_, {}, false);
// setup function: external ptr malloc(i32)
create_llvm_function("malloc", ptr, {i32}, false);
// setup function: external void free(ptr)
create_llvm_function("free", void_, {ptr}, false);
auto* ObjectTy = ptr;
create_function("Object_new", ObjectTy, {}, GlobalValue::ExternalLinkage);
auto* IntTy = ptr;
create_function("Int_new", IntTy, {}, GlobalValue::ExternalLinkage);
create_function("Int_init", IntTy, {IntTy, i32}, GlobalValue::ExternalLinkage);
auto* BoolTy = ptr;
create_function("Bool_new", BoolTy, {}, GlobalValue::ExternalLinkage);
// this takes a i8 because C's bool is byte
create_function("Bool_init", BoolTy, {BoolTy, i8}, GlobalValue::ExternalLinkage);
auto* StringTy = ptr;
create_function("String_new", StringTy, {}, GlobalValue::ExternalLinkage);
auto* IoTy = ptr;
create_function("IO_new", IoTy, {}, GlobalValue::ExternalLinkage);
}
void CgenClassTable::setup_classes(CgenNode* c, int depth)
{
c->setup(current_tag++, depth);
for (auto child: c->get_children()) {
setup_classes(child, depth + 1);
}
c->set_max_child(current_tag - 1);
}
// The code generation first pass. Define these two functions to traverse
// the tree and setup each CgenNode
void CgenClassTable::setup()
{
setup_external_functions();
setup_classes(root(), 0);
// setup_external_functions();
}
// The code generation second pass. Add code here to traverse the tree and
// emit code for each CgenNode
void CgenClassTable::code_module()
{
code_constants();
code_classes(root());
code_main();
if (cgen_debug)
std::cerr << "\n";
}
void CgenClassTable::code_classes(CgenNode* c)
{
// emit Object first
if (c->get_type_name() == "Object") {
if (cgen_debug)
std::cerr << "\n\nEmitting classes\n";
c->code_class();
}
std::vector classes{c->get_children()};
for (auto const i: classes)
i->code_class();
// we need to generate top down so that the types are populated for inherited classes
for (auto* i: classes)
code_classes(i);
}
// Create global definitions for constant Cool objects
void CgenClassTable::code_constants()
{
if (cgen_debug)
std::cerr << "\n\nEmitting constants\n";
stringtable.code_string_table(this);
}
// Create LLVM entry point. This function will initiate our Cool program
// by generating the code to execute (new Main).main()
//
void CgenClassTable::code_main()
{
if (cgen_debug)
std::cerr << "\n\nEmitting main\n";
// Define a function main that has no parameters and returns an i32
auto* fn = create_function("main", i32, {},
GlobalValue::ExternalLinkage);
// Define an entry basic block
auto* bb = BasicBlock::Create(this->context, "main_entry_point", fn);
builder.SetInsertPoint(bb);
// Call Main_new() to create a Main
auto* main_new = the_module.getFunction("Main_new");
assertm(main_new, "Main_new exists");
auto* main = builder.CreateCall(main_new, {});
// Call Main_main
auto* main_main = the_module.getFunction("Main_main");
assertm(main_main, "Main_main exists");
auto* main_returned = builder.CreateCall(main_main, {main});
// Always return 0
builder.CreateRet(builder.getInt32(0));
}
// Get the root of the class tree.
CgenNode* CgenClassTable::root()
{
auto root = this->find(Object);
if (!root) {
throw std::runtime_error("Class Object is not defined.");
}
return root;
}
Function* CgenClassTable::create_llvm_function(const std::string &funcName,
Type* retType,
ArrayRef<Type *> argTypes,
bool isVarArgs)
{
assert(retType);
auto* ft = FunctionType::get(retType, argTypes, isVarArgs);
auto* func = Function::Create(ft, Function::ExternalLinkage, funcName,
this->the_module);
if (!func) {
errs() << "Function creation failed for function " << funcName;
llvm_unreachable("Function creation failed");
}
return func;
}
Function* CgenClassTable::create_function(const std::string &name,
Type* ret_type,
ArrayRef<Type *> arg_types,
GlobalValue::LinkageTypes linkage)
{
assert(ret_type);
auto* ft = FunctionType::get(ret_type, arg_types, false);
auto* func = Function::Create(ft, linkage, name,
this->the_module);
if (!func) {
errs() << "Function creation failed for function " << name;
llvm_unreachable("Function creation failed");
}
return func;
}
Function* CgenClassTable::create_var_function(const std::string &name,
Type* ret_type,
ArrayRef<Type *> arg_types,
GlobalValue::LinkageTypes linkage)
{
assert(ret_type);
auto* ft = FunctionType::get(ret_type, arg_types, true);
auto* func = Function::Create(ft, linkage, name,
this->the_module);
if (!func) {
errs() << "Function creation failed for function " << name;
llvm_unreachable("Function creation failed");
}
return func;
}
#pragma endregion
#pragma region "stringtab"
/*********************************************************************
StrTable / IntTable methods
Coding string, int, and boolean constants
Cool has three kinds of constants: strings, ints, and booleans.
This section defines code generation for each type.
All string constants are listed in the global "stringtable" and have
type stringEntry. stringEntry methods are defined both for string
constant definitions and references.
All integer constants are listed in the global "inttable" and have
type IntEntry. IntEntry methods are defined for Int constant references only.
Since there are only two Bool values, there is no need for a table.
The two booleans are represented by instances of the class BoolConst,
which defines the definition and reference methods for Bools.
*********************************************************************/
// Create definitions for all String constants
void StrTable::code_string_table(CgenClassTable* ct)
{
if (cgen_debug)
std::cerr << "Emitting string table\n";
for (auto &[_, entry]: this->_table) {
entry.code_def(ct);
}
}
std::string StrTable::get_file() const
{
auto it = _table.cbegin();
for (int i = 0; i < _table.size() - 1; ++i)
it++;
return it->first;
}
// generate code to define a global string constant
void StringEntry::code_def(CgenClassTable* ct)
{
if (cgen_debug)
std::cerr << "\tEmitting \"" << this->str << "\"\n";
auto* string = ct->find(String);
auto* gstr = ct->builder.CreateGlobalStringPtr(this->str, "", 0, &ct->the_module);
auto* init = ConstantStruct::get(string->type, {string->vtable, gstr});
ptr = new GlobalVariable(ct->the_module, string->type, true,
GlobalValue::InternalLinkage, init);
}
void StringEntry::code_ref(CgenClassTable *ct)
{
// TODO: add code here
}
void IntEntry::code_ref(CgenClassTable *ct)
{
// TODO: add code here
}
#pragma endregion
#pragma region "CgenNode"
//
// Class setup. You may need to add parameters to this function so that
// the classtable can provide setup information (such as the class tag
// that should be used by this class).
//
// Things that setup should do:
// - layout the features of the class
// - create the types for the class and its vtable
// - create global definitions used by the class such as the class vtable
//
void CgenNode::setup(int const tag, int const depth)
{
if (cgen_debug)
std::cerr << "Setting up " << get_type_name() << "\n";
this->tag = tag;
auto* env = new CgenEnvironment(this);
layout_features();
this->make_vtable_type(env);
this->make_type_forrealz(env);
this->make_vtable_prototype(env);
if (cgen_debug) {
std::cerr << "\t";
this->type->print(errs(), true), errs() << "\n";
std::cerr << "\t";
this->vtable_type->print(errs(), true), errs() << "\n";
}
// need to declare an init function if it doesn't already exist
if (!basic())
class_table->create_function(get_init_function_name(), type->getPointerTo(), {}, GlobalValue::ExternalLinkage);
delete env;
}
// Laying out the features involves creating a Function for each method
// and assigning each attribute a slot in the class structure.
void CgenNode::layout_features()
{
// append parent's shit to our shit (so that the object methods come first)
if (parentnd && parentnd->get_type_name() != "_no_class") {
methods.insert(methods.end(), parentnd->methods.begin(), parentnd->methods.end());
attributes.insert(attributes.end(), parentnd->attributes.begin(), parentnd->attributes.end());
}
// the type for the class is declared when its CgenNode is installed
// so that other classes can be referenced when features are laid out
for (int i = features->first(); features->more(i); i = features->next(i))
features->nth(i)->layout_feature(this);
}
// Class codegen. This should performed after every class has been setup.
// Generate code for each method of the class.
void CgenNode::code_class()
{
// No code generation for basic classes. The runtime will handle that.
if (basic())
return;
if (cgen_debug)
std::cerr << "\n\nEmitting " + get_type_name() << "\n";
auto* env = new CgenEnvironment(this);
if (cgen_debug)
std::cerr << "Emitting methods\n";
for (auto [m, _]: methods) {
if (cgen_debug)
std::cerr << "\tEmitting " << m->qualified_name << "\n";
m->code(env);
}
this->code_init_function(env);
delete env;
}
void CgenNode::code_init_function(CgenEnvironment* env) const
{
assert(type != nullptr);
assert(vtable_type != nullptr);
assert(vtable != nullptr);
if (cgen_debug)
std::cerr << "Emitting constructor " << get_init_function_name() << "\n";
auto* init = env->the_module.getFunction(get_init_function_name());
assert(init);
auto* bb = BasicBlock::Create(env->context, "constructor", init);
auto* gbb = BasicBlock::Create(env->context, "alloc_success", init);
auto* abort = env->get_or_insert_abort_block(init);
env->builder.SetInsertPoint(bb);
// allocate space for ptr to type
assert(type->isSized());
auto* heap = env->builder.CreateCall(env->the_module.getFunction("malloc"), {
ConstantInt::get(i32,
env->data_layout.getTypeAllocSize(type))
});
Value* is_nullptr = env->builder.CreateICmpEQ(heap, ConstantPointerNull::get(ptr));
env->builder.CreateCondBr(is_nullptr, abort, gbb);
env->builder.SetInsertPoint(gbb);
auto* mem = env->insert_alloca_at_head(type->getPointerTo(), "n.mem");
env->builder.CreateStore(heap, mem);
auto* hptr = env->builder.CreateLoad(type->getPointerTo(), mem, "n.hptr");
env->builder.CreateStore(vtable, env->builder.CreateStructGEP(type, hptr, 0, "n.set_vtbl"));
// create a fake self pointer in case any methods are called during init
env->open_scope();
env->add_binding(self, mem);
for (int i = 0; i < attributes.size(); ++i) {
auto* val = attributes.at(i).first->code(env); // code attrs here so that we can conform them as needed
auto* attrptr = env->builder.CreateStructGEP(type, hptr, i + 1, "n.attrptr_" + attributes.at(i).first->get_name()->get_string());
// make sure we default init
if (val == ConstantPointerNull::get(env->ptr))
env->builder.CreateStore(env->conform(env->default_value(attributes.at(i).second), env->ptr), attrptr);
else
env->builder.CreateStore(env->conform(val, env->ptr), attrptr);
}
env->close_scope();
env->builder.CreateRet(env->builder.CreateLoad(type->getPointerTo(), mem));
}
void CgenNode::make_vtable_type(CgenEnvironment *env)
{
assert(vtable_type == nullptr);
vtable_type = StructType::create(this->ctx, std::string{"_"} + name->get_string() + "_vtable");
if (cgen_debug)
std::cerr << "Creating vtable type\n";
// tag, size, ptr to name
std::vector<Type*> vtable_elems{
i32, i32,
ptr
};
for (auto [_, t] : methods)
vtable_elems.emplace_back(t->getPointerTo());
vtable_type->setBody(vtable_elems);
assert(vtable_type != nullptr);
}
void CgenNode::make_type_forrealz(CgenEnvironment *env)
{
assert(type != nullptr);
assert(vtable_type != nullptr);
std::vector<Type *> type_elems{vtable_type->getPointerTo()};
type_elems.reserve(attributes.size() + 1);
// prior art: clang codegen record / cxxRecord
if (cgen_debug)
std::cerr << "Creating type\n";
for (auto [_, i] : attributes) {
type_elems.emplace_back(env->ptr); // we always box everything
}
type->setBody(type_elems);
}
void CgenNode::make_vtable_prototype(CgenEnvironment *env)
{
assert(vtable_type != nullptr);
assert(vtable == nullptr);
// Build global with vtable
if (cgen_debug)
std::cerr << "Emitting vtable " << get_vtable_name() << "\n";
using me = std::pair<method_class*, FunctionType*>;
auto methods = map<me, Constant*>(this->methods,
[this](me fn) -> Constant* {
auto f = this->class_table->the_module.getFunction(fn.first->qualified_name);
assertm(f, ("Couldn't find " + fn.first->qualified_name).c_str());
return f;
});
auto* str = env->builder.CreateGlobalStringPtr(get_type_name(), name->get_string() + "_str", 0, &env->the_module);
assert(type->isSized());
std::vector consts{ConstantInt::get(i32, tag), ConstantInt::get(i32,
env->data_layout.getTypeAllocSize(type)),
str,
};
consts.insert(consts.end(), methods.begin(), methods.end());
auto* cstrct = ConstantStruct::get(vtable_type, {consts});
vtable = new GlobalVariable(env->the_module, this->vtable_type, true, GlobalValue::ExternalLinkage,
cstrct, get_vtable_name());
assert(vtable != nullptr);
}
void CgenNode::make_debug_type(CgenEnvironment* env)
{
auto scope = class_table->di_cu;
auto name = get_type_name();
auto file = class_table->di_file;
auto line_num = this->name->get_index();
auto size_in_bits = env->data_layout.getTypeSizeInBits(type);
auto align_in_bits = env->data_layout.getABITypeAlign(type).value();
auto offset_in_bits = 0;
auto flags = DINode::FlagZero;
DIType* derived_from = nullptr;
if (parentnd && parentnd->get_type_name() != "_no_class")
derived_from = parentnd->dtype;
auto elements = di_builder.getOrCreateArray(dfeats);
this->dtype = di_builder.createClassType(scope, name, file, line_num,
size_in_bits, align_in_bits, offset_in_bits, flags, derived_from,
elements);
}
void CgenNode::premake_debug_type()
{
auto scope = class_table->di_cu;
auto name = get_type_name();
auto file = class_table->di_file;
auto line_num = this->name->get_index();
auto size_in_bits = 0;
auto align_in_bits = 0;
auto offset_in_bits = 0;
auto flags = DINode::FlagZero;
DIType* derived_from = nullptr;
auto elements = di_builder.getOrCreateArray(dfeats);
this->dtype = di_builder.createClassType(scope, name, file, line_num,
size_in_bits, align_in_bits, offset_in_bits, flags, derived_from,
elements);
}
#pragma endregion
#pragma region "CgenEvironment"
// Look up a CgenNode given a symbol
CgenNode* CgenEnvironment::type_to_class(Symbol t) const
{
return t == SELF_TYPE
? get_class()
: get_class()->get_classtable()->find_in_scopes(t);
}
BasicBlock* CgenEnvironment::get_or_insert_abort_block(Function* f)
{
for (auto &bb: *f) {
if (bb.getName() == "abort") {
return &bb;
}
}
auto* abort_bb = BasicBlock::Create(this->context, "abort", f);
Type* void_ = Type::getVoidTy(this->context);
IRBuilder<> builder(abort_bb);
FunctionCallee abort = this->the_module.getOrInsertFunction("abort", void_);
builder.CreateCall(abort, {});
builder.CreateUnreachable();
return abort_bb;
}
std::optional<Value*> CgenEnvironment::find_if_exists(Symbol name) const
{
if (auto* f = vars.find_in_scopes(name)) {
return std::make_optional(f);
}
return std::nullopt;
}
std::pair<Type*, Value*> CgenEnvironment::find_in_scopes(Symbol name) const
{
// Value* val;
// if (name->get_string() == "self")
// val = vars.find_in_scopes(self);
// else
// val = vars.find_in_scopes(name);
// TODO: will there be an issue if there is a self that doesn't have an indentical index as the self global?
auto val = find_if_exists(name);
assertm(val, ("Variable " + name->get_string() + " not found").c_str());
return resolve_opaque(*val);
}
AllocaInst* CgenEnvironment::insert_alloca_at_head(Type* ty)
{
BasicBlock &entry_bb = builder.GetInsertBlock()->getParent()->
getEntryBlock();
if (entry_bb.empty()) {
// Insert "at the end" of this bb
return new AllocaInst(ty, 0, "", &entry_bb);
} else {
// Insert before the first instruction of this bb
return new AllocaInst(ty, 0, "", &entry_bb.front());
}
}
AllocaInst* CgenEnvironment::insert_alloca_at_head(Type* ty, Twine const &msg)
{
assert(builder.GetInsertBlock());
BasicBlock &entry_bb = builder.GetInsertBlock()->getParent()->
getEntryBlock();
if (entry_bb.empty()) {
// Insert "at the end" of this bb
return new AllocaInst(ty, 0, msg, &entry_bb);
} else {
// Insert before the first instruction of this bb
return new AllocaInst(ty, 0, msg, &entry_bb.front());
}
}
Type* CgenEnvironment::as_type(Symbol const s) const
{
auto const _s = as_string(s);
if (_s == "Int" || _s == "int" /* prim int */) return i32;
if (_s == "Bool" || _s == "bool" /* prim bool */) return i1;
if (_s == "sbyte*" /* prim string */) return ptr;
return this->type_to_class(s)->type;
}
Type* CgenEnvironment::as_mostly_boxed_type(Symbol const s) const
{
auto const _s = as_string(s);
if (_s == "Int" || _s == "int" /* prim int */) return i32;
if (_s == "Bool" || _s == "bool" /* prim bool */) return i1;
return ptr;
}
DIType* CgenEnvironment::as_boxed_dtype(Symbol s) const
{
auto const _s = as_string(s);
// if (_s == "Int" || _s == "int" /* prim int */) return class_table.di32;
// if (_s == "Bool" || _s == "bool" /* prim bool */) return class_table.di1;
// return class_table.di_builder.createPointerType(type_to_class(s)->dtype, 64);
// return type_to_class(s)->dtype;
return class_table.dptr;
}
Value* CgenEnvironment::default_value(Type* ty) const
{
if (ty->isIntegerTy())
switch (ty->getIntegerBitWidth()) {
case 1: return builder.getFalse();
case 32: return builder.getInt32(0);
default: llvm_unreachable(
"Unhandled integer bit with");
}
if (ty->isStructTy() && ty->getStructName() == "String")
return builder.CreateGlobalString("");
return ConstantPointerNull::get(ptr);
}
Value* CgenEnvironment::conform(Value* src, Type* dest_type)
{
Type* src_type = src->getType();
if (src_type == dest_type)
return src;
if (src_type->isPointerTy() && dest_type->isPointerTy())
return src;
if (src_type->isIntegerTy() && dest_type->isIntegerTy()) {
return builder.CreateZExtOrTrunc(src, dest_type);
}
// box to Int or Bool
if (src_type->isIntegerTy() && dest_type->isPointerTy()) {
// if (cgen_debug) errs() << "\t\t\t\tBoxing ", src->print(errs(), true), errs() << " to object\n";
switch (src_type->getIntegerBitWidth()) {
case 1: {
auto* bool_new = the_module.getFunction("Bool_new");
assert(bool_new);
auto* bool_init = the_module.getFunction("Bool_init");
assert(bool_init);
// allocate storage for ptr to Bool
auto* r = insert_alloca_at_head(ptr, "box.i1");
// create a new Bool
auto* b = builder.CreateCall(bool_new->getFunctionType(), bool_new, {});
// store the ptr to the bool so we can return it later
builder.CreateStore(b, r);
// upconvert to a cbool
auto* c = builder.CreateZExt(src, i8);
// initalize the bool
auto* bptr1 = builder.CreateLoad(ptr, r);
builder.CreateCall(bool_init->getFunctionType(), bool_init, {bptr1, c});
// return the initalized bool
return builder.CreateLoad(ptr, r, "boxed.i1");
}
case 32: {
auto* int_new = the_module.getFunction("Int_new");
assert(int_new);
auto* int_init = the_module.getFunction("Int_init");
assert(int_init);
// allocate storage for ptr to Int
auto* r = insert_alloca_at_head(ptr, "box.i32");
// create a new Int
auto* b = builder.CreateCall(int_new->getFunctionType(), int_new, {});
// store the ptr to the int so we can return it later
builder.CreateStore(b, r);
// initalize the int
auto* iptr1 = builder.CreateLoad(ptr, r);
builder.CreateCall(int_init->getFunctionType(), int_init, {iptr1, src});
// return the initalized int
return builder.CreateLoad(ptr, r, "boxed.i32");
}
default: llvm_unreachable("Unsupported integer width to conform to");
}
}
// rawdog a gep and hope for the best
if (src_type->isPointerTy() && dest_type->isIntegerTy()) {
// if (cgen_debug) errs() << "\t\t\t\tUnboxing ", src->print(errs(), true), errs() << " to prim\n";
auto* ptr = builder.CreateStructGEP(type_to_class(Int)->type, src, 1, "unboxedptr");
return builder.CreateLoad(dest_type, ptr, "unboxed");
}
errs() << "Source ty: ", src_type->print(errs(), true), errs() << "\n";
errs() << "Dest ty: ", dest_type->print(errs(), true), errs() << "\n";
llvm_unreachable("Couldn't conform types");
}
#pragma endregion
/*********************************************************************
APS class methods
Fill in the following methods to produce code for the
appropriate expression. You may add or remove parameters
as you wish, but if you do, remember to change the parameters
of the declarations in `cool-tree.handcode.h'.
*********************************************************************/
void program_class::cgen(const std::optional<std::string> &outfile)
{
initialize_constants();
class_table = new CgenClassTable(classes);
if (outfile) {
std::error_code err;
raw_fd_ostream s(*outfile, err, sys::fs::FA_Write);
if (err) {
std::cerr << "Cannot open output file " << *outfile << std::endl;
exit(1);
}
s << class_table->the_module;
} else {
outs() << class_table->the_module;
}
}
// Create a method body
Value* method_class::code(CgenEnvironment* env)
{
if (env->get_class()->get_type_name() != split(qualified_name, '_').first)
return nullptr;
if (cgen_debug) {
std::cerr << "\t\tmethod" << std::endl;
}
env->open_scope();
auto* bb = BasicBlock::Create(env->context, "entry", fn);
env->builder.SetInsertPoint(bb);
// name and bind function args
assert(fn->arg_size() == formals->len() + 1);
for (auto* arg = fn->arg_begin(); arg != fn->arg_end(); ++arg) {
int idx = arg->getArgNo();
// store arg
auto* arg_ptr = env->insert_alloca_at_head(arg->getType());
env->builder.CreateStore(arg, arg_ptr);
// name and bind arg
if (0 == idx) {
arg->setName("self");
env->add_binding(self, arg_ptr);
} else {
auto* name = formals->nth(idx - 1)->get_name();
arg->setName(name->get_string());
env->add_binding(name, arg_ptr);
}
}
env->open_scope(); // body can redef args
Value* val = expr->code(env);
env->builder.CreateRet(env->conform(val, fn->getFunctionType()->getReturnType()));
env->close_scope();
env->close_scope();
return fn;
}
// Codegen for expressions. Note that each expression has a value.
Value* assign_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tassign" << std::endl;
Value* r = expr->code(env);
if (auto ptr = env->find_if_exists(name)) {
auto [ty, val] = resolve_opaque(*ptr);
env->builder.CreateStore(env->conform(r, ty), val, "a.local");
return r;
}
// since we are here, it must be a class attribute
assert(env->get_class()->type->getNumElements() > 1);
auto attrs = env->get_class()->attributes;
for (int i = 0; i < attrs.size(); ++i)
if (attrs.at(i).first->get_name() == name) {
// TODO: will this just check pointer equality, or is this a real comparision?
// emit a load to the element in self
auto [ty, val] = env->find_in_scopes(self);
auto* self = env->builder.CreateLoad(ty, val, "a.self");
// TODO: figure out how to resolve an actual self out of this properly
// hardcoding it for now
auto v = env->builder.CreateStructGEP(env->get_class()->type, self, 1 + i, "a.attrptr");
auto x = env->builder.CreateStore(env->conform(r, env->ptr), v, "a.attr");
return r;
}
llvm_unreachable(("Couldn't assign to " + name->get_string() + ", reference not found").c_str());
}
Value* cond_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tcond" << std::endl;
// allocate the result
auto* res = env->insert_alloca_at_head(env->as_mostly_boxed_type(type), "cond");
BasicBlock* startbb = env->builder.GetInsertBlock();
Function* fn = startbb->getParent();
// create basic blocks for the true and false branches
auto* truebb = BasicBlock::Create(env->context, "true", fn);
auto* falsebb = BasicBlock::Create(env->context, "false", fn);
// and a basic block for the result
auto* mergebb = BasicBlock::Create(env->context, "merge", fn);
// branch
env->builder.SetInsertPoint(startbb);
Value* cond = env->conform(pred->code(env), env->i1);
env->builder.CreateCondBr(cond, truebb, falsebb);
// emit true
env->builder.SetInsertPoint(truebb);
env->builder.CreateStore(then_exp->code(env), res);
env->builder.CreateBr(mergebb); // jump to merge to close bb
// emit false
env->builder.SetInsertPoint(falsebb);
env->builder.CreateStore(else_exp->code(env), res);
env->builder.CreateBr(mergebb); // jump to merge to close bb
// load and return result
env->builder.SetInsertPoint(mergebb);
return env->builder.CreateLoad(res->getAllocatedType(), res);
}
Value* loop_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tloop" << std::endl;
BasicBlock* startbb = env->builder.GetInsertBlock();
Function* fn = startbb->getParent();
// create basic blocks for conditional, loop, and end
auto* condbb = BasicBlock::Create(env->context, "conditional", fn);
auto* loopbb = BasicBlock::Create(env->context, "loop", fn);
auto* endbb = BasicBlock::Create(env->context, "end", fn);
// explicitly jump to conditional
env->builder.SetInsertPoint(startbb);
env->builder.CreateBr(condbb);
// emit conditional
env->builder.SetInsertPoint(condbb);
// check loop conditional
Value* cond = env->conform(pred->code(env), env->i1);
env->builder.CreateCondBr(cond, loopbb, endbb);
// emit loop
env->builder.SetInsertPoint(loopbb);
body->code(env);
// end bb by jumping to conditional
env->builder.CreateBr(condbb);
// emit end
env->builder.SetInsertPoint(endbb);
// loops return void
return ConstantPointerNull::get(env->ptr);
}
Value* block_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tblock" << std::endl;
return map<Expression, Value *>(unfuck(body),
[env](Expression const &e) -> Value* {
return e->code(env);
}).back();
}
Value* let_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\tlet" << std::endl;
auto* ty = env->as_mostly_boxed_type(type_decl);
// allocate let variable
auto* var_ptr = env->insert_alloca_at_head(ty, "let");
// store inital code to var_ptr
Value* initial_val = init->code(env);
if (!ConstantPointerNull::classof(initial_val))
env->builder.CreateStore(initial_val, var_ptr);
else // otherwise init with default value
env->builder.CreateStore(env->default_value(ty), var_ptr);
// bind memory location so the body can use it
env->open_scope();
env->add_binding(identifier, var_ptr);
// return result of the let expr
Value* r = body->code(env);
env->close_scope();
return r;
}
Value* plus_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tplus" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateAdd(r1, r2, "add");
}
Value* sub_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tsub" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateSub(r1, r2, "sub");
}
Value* mul_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tmul" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateMul(r1, r2, "mul");
}
Value* divide_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tdiv" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
auto* curbb = env->builder.GetInsertBlock();
auto* div = BasicBlock::Create(env->context, "div", curbb->getParent());
auto* abort = env->get_or_insert_abort_block(curbb->getParent());
env->builder.SetInsertPoint(curbb);
Value* is_zero = env->builder.CreateICmpEQ(env->builder.getInt32(0), r2);
env->builder.CreateCondBr(is_zero, abort, div);
env->builder.SetInsertPoint(div);
return env->builder.CreateSDiv(r1, r2, "div");
}
Value* neg_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tneg" << std::endl;
Value* r = env->conform(e1->code(env), env->i32);
return env->builder.CreateNeg(r, "neg");
}
Value* lt_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tlt" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateICmpSLT(r1, r2, "cmpl");
}
Value* eq_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\teq" << std::endl;
Value* r1 = e1->code(env);
Value* r2 = e2->code(env);
if (env->as_type(e1->get_type())->isIntegerTy() || env->as_type(e2->get_type())->isIntegerTy())
return env->builder.CreateICmpEQ(env->conform(r1, env->i32), env->conform(r2, env->i32));
return env->builder.CreateICmpEQ(r1, r2, "eq");
}
Value* leq_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tleq" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateICmpSLE(r1, r2, "leq");
}
Value* comp_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tcomplement" << std::endl;
Value* r = env->conform(e1->code(env), env->i1); // todo: check you can get an i32 here
return env->builder.CreateNot(r, "comp");
}
Value* int_const_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tint_const" << std::endl;
return env->builder.getInt32((uint32_t) std::stol(token->get_string()));
}
Value* bool_const_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tbool_const" << std::endl;
return env->builder.getInt1(this->val);
}
Value* object_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tobject" << std::endl;
if (auto f = env->find_if_exists(name)) {
auto [ty, val] = resolve_opaque(*f);
return env->builder.CreateLoad(ty, val, "o.local_" + name->get_string());
}
// since we are here, it must be a class attribute
assert(env->get_class()->type->getNumElements() > 1);
auto attrs = env->get_class()->attributes;
for (int i = 0; i < attrs.size(); ++i)
if (attrs.at(i).first->get_name() == name) {
// TODO: will this just check pointer equality, or is this a real comparision?
// emit a load to the element in self
auto [ty, val] = env->find_in_scopes(self);
auto* self = env->builder.CreateLoad(ty, val, "o.self");
// TODO: figure out how to resolve an actual self out of this properly
// hardcoding it for now
auto v = env->builder.CreateStructGEP(env->get_class()->type, self, 1 + i, "o.attrptr_" + name->get_string());
auto r = env->builder.CreateLoad(env->ptr, v, "o.attr_" + name->get_string());
return r;
}
llvm_unreachable(("Couldn't resolve a reference to " + name->get_string()).c_str());
}
Value* no_expr_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tno expr" << std::endl;
// emit a nullptr
return ConstantPointerNull::get(env->ptr);
}
//*****************************************************************
// The next few functions are for node types not supported in Phase 1
// but these functions must be defined because they are declared as
// methods via the Expression_SHARED_EXTRAS hack.
//*****************************************************************
Value* static_dispatch_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tstatic dispatch" << std::endl;
// evaluate args
auto args = map<Expression, Value*>(unfuck(actual), [env](Expression const& e) -> Value* {
return e->code(env);
});
// figure out the calling class
auto* caller_class = env->type_to_class(type_name);
auto* caller = expr->code(env);
// box prims
if (caller->getType()->isIntegerTy()) {
auto* orig = caller;
caller = env->conform(orig, env->ptr);
}
// sanity check caller
assert(caller->getType()->isPointerTy());
if (cgen_debug)
errs() << "\t\t\tLooking for " << as_string(name) << "\n";
// figure out method index into vtable
auto get_method_idx = [](CgenNode* cls, Symbol name) -> int {
auto methods = cls->methods;
// search in reverse so we get the overload instead of the original
for (int i = methods.size() - 1; i > 0; --i) {
if (methods.at(i).first->get_name() == name) {
return i;
}
}
llvm_unreachable(("Couldn't find " + as_string(name) + " in " + as_string(cls->get_name())).c_str());
};
int method_idx = get_method_idx(caller_class, name);
auto n = as_string(name);
auto* curbb = env->builder.GetInsertBlock();
auto* abort = env->get_or_insert_abort_block(curbb->getParent());
auto* validbb = BasicBlock::Create(env->context, "sdispatch_" + n, curbb->getParent());
// emit nulltpr check
env->builder.SetInsertPoint(curbb);
Value* is_nullptr = env->builder.CreateICmpEQ(caller, ConstantPointerNull::get(env->ptr));
env->builder.CreateCondBr(is_nullptr, abort, validbb);
// emit call global vtable if successful
env->builder.SetInsertPoint(validbb);
// get method's signature
auto* method_ty = caller_class->methods.at(method_idx).second;
// get pointer from vtable
Value* method_ptr = env->builder.CreateStructGEP(caller_class->vtable_type,
caller_class->vtable, method_idx + 3, "sd.mptr"); // first three elems of the vtable aren't methods
auto* method = env->builder.CreateLoad(method_ty->getPointerTo(), method_ptr, "sd." + n);
// build method args
std::vector real_args{caller};
real_args.reserve(1 + args.size());
for (int i = 0; i < args.size(); ++i) { // make sure args are unboxed as needed
real_args.emplace_back(env->conform(args.at(i), method_ty->getParamType(i + 1)));
}
// call method
return env->builder.CreateCall(method_ty, method, real_args);
}
Value* string_const_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tstring_const" << std::endl;
auto* e = stringtable.lookup_string(as_string(token));
auto* global = reinterpret_cast<StringEntry*>(e)->ptr;
return global;
}
Value* dispatch_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tdispatch\n" << std::endl;
// evaluate args
auto args = map<Expression, Value*>(unfuck(actual), [env](Expression const& e) -> Value* {
return e->code(env);
});
// figure out the calling class
auto* caller_class = env->type_to_class(expr->get_type());
Value* caller = expr->code(env);
// box prims
if (caller->getType()->isIntegerTy()) {
auto* orig = caller;
caller = env->conform(orig, env->ptr);
}
// sanity check caller
assert(caller->getType()->isPointerTy());
if (cgen_debug)
errs() << "\t\t\tLooking for " << as_string(name) << "\n";
// figure out method index into vtable
auto get_method_idx = [](CgenNode* cls, Symbol name) -> int {
auto methods = cls->methods;
// search in reverse so we get the overload instead of the original
for (int i = methods.size() - 1; i >= 0; --i) {
if (methods.at(i).first->get_name() == name) {
return i;
}
}
llvm_unreachable(("Couldn't find " + as_string(name) + " in " + as_string(cls->get_name())).c_str());
};
int method_idx = get_method_idx(caller_class, name);
auto n = as_string(name);
auto* curbb = env->builder.GetInsertBlock();
auto* abort = env->get_or_insert_abort_block(curbb->getParent());
auto* validbb = BasicBlock::Create(env->context, "dispatch_" + n, curbb->getParent());
// emit nulltpr check
env->builder.SetInsertPoint(curbb);
Value* is_nullptr = env->builder.CreateICmpEQ(caller, ConstantPointerNull::get(env->ptr));
env->builder.CreateCondBr(is_nullptr, abort, validbb);
// emit call through vtable if successful
env->builder.SetInsertPoint(validbb);
// get vtable ptr
auto* vtable_ptr = env->builder.CreateStructGEP(caller_class->type, caller, 0, "d.vtblptr");
// load vtable
auto* vtable = env->builder.CreateLoad(env->ptr, vtable_ptr, "d.vtbl");
// get method's signature
auto* method_ty = caller_class->methods.at(method_idx).second;
// get pointer from vtable
Value* method_ptr = env->builder.CreateStructGEP(caller_class->vtable_type,
vtable, method_idx + 3, "d.mptr"); // first three elems of the vtable aren't methods
auto* method = env->builder.CreateLoad(method_ty->getPointerTo(), method_ptr, "d." + n);
// build method args
std::vector real_args{caller};
real_args.reserve(1 + args.size());
for (int i = 0; i < args.size(); ++i) { // make sure args are unboxed as needed
// if (cgen_debug) errs() << "\t\t\t", method_ty->getParamType(i + 1)->print(errs(), true), errs() << " <- ", args.at(i)->print(errs(), true), errs() << "\n";
real_args.emplace_back(env->conform(args.at(i), method_ty->getParamType(i + 1)));
// if (cgen_debug) errs() << "\t\t\t", real_args.at(i + 1)->print(errs(), true), errs() << "\n";
assert(real_args.at(i + 1)->getType() == method_ty->getParamType(i + 1));
}
assert(real_args.size() == method_ty->getNumParams());
// call method
if (cgen_debug)
errs() << "\t\tend dispatch\n";
return env->builder.CreateCall(method_ty, method, real_args);
}
// Handle a Cool case expression (selecting based on the type of an object)
Value* typcase_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\ttype case" << std::endl;
auto e_class = env->type_to_class(expr->get_type());
auto sumty = env->type_to_class(type);
Value* e = expr->code(env);
// box prims
if (e->getType()->isIntegerTy()) {
auto* orig = e;
e = env->conform(orig, env->ptr);
}
assert(e->getType()->isPointerTy());
auto* curbb = env->builder.GetInsertBlock();
auto* abort = env->get_or_insert_abort_block(curbb->getParent());
auto* goodbb = BasicBlock::Create(env->context, "typcase.good", curbb->getParent());
auto* matchbb = BasicBlock::Create(env->context, "typcase.match", curbb->getParent());
auto* resbb = BasicBlock::Create(env->context, "typcase.result", curbb->getParent());
// emit void check
env->builder.SetInsertPoint(curbb);
auto* test = env->builder.CreateICmpEQ(e, ConstantPointerNull::get(env->ptr), "typcase.isvoid");
env->builder.CreateCondBr(test, abort, goodbb);
env->builder.SetInsertPoint(goodbb);
// get tag
auto* vtable_ptr = env->builder.CreateStructGEP(e_class->type, e, 0, "typcase.vtblptr");
auto* vtable = env->builder.CreateLoad(env->ptr, vtable_ptr, "typcase.vtbl");
auto* tag_ptr = env->builder.CreateStructGEP(e_class->vtable_type, vtable, 0, "typcase.tagptr");
auto* tag = env->builder.CreateLoad(env->i32, tag_ptr, "typcase.tag");
// stack slot for result, case is always boxed
auto* res = env->insert_alloca_at_head(env->ptr);
// store nullptr
env->builder.CreateStore(ConstantPointerNull::get(env->ptr), res);
// sort cases largest tag to smallest
std::vector<Case> branches;
branches.reserve(cases->len());
for (auto c: cases) {
branches.emplace_back(c);
}
std::sort(branches.begin(), branches.end(), [env](Case a, Case b) {
return env->type_to_class(a->get_type_decl())->get_tag() > env->type_to_class(b->get_type_decl())->get_tag();
});
std::for_each(branches.begin(), branches.end(), [env, e, tag, res, matchbb](Case c) {
c->code(e, tag, res, matchbb, env);
});
// abort if no match
env->builder.CreateBr(abort);
env->builder.SetInsertPoint(matchbb);
// test if result is null
auto* r = env->builder.CreateLoad(env->ptr, res, "typcase.res");
auto* test_res = env->builder.CreateICmpEQ(r, ConstantPointerNull::get(env->ptr), "typcase.res.isvoid");
env->builder.CreateCondBr(test_res, abort, resbb);
// clean up
env->builder.SetInsertPoint(resbb);
return r;
}
Value* new__class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tnew" << std::endl;
// return nullptr;
auto init = env->type_to_class(type_name)->get_init_function_name();
auto* initfn = env->the_module.getFunction(init);
assert(initfn);
return env->builder.CreateCall(initfn->getFunctionType(), initfn, {});
}
Value* isvoid_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tisvoid" << std::endl;
Value* e = e1->code(env);
if (e->getType()->isIntegerTy())
return env->builder.getTrue();
assert(e->getType()->isPointerTy());
auto* ret = env->insert_alloca_at_head(env->i1);
auto* curbb = env->builder.GetInsertBlock();
auto* truebb = BasicBlock::Create(env->context, "isvoid.true", curbb->getParent());
auto* falsebb = BasicBlock::Create(env->context, "isvoid.false", curbb->getParent());
auto* mergebb = BasicBlock::Create(env->context, "isvoid.result", curbb->getParent());
env->builder.SetInsertPoint(curbb);
auto* test = env->builder.CreateICmpEQ(e, ConstantPointerNull::get(env->ptr), "isvoid");
env->builder.CreateCondBr(test, truebb, falsebb);
env->builder.SetInsertPoint(truebb);
env->builder.CreateStore(env->builder.getTrue(), ret);
env->builder.CreateBr(mergebb);
env->builder.SetInsertPoint(falsebb);
env->builder.CreateStore(env->builder.getFalse(), ret);
env->builder.CreateBr(mergebb);
env->builder.SetInsertPoint(mergebb);
return env->builder.CreateLoad(env->i1, ret);
}
// Record the method
void method_class::layout_feature(CgenNode* cls)
{
// if (cls->basic())
// return; // handled by the runtime
auto* env = new CgenEnvironment(cls);
assert(qualified_name.empty());
qualified_name = cls->get_type_name() + "_" + this->get_name()->get_string();
std::vector<Type*> real_args;
real_args.reserve(formals->len() + 1);
real_args.emplace_back(env->ptr); // first arg is always self ptr
auto _formals = unfuck(formals);
auto args = map<Formal, Type *>(_formals,
[env](Formal const &f) -> Type* {
return env->as_mostly_boxed_type(f->get_type_decl());
});
real_args.insert(real_args.end(), args.begin(), args.end());
// real function
auto* ty = CgenNode::create_functionty(env->as_mostly_boxed_type(return_type), real_args);
fn = cls->create_function(as_string(get_name()), ty);
#ifdef EMIT_DBG
if (!cls->basic()) {
// debug function type
std::vector<Metadata*> dtys;
dtys.emplace_back(env->as_boxed_dtype(return_type));
for (auto f: _formals)
dtys.emplace_back(env->as_boxed_dtype(f->get_type_decl()));
auto dty = cls->di_builder.createSubroutineType(cls->di_builder.getOrCreateTypeArray(dtys));
auto dfn = cls->di_builder.createFunction(env->class_table.di_cu, this->get_name()->get_string(), cls->get_type_name() + "_" + this->get_name()->get_string(), env->class_table.di_file, this->get_name()->get_index(), dty,this->get_name()->get_index(), DINode::FlagPrototyped, DISubprogram::SPFlagDefinition);
fn->setSubprogram(dfn);
cls->dfeats.emplace_back(dfn);
}
#endif
cls->methods.emplace_back(this, ty);
delete env;
}
// Handle one branch of a Cool case expression.
// If the source tag is >= the branch tag
// and <= (max child of the branch class) tag,
// then the branch is a superclass of the source.
// See the LAB2 handout for more information about our use of class tags.
void branch_class::code(Value* expr_val, Value* tag, Value* mem, BasicBlock* sbb, CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tbranch\n";
auto cls = env->type_to_class(type_decl);
int start_tag = cls->get_tag();
int end_tag = cls->get_max_child();
auto* curbb = env->builder.GetInsertBlock();
auto* maxbb = BasicBlock::Create(env->context, "typcase.br.match.max." + name->get_string(), curbb->getParent());
auto* minbb = BasicBlock::Create(env->context, "typcase.br.match.min." + name->get_string(), curbb->getParent());
auto* endbb = BasicBlock::Create(env->context, "typcase.br.nomatch." + name->get_string(), curbb->getParent());
env->builder.SetInsertPoint(curbb);
// test min tag first, since we test largest to smallest cases
auto* mintest = env->builder.CreateICmpSGE(tag, ConstantInt::get(env->i32, start_tag, true), "typcase.br.min." + name->get_string());
env->builder.CreateCondBr(mintest, minbb, endbb);
env->builder.SetInsertPoint(minbb);
// test max tag
auto* maxtest = env->builder.CreateICmpSLE(tag, ConstantInt::get(env->i32, end_tag, true), "typcase.br.max." + name->get_string());
env->builder.CreateCondBr(maxtest, maxbb, endbb);
env->builder.SetInsertPoint(maxbb);
auto* branchptr = env->insert_alloca_at_head(env->ptr);
env->builder.CreateStore(expr_val, branchptr);
env->open_scope(); // eval branch with new scope
env->add_binding(name, branchptr);
auto* res = expr->code(env);
env->close_scope();
// store into result
env->builder.CreateStore(res, mem);
env->builder.CreateBr(sbb);
env->builder.SetInsertPoint(endbb);
}
// Assign this attribute a slot in the class structure
void attr_class::layout_feature(CgenNode* cls)
{
auto* env = new CgenEnvironment(cls);
auto ty = env->as_mostly_boxed_type(type_decl);
cls->attributes.emplace_back(this, ty);
#ifdef EMIT_DBG
// build debug info
cls->dfeats.emplace_back(env->as_boxed_dtype(type_decl));
#endif
delete env;
}
Value* attr_class::code(CgenEnvironment* env)
{
val = init->code(env);
// return env->conform(val, env->ptr);
return val;
}
#pragma region "utils"
namespace
{
std::string as_string(Symbol const s)
{
return s->get_string();
}
std::vector<Expression> unfuck(Expressions const fuck_this)
{
std::vector<Expression> r{};
r.reserve(fuck_this->len());
for (int i = fuck_this->first(); fuck_this->more(i); i = fuck_this->next(i))
r.push_back(fuck_this->nth(i));
return r;
}
std::vector<Formal> unfuck(Formals const fuck_this)
{
std::vector<Formal> r{};
r.reserve(fuck_this->len());
for (int i = fuck_this->first(); fuck_this->more(i); i = fuck_this->next(i))
r.push_back(fuck_this->nth(i));
return r;
}
std::vector<Feature> unfuck(Features const fuck_this)
{
std::vector<Feature> r{};
r.reserve(fuck_this->len());
for (int i = fuck_this->first(); fuck_this->more(i); i = fuck_this->next(i))
r.push_back(fuck_this->nth(i));
return r;
}
std::pair<Type*, Value*> resolve_opaque(Value* val)
{
// TODO: resolve malloced things
if (auto* a = dyn_cast<AllocaInst>(val))
return {a->getAllocatedType(), val};
if (auto* g = dyn_cast<GlobalVariable>(val))
return {g->getValueType(), val};
if (auto* s = dyn_cast<GetElementPtrInst>(val))
return {s->getSourceElementType(), val};
errs() << "Unresolved opaque value: ", val->print(errs(), true), errs() << "\n";
llvm_unreachable("couldn't get original type for value");
}
template<class T, class R>
std::vector<R> map(std::vector<T> src, std::function<R(T const &)> mapper)
{
std::vector<R> r{};
r.reserve(src.size());
for (auto i: src)
r.emplace_back(mapper(i));
return r;
}
std::pair<std::string, std::string> split(const std::string& s, char const c)
{
size_t pos = s.find(c);
if (pos == std::string::npos)
return {s, ""};
return {s.substr(0, pos), s.substr(pos + 1)};
}
}
#pragma endregion
/*
* This file provides the runtime library for cool. It implements
* the cool classes in C. Feel free to change it to match the structure
* of your code generator.
*/
#include <stdbool.h>
#if defined _MSC_VER && !defined __clang__
#define __attribute(...)
#endif
typedef struct Object Object;
typedef struct Int Int;
typedef struct Bool Bool;
typedef struct String String;
typedef struct IO IO;
typedef struct _Object_vtable Object_vtable;
typedef struct _Int_vtable Int_vtable;
typedef struct _Bool_vtable Bool_vtable;
typedef struct _String_vtable String_vtable;
typedef struct _IO_vtable IO_vtable;
/* class type definitions */
struct Object {
const Object_vtable *vtblptr;
};
struct Int {
const Int_vtable *vtblptr;
int val;
};
struct Bool {
const Bool_vtable *vtblptr;
bool val;
};
struct String {
const String_vtable *vtblptr;
const char *val;
};
struct IO {
const IO_vtable *vtblptr;
};
/* vtable type definitions */
struct _Object_vtable {
int tag;
int size;
const char *name;
Object *(*abort_object)(Object *self);
String *(*type_name_object)(Object *self);
Object *(*copy_object)(Object *self);
};
struct _Int_vtable {
int tag;
int size;
const char *name;
Object *(*abort_int)(Object *self);
String *(*type_name_int)(Object *self);
Object *(*copy_int)(Object *self);
};
struct _Bool_vtable {
int tag;
int size;
const char *name;
Object *(*abort_bool)(Object *self);
String *(*type_name_bool)(Object *self);
Object *(*copy_bool)(Object *self);
};
struct _String_vtable {
int tag;
int size;
const char *name;
Object *(*abort_string)(Object *self);
String *(*type_name_string)(Object *self);
Object *(*copy_string)(Object *self);
int (*length_string)(String *self);
String *(*concat_string)(String *self, String *s);
String *(*substr_string)(String *self, int i, int l);
};
struct _IO_vtable {
int tag;
int size;
const char *name;
Object *(*abort_io)(Object *self);
String *(*type_name_io)(Object *self);
Object *(*copy_io)(Object *self);
IO *(*out_string_io)(IO *self, String *s);
IO *(*out_int_io)(IO *self, int x);
String *(*in_string_io)(IO *self);
int (*in_int_io)(IO *self);
};
/* Class vtable prototypes */
extern const Object_vtable _Object_vtable_prototype;
extern const Int_vtable _Int_vtable_prototype;
extern const Bool_vtable _Bool_vtable_prototype;
extern const String_vtable _String_vtable_prototype;
extern const IO_vtable _IO_vtable_prototype;
/* methods in class Object */
Object *Object_new(void);
Object *Object_abort(Object *self) __attribute((noreturn));
String *Object_type_name(Object *self);
Object *Object_copy(Object *self);
/* methods in class Int */
Int *Int_new(void);
void Int_init(Int *self, int i);
/* methods in class Bool */
Bool *Bool_new(void);
void Bool_init(Bool *self, bool b);
/* methods in class String */
String *String_new(void);
int String_length(String *self);
String *String_concat(String *self, String *s);
String *String_substr(String *self, int i, int l);
/* methods in class IO */
IO *IO_new(void);
IO *IO_out_string(IO *self, String *s);
IO *IO_out_int(IO *self, int x);
String *IO_in_string(IO *self);
int IO_in_int(IO *self);
#include "coolrt.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* This file provides the runtime library for cool. It implements
the functions of the cool classes in C
*/
/* Class name strings */
const char Object_string[] = "Object";
const char Int_string[] = "Int";
const char Bool_string[] = "Bool";
const char String_string[] = "String";
const char IO_string[] = "IO";
const char default_string[] = "";
/* Class vtable prototypes */
/*
const Object_vtable _Object_vtable_prototype = {
.tag = 0,
.size = sizeof(struct Object),
.name = Object_string,
.abort_object = Object_abort,
.type_name_object = Object_type_name,
.copy_object = Object_copy
};
const Int_vtable _Int_vtable_prototype = {
.tag = 1,
.size = sizeof(struct Int),
.name = Int_string,
.abort_int = Object_abort,
.type_name_int = Object_type_name,
.copy_int = Object_copy
};
const Bool_vtable _Bool_vtable_prototype = {
.tag = 2,
.size = sizeof(struct Bool),
.name = Bool_string,
.abort_bool = Object_abort,
.type_name_bool = Object_type_name,
.copy_bool = Object_copy
};
const String_vtable _String_vtable_prototype = {
.tag = 3,
.size = sizeof(struct String),
.name = String_string,
.abort_string = Object_abort,
.type_name_string = Object_type_name,
.copy_string = Object_copy,
.length_string = String_length,
.concat_string = String_concat,
.substr_string = String_substr
};
const IO_vtable _IO_vtable_prototype = {
.tag = 4,
.size = sizeof(struct IO),
.name = IO_string,
.abort_io = Object_abort,
.type_name_io = Object_type_name,
.copy_io = Object_copy,
.out_string_io = IO_out_string,
.out_int_io = IO_out_int,
.in_string_io = IO_in_string,
.in_int_io = IO_in_int
};
*/
/*
// Methods in class object (only some are provided to you)
*/
Object* Object_new()
{
Object* o = (Object *) malloc(sizeof(Object));
if (o == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
o->vtblptr = &_Object_vtable_prototype;
return o;
}
Object* Object_abort(Object* self)
{
printf("Abort called from class %s\n",
!self ? "Unknown" : self->vtblptr->name);
exit(1);
return self;
}
String* Object_type_name(Object* self)
{
if (self == 0) {
fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
abort();
}
String* s = String_new();
s->val = self->vtblptr->name;
return s;
}
Object* Object_copy(Object* self)
{
if (self == 0) {
fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
abort();
}
unsigned size = self->vtblptr->size;
assert(size > 0);
Object* obj = (Object *) malloc(size);
if (obj == 0) {
fprintf(stderr, "At %s(line %d): malloc failed in Object::copy()\n",
__FILE__, __LINE__);
abort();
}
memcpy(obj, self, size);
return obj;
}
/*
// Methods in class IO (only some are provided to you)
*/
IO* IO_new()
{
IO* io = (IO *) malloc(sizeof(IO));
if (io == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
io->vtblptr = &_IO_vtable_prototype;
return io;
}
IO* IO_out_string(IO* self, String* s)
{
if (self == 0 || s == 0) {
fprintf(stderr, "At %s(line %d): NULL object\n", __FILE__, __LINE__);
abort();
}
printf("%s", s->val);
return self;
}
IO* IO_out_int(IO* self, int x)
{
if (self == 0) {
fprintf(stderr, "At %s(line %d): NULL object\n", __FILE__, __LINE__);
abort();
}
printf("%d", x);
return self;
}
/*
* Get one line from stream using get_line(), then discard newline character.
* Allocate string *in_string_p and store result there.
* Return number of chars read.
*/
static int get_one_line(char** in_string_p, FILE* stream)
{
/* Get one line worth of input */
size_t len = 0;
ssize_t num_chars_read;
num_chars_read = getline(in_string_p, &len, stdin);
if (*in_string_p == 0) {
fprintf(
stderr, "At %s(line %d): allocation failed in IO::in_string()\n",
__FILE__, __LINE__);
exit(1);
}
/* Discard the newline char, if any. It may not exist if EOF reached. */
if (num_chars_read > 0 && (*in_string_p)[num_chars_read - 1] == '\n') {
(*in_string_p)[num_chars_read - 1] = '\0';
--len;
}
return len;
}
/*
* The method IO::in_string(): String reads a string from
* the standard input, up to but not including a newline character.
*/
String* IO_in_string(IO* self)
{
if (self == 0) {
fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
abort();
}
/* Get one line worth of input with the newline, if any, discarded */
char* in_string = 0;
ssize_t len = get_one_line(&in_string, stdin);
assert(in_string);
/* We can take advantage of knowing the internal layout of String objects */
String* str = String_new();
str->val = in_string;
return str;
}
/*
* The method IO::in_int(): Int reads a single integer, which may be preceded
* by whitespace.
* Any characters following the integer, up to and including the next newline,
* are discarded by in_int.
*/
int IO_in_int(IO* self)
{
if (self == 0) {
fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
abort();
}
/* Get one line worth of input with the newline, if any, discarded */
char* in_string = 0;
ssize_t len = get_one_line(&in_string, stdin);
assert(in_string);
/* Now extract initial int and ignore the rest of the line */
int x;
int num_ints = 0;
if (len)
/* Discards initial spaces*/
num_ints = sscanf(in_string, " %d", &x);
/* If no text found, abort. */
if (num_ints == 0) {
fprintf(stderr,
"At %s(line %d): Invalid integer on input in IO::in_int()\n",
__FILE__, __LINE__);
Object_abort((Object *) self);
}
return x;
}
/*
// Methods in class Int
*/
Int* Int_new()
{
Int* x = (Int *) malloc(sizeof(Int));
if (x == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
x->vtblptr = &_Int_vtable_prototype;
x->val = 0;
return x;
}
void Int_init(Int* self, int i) { self->val = i; }
/*
// Methods in class Bool
*/
Bool* Bool_new()
{
Bool* b = (Bool *) malloc(sizeof(Bool));
if (b == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
b->vtblptr = &_Bool_vtable_prototype;
b->val = false;
return b;
}
void Bool_init(Bool* self, bool b) { self->val = b; }
/*
// Methods in class String
*/
String* String_new()
{
String* s = (String *) malloc(sizeof(String));
if (s == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
s->vtblptr = &_String_vtable_prototype;
s->val = "";
return s;
}
int String_length(String* self)
{
if (self == 0) {
fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
abort();
}
return strlen(self->val);
}
String* String_concat(String* self, String* s)
{
if (self == 0 || s == 0) {
fprintf(stderr, "At %s(line %d): NULL object\n", __FILE__, __LINE__);
abort();
}
String* s1 = (String *) malloc(sizeof(String));
if (s1 == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
s1->vtblptr = &_String_vtable_prototype;
char* cats = (char *) malloc(strlen(self->val) + strlen(s->val) + 1);
if (cats == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
strcpy(cats, self->val);
strcat(cats, s->val);
s1->val = cats;
return s1;
}
String* String_substr(String* self, int i, int l)
{
if (self == 0) {
fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
abort();
}
int len = strlen(self->val);
if (i >= len || i + l - 1 >= len) {
fprintf(stderr, "At %s(line %d): Substring out of range\n", __FILE__,
__LINE__);
Object_abort((Object *) 0);
}
String* s1 = (String *) malloc(sizeof(String));
if (s1 == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
s1->vtblptr = &_String_vtable_prototype;
char* subs = (char *) malloc(l + 1);
if (subs == 0) {
fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
Object_abort((Object *) 0);
}
strncpy(subs, &(self->val[i]), l);
subs[l] = '\0';
s1->val = subs;
return s1;
}
//
// Created by isaac on 2/18/2024.
//
#ifdef _WIN32
#ifndef UNISTD_H
#define UNISTD_H
#include <stdlib.h>
#include <io.h>
#include <getopt.h>
#include <process.h> /* for getpid() and the exec..() family */
#include <direct.h> /* for _getcwd() and _chdir() */
#define srandom srand
#define random rand
/* Values for the second argument to access.
These may be OR'd together. */
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
//#define X_OK 1 /* execute permission - unsupported in windows*/
#define F_OK 0 /* Test for existence. */
#define access _access
#define dup2 _dup2
#define execve _execve
#define ftruncate _chsize
#define unlink _unlink
#define fileno _fileno
#define getcwd _getcwd
#define chdir _chdir
#define isatty _isatty
#define lseek _lseek
/* read, write, and close are NOT being #defined here, because while there are file handle specific versions for Windows, they probably don't work for sockets. You need to look at your app and consider whether to call e.g. closesocket(). */
#ifdef _WIN64
#define ssize_t __int64
#else
#define ssize_t long
#endif
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
/* should be in some equivalent to <sys/types.h> */
// typedef __int8 int8_t;
// typedef __int16 int16_t;
// typedef __int32 int32_t;
// typedef __int64 int64_t;
// typedef unsigned __int8 uint8_t;
// typedef unsigned __int16 uint16_t;
// typedef unsigned __int32 uint32_t;
// typedef unsigned __int64 uint64_t;
#endif //UNISTD_H
#endif //WIN32
#ifndef __GETOPT_H__
/**
* DISCLAIMER
* This file has no copyright assigned and is placed in the Public Domain.
* This file is a part of the w64 mingw-runtime package.
*
* The w64 mingw-runtime package and its code is distributed in the hope that it
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#define __GETOPT_H__
/* All the headers include this file. */
#include <crtdefs.h>
#if defined( WINGETOPT_SHARED_LIB )
# if defined( BUILDING_WINGETOPT_DLL )
# define WINGETOPT_API __declspec(dllexport)
# else
# define WINGETOPT_API __declspec(dllimport)
# endif
#else
# define WINGETOPT_API
#endif
#ifdef __cplusplus
extern "C" {
#endif
WINGETOPT_API extern int optind; /* index of first non-option in argv */
WINGETOPT_API extern int optopt; /* single option character, as parsed */
WINGETOPT_API extern int opterr; /* flag to enable built-in diagnostics... */
/* (user may set to zero, to suppress) */
WINGETOPT_API extern char *optarg; /* pointer to argument of current option */
extern int getopt(int nargc, char * const *nargv, const char *options);
#ifdef _BSD_SOURCE
/*
* BSD adds the non-standard `optreset' feature, for reinitialisation
* of `getopt' parsing. We support this feature, for applications which
* proclaim their BSD heritage, before including this header; however,
* to maintain portability, developers are advised to avoid it.
*/
# define optreset __mingw_optreset
extern int optreset;
#endif
#ifdef __cplusplus
}
#endif
/*
* POSIX requires the `getopt' API to be specified in `unistd.h';
* thus, `unistd.h' includes this header. However, we do not want
* to expose the `getopt_long' or `getopt_long_only' APIs, when
* included in this manner. Thus, close the standard __GETOPT_H__
* declarations block, and open an additional __GETOPT_LONG_H__
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
* to declare the extended API.
*/
#endif /* !defined(__GETOPT_H__) */
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
#define __GETOPT_LONG_H__
#ifdef __cplusplus
extern "C" {
#endif
struct option /* specification for a long form option... */
{
const char *name; /* option name, without leading hyphens */
int has_arg; /* does it take an argument? */
int *flag; /* where to save its status, or NULL */
int val; /* its associated status value */
};
enum /* permitted values for its `has_arg' field... */
{
no_argument = 0, /* option never takes an argument */
required_argument, /* option always requires an argument */
optional_argument /* option may take an argument */
};
extern int getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx);
extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx);
/*
* Previous MinGW implementation had...
*/
#ifndef HAVE_DECL_GETOPT
/*
* ...for the long form API only; keep this for compatibility.
*/
# define HAVE_DECL_GETOPT 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef _WIN32
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdio.h>
#include <windows.h>
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
#ifdef REPLACE_GETOPT
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
#undef optreset /* see getopt.h */
#define optreset __mingw_optreset
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#endif
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#ifndef __CYGWIN__
#define __progname __argv[0]
#else
extern char __declspec(dllimport) *__progname;
#endif
#ifdef __CYGWIN__
static char EMSG[] = "";
#else
#define EMSG ""
#endif
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
static void
_vwarnx(const char *fmt,va_list ap)
{
(void)fprintf(stderr,"%s: ",__progname);
if (fmt != NULL)
(void)vfprintf(stderr,fmt,ap);
(void)fprintf(stderr,"\n");
}
static void
warnx(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
_vwarnx(fmt,ap);
va_end(ap);
}
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too)
{
char *current_argv, *has_equal;
size_t current_argv_len;
int i, ambiguous, match;
#define IDENTICAL_INTERPRETATION(_x, _y) \
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
long_options[(_x)].flag == long_options[(_y)].flag && \
long_options[(_x)].val == long_options[(_y)].val)
current_argv = place;
match = -1;
ambiguous = 0;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
ambiguous = 0;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* partial match */
match = i;
else if (!IDENTICAL_INTERPRETATION(i, match))
ambiguous = 1;
}
if (ambiguous) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
#undef IDENTICAL_INTERPRETATION
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
const char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
* optreset != 0 for GNU compatibility.
*/
if (posixly_correct == -1 || optreset != 0)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options,
idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#endif /* REPLACE_GETOPT */
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
#endif
#include "utils.h"
#include <iomanip>
#include <ostream>
#include <unordered_map>
std::string pad(int n) {
if (n <= 0) {
return "";
}
return std::string(std::min(n, 80), ' ');
}
void print_escaped_string(std::ostream &str, const std::string &s) {
for (char c : s) {
switch (c) {
case '\\':
str << "\\\\";
break;
case '\"':
str << "\\\"";
break;
case '\n':
str << "\\n";
break;
case '\t':
str << "\\t";
break;
case '\b':
str << "\\b";
break;
case '\f':
str << "\\f";
break;
default:
if (isprint(c))
str << c;
else
//
// Unprintable characters are printed using octal equivalents.
// To get the sign of the octal number correct, the character
// must be cast to an unsigned char before coverting it to an
// integer.
//
str << '\\' << std::oct << std::setfill('0') << std::setw(3)
<< (int)((unsigned char)(c)) << std::dec << std::setfill(' ');
break;
}
}
}
void dump_Boolean(std::ostream &stream, int padding, bool b) {
stream << pad(padding) << (int)b << "\n";
}
void dump_Symbol(std::ostream &s, int n, Symbol sym) {
s << pad(n) << sym->get_string() << std::endl;
}
//
// See copyright.h for copyright notice and limitation of liability
// and disclaimer of warranty provisions.
//
#include "copyright.h"
///////////////////////////////////////////////////////////////////////////
//
// file: tree.cc
//
// This file defines the basic class of tree node
//
///////////////////////////////////////////////////////////////////////////
#include "tree.h"
extern int curr_lineno;
///////////////////////////////////////////////////////////////////////////
//
// tree_node::tree_node
//
// constructor of tree node
//
///////////////////////////////////////////////////////////////////////////
tree_node::tree_node() { line_number = curr_lineno; }
///////////////////////////////////////////////////////////////////////////
//
// tree_node::get_line_number
//
///////////////////////////////////////////////////////////////////////////
int tree_node::get_line_number() { return line_number; }
//
// Set up common area from existing node
//
tree_node *tree_node::set(tree_node *t) {
line_number = t->line_number;
return this;
}
#include "stringtab.h"
IntTable inttable;
IdTable idtable;
StrTable stringtable;
//
// See copyright.h for copyright notice and limitation of liability
// and disclaimer of warranty provisions.
//
#include "copyright.h"
#include "cool_tree.h"
#include "tree.h"
#include "utils.h"
//////////////////////////////////////////////////////////////////
//
// dumptype.cc
//
// dumptype defines a simple recursive traversal of the abstract
// syntax tree (AST) that prints each node and any associated
// type information. Use dump_with_types to inspect the results of
// type inference.
//
// dump_with_types takes two argumenmts:
// an output stream
// an indentation "n", the number of blanks to insert at the beginning of
// a new line.
//
// dump_with_types is just a simple pretty printer, formatting the output
// to show the AST relationships between nodes and their types.
// dump_type is a virtual function, with a separate implementation for
// each kind of AST node.
//
// dump_type prints the type of an Expression on the output stream,
// after indenting the correct number of spaces. A check is made to
// see if no type is assigned to the node.
//
// Note that the "type" member referred to here is inherited from tree_node
// by all subclasses of Expression_class. Note also that dump_type is
// defined for the Phylum Expression here, and is therefore inherited by
// every distinct subclass of Expression.
//
void Expression_class::dump_type(std::ostream &stream, int n) {
if (type) {
stream << pad(n) << ": " << type->get_string() << std::endl;
} else {
stream << pad(n) << ": _no_type" << std::endl;
}
}
void dump_line(std::ostream &stream, int n, tree_node *t) {
stream << pad(n) << "#" << t->get_line_number() << "\n";
}
//
// program_class prints "program" and then each of the
// component classes of the program, one at a time, at a
// greater indentation. The recursive invocation on
// "classes->nth(i)->dump_with_types(...)" shows how useful
// and compact virtual functions are for this kind of computation.
//
// Note the use of the iterator to cycle through all of the
// classes. The methods first, more, next, and nth on AST lists
// are defined in tree.h.
//
void program_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_program\n";
for (int i = classes->first(); classes->more(i); i = classes->next(i)) {
classes->nth(i)->dump_with_types(stream, n + 2);
}
}
//
// Prints the components of a class, including all of the features.
// Note that printing the Features is another use of an iterator.
//
void class__class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_class\n";
dump_Symbol(stream, n + 2, name);
dump_Symbol(stream, n + 2, parent);
stream << pad(n + 2) << "\"";
print_escaped_string(stream, filename->get_string());
stream << "\"\n" << pad(n + 2) << "(\n";
for (int i = features->first(); features->more(i); i = features->next(i))
features->nth(i)->dump_with_types(stream, n + 2);
stream << pad(n + 2) << ")\n";
}
//
// dump_with_types for method_class first prints that this is a method,
// then prints the method name followed by the formal parameters
// (another use of an iterator, this time access all of the list members
// of type Formal), the return type, and finally calls dump_type recursively
// on the method body.
void method_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_method\n";
dump_Symbol(stream, n + 2, name);
for (int i = formals->first(); formals->more(i); i = formals->next(i))
formals->nth(i)->dump_with_types(stream, n + 2);
dump_Symbol(stream, n + 2, return_type);
expr->dump_with_types(stream, n + 2);
}
//
// attr_class::dump_with_types prints the attribute name, type declaration,
// and any initialization expression at the appropriate offset.
//
void attr_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_attr\n";
dump_Symbol(stream, n + 2, name);
dump_Symbol(stream, n + 2, type_decl);
init->dump_with_types(stream, n + 2);
}
//
// formal_class::dump_with_types dumps the name and type declaration
// of a formal parameter.
//
void formal_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_formal\n";
dump_Symbol(stream, n + 2, name);
dump_Symbol(stream, n + 2, type_decl);
}
//
// branch_class::dump_with_types dumps the name, type declaration,
// and body of any case branch.
//
void branch_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_branch\n";
dump_Symbol(stream, n + 2, name);
dump_Symbol(stream, n + 2, type_decl);
expr->dump_with_types(stream, n + 2);
}
//
// assign_class::dump_with_types prints "assign" and then (indented)
// the variable being assigned, the expression, and finally the type
// of the result. Note the call to dump_type (see above) at the
// end of the method.
//
void assign_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_assign\n";
dump_Symbol(stream, n + 2, name);
expr->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
//
// static_dispatch_class::dump_with_types prints the expression,
// static dispatch class, function name, and actual arguments
// of any static dispatch.
//
void static_dispatch_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_static_dispatch\n";
expr->dump_with_types(stream, n + 2);
dump_Symbol(stream, n + 2, type_name);
dump_Symbol(stream, n + 2, name);
stream << pad(n + 2) << "(\n";
for (int i = actual->first(); actual->more(i); i = actual->next(i))
actual->nth(i)->dump_with_types(stream, n + 2);
stream << pad(n + 2) << ")\n";
dump_type(stream, n);
}
//
// dispatch_class::dump_with_types is similar to
// static_dispatch_class::dump_with_types
//
void dispatch_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_dispatch\n";
expr->dump_with_types(stream, n + 2);
dump_Symbol(stream, n + 2, name);
stream << pad(n + 2) << "(\n";
for (int i = actual->first(); actual->more(i); i = actual->next(i))
actual->nth(i)->dump_with_types(stream, n + 2);
stream << pad(n + 2) << ")\n";
dump_type(stream, n);
}
//
// cond_class::dump_with_types dumps each of the three expressions
// in the conditional and then the type of the entire expression.
//
void cond_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_cond\n";
pred->dump_with_types(stream, n + 2);
then_exp->dump_with_types(stream, n + 2);
else_exp->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
//
// loop_class::dump_with_types dumps the predicate and then the
// body of the loop, and finally the type of the entire expression.
//
void loop_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_loop\n";
pred->dump_with_types(stream, n + 2);
body->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
//
// typcase_class::dump_with_types dumps each branch of the
// the Case_ one at a time. The type of the entire expression
// is dumped at the end.
//
void typcase_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_typcase\n";
expr->dump_with_types(stream, n + 2);
for (int i = cases->first(); cases->more(i); i = cases->next(i))
cases->nth(i)->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
//
// The rest of the cases for Expression are very straightforward
// and introduce nothing that isn't already in the code discussed
// above.
//
void block_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_block\n";
for (int i = body->first(); body->more(i); i = body->next(i))
body->nth(i)->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void let_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_let\n";
dump_Symbol(stream, n + 2, identifier);
dump_Symbol(stream, n + 2, type_decl);
init->dump_with_types(stream, n + 2);
body->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void plus_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_plus\n";
e1->dump_with_types(stream, n + 2);
e2->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void sub_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_sub\n";
e1->dump_with_types(stream, n + 2);
e2->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void mul_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_mul\n";
e1->dump_with_types(stream, n + 2);
e2->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void divide_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_divide\n";
e1->dump_with_types(stream, n + 2);
e2->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void neg_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_neg\n";
e1->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void lt_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_lt\n";
e1->dump_with_types(stream, n + 2);
e2->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void eq_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_eq\n";
e1->dump_with_types(stream, n + 2);
e2->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void leq_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_leq\n";
e1->dump_with_types(stream, n + 2);
e2->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void comp_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_comp\n";
e1->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void int_const_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_int\n";
dump_Symbol(stream, n + 2, token);
dump_type(stream, n);
}
void bool_const_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_bool\n";
dump_Boolean(stream, n + 2, val);
dump_type(stream, n);
}
void string_const_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_string\n";
stream << pad(n + 2) << "\"";
print_escaped_string(stream, token->get_string());
stream << "\"\n";
dump_type(stream, n);
}
void new__class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_new\n";
dump_Symbol(stream, n + 2, type_name);
dump_type(stream, n);
}
void isvoid_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_isvoid\n";
e1->dump_with_types(stream, n + 2);
dump_type(stream, n);
}
void no_expr_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_no_expr\n";
dump_type(stream, n);
}
void object_class::dump_with_types(std::ostream &stream, int n) {
dump_line(stream, n, this);
stream << pad(n) << "_object\n";
dump_Symbol(stream, n + 2, name);
dump_type(stream, n);
}
//////////////////////////////////////////////////////////
//
// file: cool-tree.cc
//
// This file defines the functions of each class
//
//////////////////////////////////////////////////////////
#include "cool_tree.h"
#include "tree.h"
// constructors' functions
Program program_class::copy_Program() {
return new program_class(classes->copy_list());
}
void program_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "program\n";
classes->dump(stream, n + 2);
}
Class_ class__class::copy_Class_() {
return new class__class(name, parent, features->copy_list(), filename);
}
void class__class::dump(std::ostream &stream, int n) {
stream << pad(n) << "class_\n";
dump_Symbol(stream, n + 2, name);
dump_Symbol(stream, n + 2, parent);
features->dump(stream, n + 2);
dump_Symbol(stream, n + 2, filename);
}
Feature method_class::copy_Feature() {
return new method_class(name, formals->copy_list(), return_type,
expr->copy_Expression());
}
void method_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "method\n";
dump_Symbol(stream, n + 2, name);
formals->dump(stream, n + 2);
dump_Symbol(stream, n + 2, return_type);
expr->dump(stream, n + 2);
}
Feature attr_class::copy_Feature() {
return new attr_class(name, type_decl, init->copy_Expression());
}
void attr_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "attr\n";
dump_Symbol(stream, n + 2, name);
dump_Symbol(stream, n + 2, type_decl);
init->dump(stream, n + 2);
}
Formal formal_class::copy_Formal() { return new formal_class(name, type_decl); }
void formal_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "formal\n";
dump_Symbol(stream, n + 2, name);
dump_Symbol(stream, n + 2, type_decl);
}
Case branch_class::copy_Case() {
return new branch_class(name, type_decl, expr->copy_Expression());
}
void branch_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "branch\n";
dump_Symbol(stream, n + 2, name);
dump_Symbol(stream, n + 2, type_decl);
expr->dump(stream, n + 2);
}
Expression assign_class::copy_Expression() {
return new assign_class(name, expr->copy_Expression());
}
void assign_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "assign\n";
dump_Symbol(stream, n + 2, name);
expr->dump(stream, n + 2);
}
Expression static_dispatch_class::copy_Expression() {
return new static_dispatch_class(expr->copy_Expression(), type_name, name,
actual->copy_list());
}
void static_dispatch_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "static_dispatch\n";
expr->dump(stream, n + 2);
dump_Symbol(stream, n + 2, type_name);
dump_Symbol(stream, n + 2, name);
actual->dump(stream, n + 2);
}
Expression dispatch_class::copy_Expression() {
return new dispatch_class(expr->copy_Expression(), name, actual->copy_list());
}
void dispatch_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "dispatch\n";
expr->dump(stream, n + 2);
dump_Symbol(stream, n + 2, name);
actual->dump(stream, n + 2);
}
Expression cond_class::copy_Expression() {
return new cond_class(pred->copy_Expression(), then_exp->copy_Expression(),
else_exp->copy_Expression());
}
void cond_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "cond\n";
pred->dump(stream, n + 2);
then_exp->dump(stream, n + 2);
else_exp->dump(stream, n + 2);
}
Expression loop_class::copy_Expression() {
return new loop_class(pred->copy_Expression(), body->copy_Expression());
}
void loop_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "loop\n";
pred->dump(stream, n + 2);
body->dump(stream, n + 2);
}
Expression typcase_class::copy_Expression() {
return new typcase_class(expr->copy_Expression(), cases->copy_list());
}
void typcase_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "typcase\n";
expr->dump(stream, n + 2);
cases->dump(stream, n + 2);
}
Expression block_class::copy_Expression() {
return new block_class(body->copy_list());
}
void block_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "block\n";
body->dump(stream, n + 2);
}
Expression let_class::copy_Expression() {
return new let_class(identifier, type_decl, init->copy_Expression(),
body->copy_Expression());
}
void let_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "let\n";
dump_Symbol(stream, n + 2, identifier);
dump_Symbol(stream, n + 2, type_decl);
init->dump(stream, n + 2);
body->dump(stream, n + 2);
}
Expression plus_class::copy_Expression() {
return new plus_class(e1->copy_Expression(), e2->copy_Expression());
}
void plus_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "plus\n";
e1->dump(stream, n + 2);
e2->dump(stream, n + 2);
}
Expression sub_class::copy_Expression() {
return new sub_class(e1->copy_Expression(), e2->copy_Expression());
}
void sub_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "sub\n";
e1->dump(stream, n + 2);
e2->dump(stream, n + 2);
}
Expression mul_class::copy_Expression() {
return new mul_class(e1->copy_Expression(), e2->copy_Expression());
}
void mul_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "mul\n";
e1->dump(stream, n + 2);
e2->dump(stream, n + 2);
}
Expression divide_class::copy_Expression() {
return new divide_class(e1->copy_Expression(), e2->copy_Expression());
}
void divide_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "divide\n";
e1->dump(stream, n + 2);
e2->dump(stream, n + 2);
}
Expression neg_class::copy_Expression() {
return new neg_class(e1->copy_Expression());
}
void neg_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "neg\n";
e1->dump(stream, n + 2);
}
Expression lt_class::copy_Expression() {
return new lt_class(e1->copy_Expression(), e2->copy_Expression());
}
void lt_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "lt\n";
e1->dump(stream, n + 2);
e2->dump(stream, n + 2);
}
Expression eq_class::copy_Expression() {
return new eq_class(e1->copy_Expression(), e2->copy_Expression());
}
void eq_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "eq\n";
e1->dump(stream, n + 2);
e2->dump(stream, n + 2);
}
Expression leq_class::copy_Expression() {
return new leq_class(e1->copy_Expression(), e2->copy_Expression());
}
void leq_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "leq\n";
e1->dump(stream, n + 2);
e2->dump(stream, n + 2);
}
Expression comp_class::copy_Expression() {
return new comp_class(e1->copy_Expression());
}
void comp_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "comp\n";
e1->dump(stream, n + 2);
}
Expression int_const_class::copy_Expression() {
return new int_const_class(token);
}
void int_const_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "int_const\n";
dump_Symbol(stream, n + 2, token);
}
Expression bool_const_class::copy_Expression() {
return new bool_const_class(val);
}
void bool_const_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "bool_const\n";
dump_Boolean(stream, n + 2, val);
}
Expression string_const_class::copy_Expression() {
return new string_const_class(token);
}
void string_const_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "string_const\n";
dump_Symbol(stream, n + 2, token);
}
Expression new__class::copy_Expression() { return new new__class(type_name); }
void new__class::dump(std::ostream &stream, int n) {
stream << pad(n) << "new_\n";
dump_Symbol(stream, n + 2, type_name);
}
Expression isvoid_class::copy_Expression() {
return new isvoid_class(e1->copy_Expression());
}
void isvoid_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "isvoid\n";
e1->dump(stream, n + 2);
}
Expression no_expr_class::copy_Expression() { return new no_expr_class(); }
void no_expr_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "no_expr\n";
}
Expression object_class::copy_Expression() { return new object_class(name); }
void object_class::dump(std::ostream &stream, int n) {
stream << pad(n) << "object\n";
dump_Symbol(stream, n + 2, name);
}
// interfaces used by Bison
Classes nil_Classes() { return new nil_node<Class_>(); }
Classes single_Classes(Class_ e) { return new single_list_node<Class_>(e); }
Classes append_Classes(Classes p1, Classes p2) {
return new append_node<Class_>(p1, p2);
}
Features nil_Features() { return new nil_node<Feature>(); }
Features single_Features(Feature e) { return new single_list_node<Feature>(e); }
Features append_Features(Features p1, Features p2) {
return new append_node<Feature>(p1, p2);
}
Formals nil_Formals() { return new nil_node<Formal>(); }
Formals single_Formals(Formal e) { return new single_list_node<Formal>(e); }
Formals append_Formals(Formals p1, Formals p2) {
return new append_node<Formal>(p1, p2);
}
Expressions nil_Expressions() { return new nil_node<Expression>(); }
Expressions single_Expressions(Expression e) {
return new single_list_node<Expression>(e);
}
Expressions append_Expressions(Expressions p1, Expressions p2) {
return new append_node<Expression>(p1, p2);
}
Cases nil_Cases() { return new nil_node<Case>(); }
Cases single_Cases(Case e) { return new single_list_node<Case>(e); }
Cases append_Cases(Cases p1, Cases p2) { return new append_node<Case>(p1, p2); }
Program program(Classes classes) { return new program_class(classes); }
Class_ class_(Symbol name, Symbol parent, Features features, Symbol filename) {
return new class__class(name, parent, features, filename);
}
Feature method(Symbol name, Formals formals, Symbol return_type,
Expression expr) {
return new method_class(name, formals, return_type, expr);
}
Feature attr(Symbol name, Symbol type_decl, Expression init) {
return new attr_class(name, type_decl, init);
}
Formal formal(Symbol name, Symbol type_decl) {
return new formal_class(name, type_decl);
}
Case branch(Symbol name, Symbol type_decl, Expression expr) {
return new branch_class(name, type_decl, expr);
}
Expression assign(Symbol name, Expression expr) {
return new assign_class(name, expr);
}
Expression static_dispatch(Expression expr, Symbol type_name, Symbol name,
Expressions actual) {
return new static_dispatch_class(expr, type_name, name, actual);
}
Expression dispatch(Expression expr, Symbol name, Expressions actual) {
return new dispatch_class(expr, name, actual);
}
Expression cond(Expression pred, Expression then_exp, Expression else_exp) {
return new cond_class(pred, then_exp, else_exp);
}
Expression loop(Expression pred, Expression body) {
return new loop_class(pred, body);
}
Expression typcase(Expression expr, Cases cases) {
return new typcase_class(expr, cases);
}
Expression block(Expressions body) { return new block_class(body); }
Expression let(Symbol identifier, Symbol type_decl, Expression init,
Expression body) {
return new let_class(identifier, type_decl, init, body);
}
Expression plus(Expression e1, Expression e2) { return new plus_class(e1, e2); }
Expression sub(Expression e1, Expression e2) { return new sub_class(e1, e2); }
Expression mul(Expression e1, Expression e2) { return new mul_class(e1, e2); }
Expression divide(Expression e1, Expression e2) {
return new divide_class(e1, e2);
}
Expression neg(Expression e1) { return new neg_class(e1); }
Expression lt(Expression e1, Expression e2) { return new lt_class(e1, e2); }
Expression eq(Expression e1, Expression e2) { return new eq_class(e1, e2); }
Expression leq(Expression e1, Expression e2) { return new leq_class(e1, e2); }
Expression comp(Expression e1) { return new comp_class(e1); }
Expression int_const(Symbol token) { return new int_const_class(token); }
Expression bool_const(bool val) { return new bool_const_class(val); }
Expression string_const(Symbol token) { return new string_const_class(token); }
Expression new_(Symbol type_name) { return new new__class(type_name); }
Expression isvoid(Expression e1) { return new isvoid_class(e1); }
Expression no_expr() { return new no_expr_class(); }
Expression object(Symbol name) { return new object_class(name); }
//
// See copyright.h for copyright notice and limitation of liability
// and disclaimer of warranty provisions.
//
#include "copyright.h"
#include "cool_tree.h"
#include <fstream>
#include <iostream>
#include <optional>
#include <unistd.h>
extern Program ast_root; // root of the abstract syntax tree
FILE* ast_file = stdin; // we read the AST from standard input
extern int ast_yyparse(void); // entry point to the AST parser
std::string out_filename; // file name for generated code
int cgen_debug, curr_lineno; // for code gen
extern char* optarg; // used for option processing (man 3 getopt for more info)
void handle_flags(int argc, char* argv[])
{
int c;
int unknownopt = 0;
// no debugging or optimization by default
cgen_debug = 0;
while ((c = getopt(argc, argv, "do:")) != -1) {
switch (c) {
#ifdef DEBUG
case 'd':
cgen_debug = 1;
break;
#else
case 'd':
std::cerr << "No debugging available\n";
break;
#endif
case 'o': // set the name of the output file
out_filename = optarg;
break;
case '?':
unknownopt = 1;
break;
case ':':
unknownopt = 1;
break;
}
}
if (unknownopt) {
std::cerr << "usage: " << argv[0] <<
#ifdef DEBUG
" [-d -o outname]\n";
#else
" [-o outname]\n";
#endif
exit(1);
}
}
int main(int argc, char* argv[])
{
handle_flags(argc, argv);
if (optind < argc) {
ast_file = fopen(argv[optind], "r");
if (!ast_file) {
std::cerr << "Cannot open input file " << argv[optind] << std::endl;
exit(1);
}
}
// Don't touch the output file until we know that earlier phases of the
// compiler have succeeded.
ast_yyparse();
if (!out_filename.empty()) {
ast_root->cgen(out_filename);
}
else {
ast_root->cgen(std::nullopt);
}
}
/* A Bison parser, made from ast.y
by GNU bison 1.35. */
#define YYBISON 1 /* Identify Bison output. */
#define yyparse ast_yyparse
#define yylex ast_yylex
#define yyerror ast_yyerror
#define yylval ast_yylval
#define yychar ast_yychar
#define yydebug ast_yydebug
#define yynerrs ast_yynerrs
#define PROGRAM 257
#define CLASS 258
#define METHOD 259
#define ATTR 260
#define FORMAL 261
#define BRANCH 262
#define ASSIGN 263
#define STATIC_DISPATCH 264
#define DISPATCH 265
#define COND 266
#define LOOP 267
#define TYPCASE 268
#define BLOCK 269
#define LET 270
#define PLUS 271
#define SUB 272
#define MUL 273
#define DIVIDE 274
#define NEG 275
#define LESSTHAN 276
#define EQUAL 277
#define LEQ 278
#define COMP 279
#define INT 280
#define STR 281
#define BOOL 282
#define NEW 283
#define ISVOID 284
#define NO_EXPR 285
#define OBJECT 286
#define NO_TYPE 287
#define STR_CONST 288
#define INT_CONST 289
#define IDENT 290
#define LINENO 291
#line 6 "ast.y"
#include "cool_tree.h"
#include "stringtab.h"
#include "utils.h"
void ast_yyerror(char *);
extern int curr_lineno;
extern int yylex(); /* the entry point to the lexer */
Program ast_root; /* the result of the parse */
Classes parse_results; /* for use in parsing multiple files */
int omerrs = 0; /* number of errors in lexing and parsing */
#line 21 "ast.y"
#ifndef YYSTYPE
typedef union {
int lineno;
bool boolean;
Symbol symbol;
Program program;
Class_ class_;
Classes classes;
Feature feature;
Features features;
Formal formal;
Formals formals;
Case case_;
Cases cases;
Expression expression;
Expressions expressions;
} yystype;
#define YYSTYPE yystype
#define YYSTYPE_IS_TRIVIAL 1
#endif
#ifndef YYDEBUG
#define YYDEBUG 1
#endif
#define YYFINAL 121
#define YYFLAG -32768
#define YYNTBASE 41
/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
#define YYTRANSLATE(x) ((unsigned)(x) <= 291 ? yytranslate[x] : 56)
/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
static const char yytranslate[] = {
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 38, 39, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37};
#if YYDEBUG
static const short yyprhs[] = {
0, 0, 4, 5, 7, 10, 19, 20, 22, 24, 27, 34, 40,
41, 43, 45, 48, 53, 57, 61, 66, 73, 79, 85, 90, 94,
101, 106, 110, 114, 119, 124, 129, 134, 138, 143, 148, 153, 157,
161, 165, 169, 173, 176, 179, 183, 185, 188, 190, 193};
static const short yyrhs[] = {
37, 3, 42, 0, 0, 43, 0, 42, 43, 0, 37, 4, 36, 36, 34, 38, 44, 39, 0,
0, 45, 0, 46, 0, 45, 46, 0, 37, 5, 36, 47, 36, 50, 0, 37, 6, 36, 36,
50, 0, 0, 48, 0, 49, 0, 48, 49, 0, 37, 7, 36, 36, 0, 51, 40, 36, 0,
51, 40, 33, 0, 37, 9, 36, 50, 0, 37, 10, 50, 36, 36, 52, 0, 37, 11, 50,
36, 52, 0, 37, 12, 50, 50, 50, 0, 37, 13, 50, 50, 0, 37, 15, 53, 0, 37,
16, 36, 36, 50, 50, 0, 37, 14, 50, 54, 0, 37, 29, 36, 0, 37, 30, 50, 0,
37, 17, 50, 50, 0, 37, 18, 50, 50, 0, 37, 19, 50, 50, 0, 37, 20, 50, 50,
0, 37, 21, 50, 0, 37, 22, 50, 50, 0, 37, 23, 50, 50, 0, 37, 24, 50, 50,
0, 37, 25, 50, 0, 37, 26, 35, 0, 37, 27, 34, 0, 37, 28, 35, 0, 37, 32,
36, 0, 37, 31, 0, 38, 39, 0, 38, 53, 39, 0, 50, 0, 53, 50, 0, 55, 0,
54, 55, 0, 37, 8, 36, 36, 50, 0};
#endif
#if YYDEBUG
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const short yyrline[] = {
0, 68, 70, 75, 78, 83, 89, 91, 96, 98, 102, 104, 108,
110, 115, 117, 121, 125, 129, 132, 135, 138, 141, 144, 147, 150,
153, 156, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 189,
192, 195, 203, 206, 210, 212, 217, 219, 224, 226, 231};
#endif
#if (YYDEBUG) || defined YYERROR_VERBOSE
/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */
static const char *const yytname[] = {"$",
"error",
"$undefined.",
"PROGRAM",
"CLASS",
"METHOD",
"ATTR",
"FORMAL",
"BRANCH",
"ASSIGN",
"STATIC_DISPATCH",
"DISPATCH",
"COND",
"LOOP",
"TYPCASE",
"BLOCK",
"LET",
"PLUS",
"SUB",
"MUL",
"DIVIDE",
"NEG",
"LESSTHAN",
"EQUAL",
"LEQ",
"COMP",
"INT",
"STR",
"BOOL",
"NEW",
"ISVOID",
"NO_EXPR",
"OBJECT",
"NO_TYPE",
"STR_CONST",
"INT_CONST",
"IDENT",
"LINENO",
"'('",
"')'",
"':'",
"program",
"class_list",
"class",
"optional_feature_list",
"feature_list",
"feature",
"formals",
"formal_list",
"formal",
"expr",
"expr_aux",
"actuals",
"expr_list",
"case_list",
"simple_case",
0};
#endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const short yyr1[] = {0, 41, 41, 42, 42, 43, 44, 44, 45, 45, 46, 46, 47,
47, 48, 48, 49, 50, 50, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 52, 52, 53, 53, 54, 54, 55};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
static const short yyr2[] = {0, 3, 0, 1, 2, 8, 0, 1, 1, 2, 6, 5, 0, 1, 1, 2, 4,
3, 3, 4, 6, 5, 5, 4, 3, 6, 4, 3, 3, 4, 4, 4, 4, 3,
4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 3, 1, 2, 1, 2, 5};
/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
doesn't specify something else to do. Zero means the default is an
error. */
static const short yydefact[] = {
2, 0, 0, 0, 1, 3, 0, 4, 0, 0, 0, 6, 0, 0, 7, 8, 0, 0,
5, 9, 12, 0, 0, 0, 13, 14, 0, 0, 0, 15, 0, 11, 0, 0, 10, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 42, 0, 0, 16, 0, 0, 0, 0, 0, 0, 45, 24, 0, 0, 0,
0, 0, 33, 0, 0, 0, 37, 38, 39, 40, 27, 28, 41, 18, 17, 19, 0, 0,
0, 23, 0, 26, 47, 46, 0, 29, 30, 31, 32, 34, 35, 36, 0, 0, 21, 22,
0, 48, 0, 20, 43, 0, 0, 25, 44, 0, 49, 0, 0, 0};
static const short yydefgoto[] = {119, 4, 5, 13, 14, 15, 23, 24,
25, 67, 32, 106, 68, 93, 94};
static const short yypact[] = {
-30, 6, -11, 23, -11, -32768, -8, -32768, -7,
-3, -6, -4, 10, -5, -4, -32768, 0, 1,
-32768, -32768, 3, 5, 36, 12, 3, -32768, 15,
17, 15, -32768, 83, -32768, 14, 19, -32768, 20,
15, 15, 15, 15, 15, 15, 21, 15, 15,
15, 15, 15, 15, 15, 15, 15, 24, 26,
27, 22, 15, -32768, 25, -32, -32768, 15, 29,
30, 15, 15, 31, -32768, 15, 33, 15, 15,
15, 15, -32768, 15, 15, 15, -32768, -32768, -32768,
-32768, -32768, -32768, -32768, -32768, -32768, -32768, 35, 34,
15, -32768, 55, 31, -32768, -32768, 15, -32768, -32768,
-32768, -32768, -32768, -32768, -32768, 34, -34, -32768, -32768,
37, -32768, 15, -32768, -32768, -31, 38, -32768, -32768,
15, -32768, 67, 75, -32768};
static const short yypgoto[] = {-32768, -32768, 72, -32768, -32768,
63, -32768, -32768, 54, -26,
-32768, -25, -24, -32768, -13};
#define YYLAST 115
static const short yytable[] = {
31, 85, 34, 30, 86, 112, 30, 1, 116, 2, 62, 63, 64, 65, 66,
16, 17, 70, 71, 72, 73, 74, 75, 76, 77, 78, 3, 6, 8, 9,
83, 10, 11, 12, 18, 87, 20, 21, 90, 91, 22, 26, 95, 27, 97,
98, 99, 100, 28, 101, 102, 103, 30, 33, 59, 60, 61, 69, 82, 79,
80, 84, 81, 108, 107, 88, 89, 120, 92, 96, 110, 104, 105, 114, 117,
121, 7, 19, 29, 111, 109, 113, 0, 0, 115, 0, 0, 95, 0, 0,
0, 118, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58};
static const short yycheck[] = {
26, 33, 28, 37, 36, 39, 37, 37, 39, 3, 36, 37, 38, 39, 40, 5, 6,
43, 44, 45, 46, 47, 48, 49, 50, 51, 37, 4, 36, 36, 56, 34, 38, 37,
39, 61, 36, 36, 64, 65, 37, 36, 68, 7, 70, 71, 72, 73, 36, 75, 76,
77, 37, 36, 40, 36, 36, 36, 36, 35, 34, 36, 35, 8, 90, 36, 36, 0,
37, 36, 96, 36, 38, 36, 36, 0, 4, 14, 24, 104, 93, 105, -1, -1, 110,
-1, -1, 113, -1, -1, -1, 117, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
#line 3 "/usr/share/bison/bison.simple"
/* Skeleton output parser for bison,
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, when this file is copied by Bison into a
Bison output file, you may use that output file without restriction.
This special exception was added by the Free Software Foundation
in version 1.24 of Bison. */
/* This is the parser code that is written into each bison parser when
the %semantic_parser declaration is not specified in the grammar.
It was written by Richard Stallman by simplifying the hairy parser
used when %semantic_parser is specified. */
/* All symbols defined below should begin with yy or YY, to avoid
infringing on user name space. This should be done even for local
variables, as they might otherwise be expanded by user macros.
There are some unavoidable exceptions within include files to
define necessary library symbols; they are noted "INFRINGES ON
USER NAME SPACE" below. */
#if !defined(yyoverflow) || defined(YYERROR_VERBOSE)
/* The parser invokes alloca or malloc; define the necessary symbols. */
#if YYSTACK_USE_ALLOCA
#define YYSTACK_ALLOC alloca
#else
#ifndef YYSTACK_USE_ALLOCA
#if defined(alloca) || defined(_ALLOCA_H)
#define YYSTACK_ALLOC alloca
#else
#ifdef __GNUC__
#define YYSTACK_ALLOC __builtin_alloca
#endif
#endif
#endif
#endif
#ifdef YYSTACK_ALLOC
/* Pacify GCC's `empty if-body' warning. */
#define YYSTACK_FREE(Ptr) \
do { /* empty */ \
; \
} while (0)
#else
#if defined(__STDC__) || defined(__cplusplus)
#include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
#define YYSIZE_T size_t
#endif
#define YYSTACK_ALLOC malloc
#define YYSTACK_FREE free
#endif
#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */
#if (!defined(yyoverflow) && \
(!defined(__cplusplus) || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
/* A type that is properly aligned for any stack member. */
union yyalloc {
short yyss;
YYSTYPE yyvs;
#if YYLSP_NEEDED
YYLTYPE yyls;
#endif
};
/* The size of the maximum gap between one aligned stack and the next. */
#define YYSTACK_GAP_MAX (sizeof(union yyalloc) - 1)
/* The size of an array large to enough to hold all stacks, each with
N elements. */
#if YYLSP_NEEDED
#define YYSTACK_BYTES(N) \
((N) * (sizeof(short) + sizeof(YYSTYPE) + sizeof(YYLTYPE)) + \
2 * YYSTACK_GAP_MAX)
#else
#define YYSTACK_BYTES(N) \
((N) * (sizeof(short) + sizeof(YYSTYPE)) + YYSTACK_GAP_MAX)
#endif
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
#ifndef YYCOPY
#if 1 < __GNUC__
#define YYCOPY(To, From, Count) \
__builtin_memcpy(To, From, (Count) * sizeof(*(From)))
#else
#define YYCOPY(To, From, Count) \
do { \
register YYSIZE_T yyi; \
for (yyi = 0; yyi < (Count); yyi++) \
(To)[yyi] = (From)[yyi]; \
} while (0)
#endif
#endif
/* Relocate STACK from its old location to the new one. The
local variables YYSIZE and YYSTACKSIZE give the old and new number of
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
#define YYSTACK_RELOCATE(Stack) \
do { \
YYSIZE_T yynewbytes; \
YYCOPY(&yyptr->Stack, Stack, yysize); \
Stack = &yyptr->Stack; \
yynewbytes = yystacksize * sizeof(*Stack) + YYSTACK_GAP_MAX; \
yyptr += yynewbytes / sizeof(*yyptr); \
} while (0)
#endif
#if !defined(YYSIZE_T) && defined(__SIZE_TYPE__)
#define YYSIZE_T __SIZE_TYPE__
#endif
#if !defined(YYSIZE_T) && defined(size_t)
#define YYSIZE_T size_t
#endif
#if !defined(YYSIZE_T)
#if defined(__STDC__) || defined(__cplusplus)
#include <stddef.h> /* INFRINGES ON USER NAME SPACE */
#define YYSIZE_T size_t
#endif
#endif
#if !defined(YYSIZE_T)
#define YYSIZE_T unsigned int
#endif
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
#define YYEMPTY -2
#define YYEOF 0
#define YYACCEPT goto yyacceptlab
#define YYABORT goto yyabortlab
#define YYERROR goto yyerrlab1
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
Once GCC version 2 has supplanted version 1, this can go. */
#define YYFAIL goto yyerrlab
#define YYRECOVERING() (!!yyerrstatus)
#define YYBACKUP(Token, Value) \
do \
if (yychar == YYEMPTY && yylen == 1) { \
yychar = (Token); \
yylval = (Value); \
yychar1 = YYTRANSLATE(yychar); \
YYPOPSTACK; \
goto yybackup; \
} else { \
yyerror("syntax error: cannot back up"); \
YYERROR; \
} \
while (0)
#define YYTERROR 1
#define YYERRCODE 256
/* YYLLOC_DEFAULT -- Compute the default location (before the actions
are run).
When YYLLOC_DEFAULT is run, CURRENT is set the location of the
first token. By default, to implement support for ranges, extend
its range to the last symbol. */
#ifndef YYLLOC_DEFAULT
#define YYLLOC_DEFAULT(Current, Rhs, N) \
Current.last_line = Rhs[N].last_line; \
Current.last_column = Rhs[N].last_column;
#endif
/* YYLEX -- calling `yylex' with the right arguments. */
#if YYPURE
#if YYLSP_NEEDED
#ifdef YYLEX_PARAM
#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
#else
#define YYLEX yylex(&yylval, &yylloc)
#endif
#else /* !YYLSP_NEEDED */
#ifdef YYLEX_PARAM
#define YYLEX yylex(&yylval, YYLEX_PARAM)
#else
#define YYLEX yylex(&yylval)
#endif
#endif /* !YYLSP_NEEDED */
#else /* !YYPURE */
#define YYLEX yylex()
#endif /* !YYPURE */
/* Enable debugging if requested. */
#if YYDEBUG
#ifndef YYFPRINTF
#include <stdio.h> /* INFRINGES ON USER NAME SPACE */
#define YYFPRINTF fprintf
#endif
#define YYDPRINTF(Args) \
do { \
if (yydebug) \
YYFPRINTF Args; \
} while (0)
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
int yydebug;
#else /* !YYDEBUG */
#define YYDPRINTF(Args)
#endif /* !YYDEBUG */
/* YYINITDEPTH -- initial size of the parser's stacks. */
#ifndef YYINITDEPTH
#define YYINITDEPTH 200
#endif
/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
if the built-in stack extension method is used).
Do not make this value too large; the results are undefined if
SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
evaluated with infinite-precision integer arithmetic. */
#if YYMAXDEPTH == 0
#undef YYMAXDEPTH
#endif
#ifndef YYMAXDEPTH
#define YYMAXDEPTH 10000
#endif
#ifdef YYERROR_VERBOSE
#ifndef yystrlen
#if defined(__GLIBC__) && defined(_STRING_H)
#define yystrlen strlen
#else
/* Return the length of YYSTR. */
static YYSIZE_T
#if defined(__STDC__) || defined(__cplusplus)
yystrlen(const char *yystr)
#else
yystrlen(yystr) const char *yystr;
#endif
{
register const char *yys = yystr;
while (*yys++ != '\0')
continue;
return yys - yystr - 1;
}
#endif
#endif
#ifndef yystpcpy
#if defined(__GLIBC__) && defined(_STRING_H) && defined(_GNU_SOURCE)
#define yystpcpy stpcpy
#else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
static char *
#if defined(__STDC__) || defined(__cplusplus)
yystpcpy(char *yydest, const char *yysrc)
#else
yystpcpy(yydest, yysrc) char *yydest;
const char *yysrc;
#endif
{
register char *yyd = yydest;
register const char *yys = yysrc;
while ((*yyd++ = *yys++) != '\0')
continue;
return yyd - 1;
}
#endif
#endif
#endif
#line 315 "/usr/share/bison/bison.simple"
/* The user can define YYPARSE_PARAM as the name of an argument to be passed
into yyparse. The argument should have type void *.
It should actually point to an object.
Grammar actions can access the variable by casting it
to the proper pointer type. */
#ifdef YYPARSE_PARAM
#if defined(__STDC__) || defined(__cplusplus)
#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
#define YYPARSE_PARAM_DECL
#else
#define YYPARSE_PARAM_ARG YYPARSE_PARAM
#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
#endif
#else /* !YYPARSE_PARAM */
#define YYPARSE_PARAM_ARG
#define YYPARSE_PARAM_DECL
#endif /* !YYPARSE_PARAM */
/* Prevent warning if -Wstrict-prototypes. */
#ifdef __GNUC__
#ifdef YYPARSE_PARAM
int yyparse(void *);
#else
int yyparse(void);
#endif
#endif
/* YY_DECL_VARIABLES -- depending whether we use a pure parser,
variables are global, or local to YYPARSE. */
#define YY_DECL_NON_LSP_VARIABLES \
/* The lookahead symbol. */ \
int yychar; \
\
/* The semantic value of the lookahead symbol. */ \
YYSTYPE yylval; \
\
/* Number of parse errors so far. */ \
int yynerrs;
#if YYLSP_NEEDED
#define YY_DECL_VARIABLES \
YY_DECL_NON_LSP_VARIABLES \
\
/* Location data for the lookahead symbol. */ \
YYLTYPE yylloc;
#else
#define YY_DECL_VARIABLES YY_DECL_NON_LSP_VARIABLES
#endif
/* If nonreentrant, generate the variables here. */
#if !YYPURE
YY_DECL_VARIABLES
#endif /* !YYPURE */
int yyparse(YYPARSE_PARAM_ARG) YYPARSE_PARAM_DECL {
/* If reentrant, generate the variables here. */
#if YYPURE
YY_DECL_VARIABLES
#endif /* !YYPURE */
register int yystate;
register int yyn;
int yyresult;
/* Number of tokens to shift before error messages enabled. */
int yyerrstatus;
/* Lookahead token as an internal (translated) token number. */
int yychar1 = 0;
/* Three stacks and their tools:
`yyss': related to states,
`yyvs': related to semantic values,
`yyls': related to locations.
Refer to the stacks thru separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
/* The state stack. */
short yyssa[YYINITDEPTH];
short *yyss = yyssa;
register short *yyssp;
/* The semantic value stack. */
YYSTYPE yyvsa[YYINITDEPTH];
YYSTYPE *yyvs = yyvsa;
register YYSTYPE *yyvsp;
#if YYLSP_NEEDED
/* The location stack. */
YYLTYPE yylsa[YYINITDEPTH];
YYLTYPE *yyls = yylsa;
YYLTYPE *yylsp;
#endif
#if YYLSP_NEEDED
#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
#else
#define YYPOPSTACK (yyvsp--, yyssp--)
#endif
YYSIZE_T yystacksize = YYINITDEPTH;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
#if YYLSP_NEEDED
YYLTYPE yyloc;
#endif
/* When reducing, the number of symbols on the RHS of the reduced
rule. */
int yylen;
YYDPRINTF((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
yyssp = yyss;
yyvsp = yyvs;
#if YYLSP_NEEDED
yylsp = yyls;
#endif
goto yysetstate;
/*------------------------------------------------------------.
| yynewstate -- Push a new state, which is found in yystate. |
`------------------------------------------------------------*/
yynewstate:
/* In all cases, when you get here, the value and location stacks
have just been pushed. so pushing a state here evens the stacks.
*/
yyssp++;
yysetstate:
*yyssp = yystate;
if (yyssp >= yyss + yystacksize - 1) {
/* Get the current used size of the three stacks, in elements. */
YYSIZE_T yysize = yyssp - yyss + 1;
#ifdef yyoverflow
{
/* Give user a chance to reallocate the stack. Use copies of
these so that the &'s don't force the real ones into
memory. */
YYSTYPE *yyvs1 = yyvs;
short *yyss1 = yyss;
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. */
#if YYLSP_NEEDED
YYLTYPE *yyls1 = yyls;
/* This used to be a conditional around just the two extra args,
but that might be undefined if yyoverflow is a macro. */
yyoverflow("parser stack overflow", &yyss1, yysize * sizeof(*yyssp),
&yyvs1, yysize * sizeof(*yyvsp), &yyls1,
yysize * sizeof(*yylsp), &yystacksize);
yyls = yyls1;
#else
yyoverflow("parser stack overflow", &yyss1, yysize * sizeof(*yyssp),
&yyvs1, yysize * sizeof(*yyvsp), &yystacksize);
#endif
yyss = yyss1;
yyvs = yyvs1;
}
#else /* no yyoverflow */
#ifndef YYSTACK_RELOCATE
goto yyoverflowlab;
#else
/* Extend the stack our own way. */
if (yystacksize >= YYMAXDEPTH)
goto yyoverflowlab;
yystacksize *= 2;
if (yystacksize > YYMAXDEPTH)
yystacksize = YYMAXDEPTH;
{
short *yyss1 = yyss;
union yyalloc *yyptr =
(union yyalloc *)YYSTACK_ALLOC(YYSTACK_BYTES(yystacksize));
if (!yyptr)
goto yyoverflowlab;
YYSTACK_RELOCATE(yyss);
YYSTACK_RELOCATE(yyvs);
#if YYLSP_NEEDED
YYSTACK_RELOCATE(yyls);
#endif
#undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE(yyss1);
}
#endif
#endif /* no yyoverflow */
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
#if YYLSP_NEEDED
yylsp = yyls + yysize - 1;
#endif
YYDPRINTF((stderr, "Stack size increased to %lu\n",
(unsigned long int)yystacksize));
if (yyssp >= yyss + yystacksize - 1)
YYABORT;
}
YYDPRINTF((stderr, "Entering state %d\n", yystate));
goto yybackup;
/*-----------.
| yybackup. |
`-----------*/
yybackup:
/* Do appropriate processing given the current state. */
/* Read a lookahead token if we need one and don't already have one. */
/* yyresume: */
/* First try to decide what to do without reference to lookahead token. */
yyn = yypact[yystate];
if (yyn == YYFLAG)
goto yydefault;
/* Not known => get a lookahead token if don't already have one. */
/* yychar is either YYEMPTY or YYEOF
or a valid token in external form. */
if (yychar == YYEMPTY) {
YYDPRINTF((stderr, "Reading a token: "));
yychar = YYLEX;
}
/* Convert token to internal form (in yychar1) for indexing tables with */
if (yychar <= 0) /* This means end of input. */
{
yychar1 = 0;
yychar = YYEOF; /* Don't call YYLEX any more */
YYDPRINTF((stderr, "Now at end of input.\n"));
} else {
yychar1 = YYTRANSLATE(yychar);
#if YYDEBUG
/* We have to keep this `#if YYDEBUG', since we use variables
which are defined only if `YYDEBUG' is set. */
if (yydebug) {
YYFPRINTF(stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
/* Give the individual parser a way to print the precise
meaning of a token, for further debugging info. */
#ifdef YYPRINT
YYPRINT(stderr, yychar, yylval);
#endif
YYFPRINTF(stderr, ")\n");
}
#endif
}
yyn += yychar1;
if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
goto yydefault;
yyn = yytable[yyn];
/* yyn is what to do for this token type in this state.
Negative => reduce, -yyn is rule number.
Positive => shift, yyn is new state.
New state is final state => don't bother to shift,
just return success.
0, or most negative number => error. */
if (yyn < 0) {
if (yyn == YYFLAG)
goto yyerrlab;
yyn = -yyn;
goto yyreduce;
} else if (yyn == 0)
goto yyerrlab;
if (yyn == YYFINAL)
YYACCEPT;
/* Shift the lookahead token. */
YYDPRINTF((stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]));
/* Discard the token being shifted unless it is eof. */
if (yychar != YYEOF)
yychar = YYEMPTY;
*++yyvsp = yylval;
#if YYLSP_NEEDED
*++yylsp = yylloc;
#endif
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
yystate = yyn;
goto yynewstate;
/*-----------------------------------------------------------.
| yydefault -- do the default action for the current state. |
`-----------------------------------------------------------*/
yydefault:
yyn = yydefact[yystate];
if (yyn == 0)
goto yyerrlab;
goto yyreduce;
/*-----------------------------.
| yyreduce -- Do a reduction. |
`-----------------------------*/
yyreduce:
/* yyn is the number of a rule to reduce with. */
yylen = yyr2[yyn];
/* If YYLEN is nonzero, implement the default value of the action:
`$$ = $1'.
Otherwise, the following line sets YYVAL to the semantic value of
the lookahead token. This behavior is undocumented and Bison
users should not rely upon it. Assigning to YYVAL
unconditionally makes the parser a bit smaller, and it avoids a
GCC warning that YYVAL may be used uninitialized. */
yyval = yyvsp[1 - yylen];
#if YYLSP_NEEDED
/* Similarly for the default location. Let the user run additional
commands if for instance locations are ranges. */
yyloc = yylsp[1 - yylen];
YYLLOC_DEFAULT(yyloc, (yylsp - yylen), yylen);
#endif
#if YYDEBUG
/* We have to keep this `#if YYDEBUG', since we use variables which
are defined only if `YYDEBUG' is set. */
if (yydebug) {
int yyi;
YYFPRINTF(stderr, "Reducing via rule %d (line %d), ", yyn, yyrline[yyn]);
/* Print the symbols being reduced, and their result. */
for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++)
YYFPRINTF(stderr, "%s ", yytname[yyrhs[yyi]]);
YYFPRINTF(stderr, " -> %s\n", yytname[yyr1[yyn]]);
}
#endif
switch (yyn) {
case 1:
#line 69 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
ast_root = program(yyvsp[0].classes);
} break;
case 2:
#line 71 "ast.y"
{
exit(1);
} break;
case 3:
#line 76 "ast.y"
{
yyval.classes = single_Classes(yyvsp[0].class_);
parse_results = yyval.classes;
} break;
case 4:
#line 79 "ast.y"
{
yyval.classes =
append_Classes(yyvsp[-1].classes, single_Classes(yyvsp[0].class_));
parse_results = yyval.classes;
} break;
case 5:
#line 84 "ast.y"
{
curr_lineno = yyvsp[-7].lineno;
yyval.class_ = class_(yyvsp[-5].symbol, yyvsp[-4].symbol,
yyvsp[-1].features, yyvsp[-3].symbol);
} break;
case 6:
#line 90 "ast.y"
{
yyval.features = nil_Features();
} break;
case 7:
#line 92 "ast.y"
{
yyval.features = yyvsp[0].features;
} break;
case 8:
#line 97 "ast.y"
{
yyval.features = single_Features(yyvsp[0].feature);
} break;
case 9:
#line 99 "ast.y"
{
yyval.features =
append_Features(yyvsp[-1].features, single_Features(yyvsp[0].feature));
} break;
case 10:
#line 103 "ast.y"
{
curr_lineno = yyvsp[-5].lineno;
yyval.feature = method(yyvsp[-3].symbol, yyvsp[-2].formals,
yyvsp[-1].symbol, yyvsp[0].expression);
} break;
case 11:
#line 105 "ast.y"
{
curr_lineno = yyvsp[-4].lineno;
yyval.feature =
attr(yyvsp[-2].symbol, yyvsp[-1].symbol, yyvsp[0].expression);
} break;
case 12:
#line 109 "ast.y"
{
yyval.formals = nil_Formals();
} break;
case 13:
#line 111 "ast.y"
{
yyval.formals = yyvsp[0].formals;
} break;
case 14:
#line 116 "ast.y"
{
yyval.formals = single_Formals(yyvsp[0].formal);
} break;
case 15:
#line 118 "ast.y"
{
yyval.formals =
append_Formals(yyvsp[-1].formals, single_Formals(yyvsp[0].formal));
} break;
case 16:
#line 122 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.formal = formal(yyvsp[-1].symbol, yyvsp[0].symbol);
} break;
case 17:
#line 126 "ast.y"
{
yyval.expression = yyvsp[-2].expression;
yyval.expression->set_type(yyvsp[0].symbol);
} break;
case 18:
#line 130 "ast.y"
{
yyval.expression = yyvsp[-2].expression;
} break;
case 19:
#line 133 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = assign(yyvsp[-1].symbol, yyvsp[0].expression);
} break;
case 20:
#line 136 "ast.y"
{
curr_lineno = yyvsp[-5].lineno;
yyval.expression = static_dispatch(yyvsp[-3].expression, yyvsp[-2].symbol,
yyvsp[-1].symbol, yyvsp[0].expressions);
} break;
case 21:
#line 139 "ast.y"
{
curr_lineno = yyvsp[-4].lineno;
yyval.expression =
dispatch(yyvsp[-2].expression, yyvsp[-1].symbol, yyvsp[0].expressions);
} break;
case 22:
#line 142 "ast.y"
{
curr_lineno = yyvsp[-4].lineno;
yyval.expression =
cond(yyvsp[-2].expression, yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 23:
#line 145 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = loop(yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 24:
#line 148 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
yyval.expression = block(yyvsp[0].expressions);
} break;
case 25:
#line 151 "ast.y"
{
curr_lineno = yyvsp[-5].lineno;
yyval.expression = let(yyvsp[-3].symbol, yyvsp[-2].symbol,
yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 26:
#line 154 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = typcase(yyvsp[-1].expression, yyvsp[0].cases);
} break;
case 27:
#line 157 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
yyval.expression = new_(yyvsp[0].symbol);
} break;
case 28:
#line 160 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
yyval.expression = isvoid(yyvsp[0].expression);
} break;
case 29:
#line 163 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = plus(yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 30:
#line 166 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = sub(yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 31:
#line 169 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = mul(yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 32:
#line 172 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = divide(yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 33:
#line 175 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
yyval.expression = neg(yyvsp[0].expression);
} break;
case 34:
#line 178 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = lt(yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 35:
#line 181 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = eq(yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 36:
#line 184 "ast.y"
{
curr_lineno = yyvsp[-3].lineno;
yyval.expression = leq(yyvsp[-1].expression, yyvsp[0].expression);
} break;
case 37:
#line 187 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
yyval.expression = comp(yyvsp[0].expression);
} break;
case 38:
#line 190 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
yyval.expression = int_const(yyvsp[0].symbol);
} break;
case 39:
#line 193 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
yyval.expression = string_const(yyvsp[0].symbol);
} break;
case 40:
#line 196 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
if (yyvsp[0].symbol->get_string() == "1")
yyval.expression = bool_const(1);
else
yyval.expression = bool_const(0);
} break;
case 41:
#line 204 "ast.y"
{
curr_lineno = yyvsp[-2].lineno;
yyval.expression = object(yyvsp[0].symbol);
} break;
case 42:
#line 207 "ast.y"
{
curr_lineno = yyvsp[-1].lineno;
yyval.expression = no_expr();
} break;
case 43:
#line 211 "ast.y"
{
yyval.expressions = nil_Expressions();
} break;
case 44:
#line 213 "ast.y"
{
yyval.expressions = yyvsp[-1].expressions;
} break;
case 45:
#line 218 "ast.y"
{
yyval.expressions = single_Expressions(yyvsp[0].expression);
} break;
case 46:
#line 220 "ast.y"
{
yyval.expressions = append_Expressions(
yyvsp[-1].expressions, single_Expressions(yyvsp[0].expression));
} break;
case 47:
#line 225 "ast.y"
{
yyval.cases = single_Cases(yyvsp[0].case_);
} break;
case 48:
#line 227 "ast.y"
{
yyval.cases = append_Cases(yyvsp[-1].cases, single_Cases(yyvsp[0].case_));
} break;
case 49:
#line 232 "ast.y"
{
curr_lineno = yyvsp[-4].lineno;
yyval.case_ =
branch(yyvsp[-2].symbol, yyvsp[-1].symbol, yyvsp[0].expression);
} break;
}
#line 705 "/usr/share/bison/bison.simple"
yyvsp -= yylen;
yyssp -= yylen;
#if YYLSP_NEEDED
yylsp -= yylen;
#endif
#if YYDEBUG
if (yydebug) {
short *yyssp1 = yyss - 1;
YYFPRINTF(stderr, "state stack now");
while (yyssp1 != yyssp)
YYFPRINTF(stderr, " %d", *++yyssp1);
YYFPRINTF(stderr, "\n");
}
#endif
*++yyvsp = yyval;
#if YYLSP_NEEDED
*++yylsp = yyloc;
#endif
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
yyn = yyr1[yyn];
yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
yystate = yytable[yystate];
else
yystate = yydefgoto[yyn - YYNTBASE];
goto yynewstate;
/*------------------------------------.
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
/* If not already recovering from an error, report this error. */
if (!yyerrstatus) {
++yynerrs;
#ifdef YYERROR_VERBOSE
yyn = yypact[yystate];
if (yyn > YYFLAG && yyn < YYLAST) {
YYSIZE_T yysize = 0;
char *yymsg;
int yyx, yycount;
yycount = 0;
/* Start YYX at -YYN if negative to avoid negative indexes in
YYCHECK. */
for (yyx = yyn < 0 ? -yyn : 0;
yyx < (int)(sizeof(yytname) / sizeof(char *)); yyx++)
if (yycheck[yyx + yyn] == yyx)
yysize += yystrlen(yytname[yyx]) + 15, yycount++;
yysize += yystrlen("parse error, unexpected ") + 1;
yysize += yystrlen(yytname[YYTRANSLATE(yychar)]);
yymsg = (char *)YYSTACK_ALLOC(yysize);
if (yymsg != 0) {
char *yyp = yystpcpy(yymsg, "parse error, unexpected ");
yyp = yystpcpy(yyp, yytname[YYTRANSLATE(yychar)]);
if (yycount < 5) {
yycount = 0;
for (yyx = yyn < 0 ? -yyn : 0;
yyx < (int)(sizeof(yytname) / sizeof(char *)); yyx++)
if (yycheck[yyx + yyn] == yyx) {
const char *yyq = !yycount ? ", expecting " : " or ";
yyp = yystpcpy(yyp, yyq);
yyp = yystpcpy(yyp, yytname[yyx]);
yycount++;
}
}
yyerror(yymsg);
YYSTACK_FREE(yymsg);
} else
yyerror("parse error; also virtual memory exhausted");
} else
#endif /* defined (YYERROR_VERBOSE) */
yyerror("parse error");
}
goto yyerrlab1;
/*--------------------------------------------------.
| yyerrlab1 -- error raised explicitly by an action |
`--------------------------------------------------*/
yyerrlab1:
if (yyerrstatus == 3) {
/* If just tried and failed to reuse lookahead token after an
error, discard it. */
/* return failure if at end of input */
if (yychar == YYEOF)
YYABORT;
YYDPRINTF(
(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]));
yychar = YYEMPTY;
}
/* Else will try to reuse lookahead token after shifting the error
token. */
yyerrstatus = 3; /* Each real token shifted decrements this */
goto yyerrhandle;
/*-------------------------------------------------------------------.
| yyerrdefault -- current state does not do anything special for the |
| error token. |
`-------------------------------------------------------------------*/
yyerrdefault:
#if 0
/* This is wrong; only states that explicitly want error tokens
should shift them. */
/* If its default is to accept any token, ok. Otherwise pop it. */
yyn = yydefact[yystate];
if (yyn)
goto yydefault;
#endif
/*---------------------------------------------------------------.
| yyerrpop -- pop the current state because it cannot handle the |
| error token |
`---------------------------------------------------------------*/
yyerrpop:
if (yyssp == yyss)
YYABORT;
yyvsp--;
yystate = *--yyssp;
#if YYLSP_NEEDED
yylsp--;
#endif
#if YYDEBUG
if (yydebug) {
short *yyssp1 = yyss - 1;
YYFPRINTF(stderr, "Error: state stack now");
while (yyssp1 != yyssp)
YYFPRINTF(stderr, " %d", *++yyssp1);
YYFPRINTF(stderr, "\n");
}
#endif
/*--------------.
| yyerrhandle. |
`--------------*/
yyerrhandle:
yyn = yypact[yystate];
if (yyn == YYFLAG)
goto yyerrdefault;
yyn += YYTERROR;
if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
goto yyerrdefault;
yyn = yytable[yyn];
if (yyn < 0) {
if (yyn == YYFLAG)
goto yyerrpop;
yyn = -yyn;
goto yyreduce;
} else if (yyn == 0)
goto yyerrpop;
if (yyn == YYFINAL)
YYACCEPT;
YYDPRINTF((stderr, "Shifting error token, "));
*++yyvsp = yylval;
#if YYLSP_NEEDED
*++yylsp = yylloc;
#endif
yystate = yyn;
goto yynewstate;
/*-------------------------------------.
| yyacceptlab -- YYACCEPT comes here. |
`-------------------------------------*/
yyacceptlab:
yyresult = 0;
goto yyreturn;
/*-----------------------------------.
| yyabortlab -- YYABORT comes here. |
`-----------------------------------*/
yyabortlab:
yyresult = 1;
goto yyreturn;
/*---------------------------------------------.
| yyoverflowab -- parser overflow comes here. |
`---------------------------------------------*/
yyoverflowlab:
yyerror("parser stack overflow");
yyresult = 2;
/* Fall through. */
yyreturn:
#ifndef yyoverflow
if (yyss != yyssa)
YYSTACK_FREE(yyss);
#endif
return yyresult;
}
#line 237 "ast.y"
void ast_yyerror(char *) {
std::cerr << "??? unexpected error in ast parsing." << std::endl;
exit(1);
}
#line 2 "ast-lex.cc"
/* A lexical scanner generated by flex */
/* Scanner skeleton version:
* $Header:
* /home/vadve/Teaching/CVSClassRepository/CS426-Current/MPSolutions/mp2-text/cool-support/src/ast-lex.cc,v
* 1.1 2011-09-29 13:07:27 bmmoore Exp $
*/
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
#include <stdio.h>
#include <unistd.h>
/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
#ifdef c_plusplus
#ifndef __cplusplus
#define __cplusplus
#endif
#endif
#ifdef __cplusplus
#include <stdlib.h>
/* Use prototypes in function declarations. */
#define YY_USE_PROTOS
/* The "const" storage-class-modifier is valid. */
#define YY_USE_CONST
#else /* ! __cplusplus */
#if __STDC__
#define YY_USE_PROTOS
#define YY_USE_CONST
#endif /* __STDC__ */
#endif /* ! __cplusplus */
#ifdef __TURBOC__
#pragma warn - rch
#pragma warn - use
#include <io.h>
#include <stdlib.h>
#define YY_USE_CONST
#define YY_USE_PROTOS
#endif
#ifdef YY_USE_CONST
#define yyconst const
#else
#define yyconst
#endif
#ifdef YY_USE_PROTOS
#define YY_PROTO(proto) proto
#else
#define YY_PROTO(proto) ()
#endif
/* Returned upon end-of-file. */
#define YY_NULL 0
/* Promotes a possibly negative, possibly signed char to an unsigned
* integer for use as an array index. If the signed char is negative,
* we want to instead treat it as an 8-bit unsigned char, hence the
* double cast.
*/
#define YY_SC_TO_UI(c) ((unsigned int)(unsigned char)c)
/* Enter a start condition. This macro really ought to take a parameter,
* but we do it the disgusting crufty way forced on us by the ()-less
* definition of BEGIN.
*/
#define BEGIN yy_start = 1 + 2 *
/* Translate the current start state into a value that can be later handed
* to BEGIN to return to the state. The YYSTATE alias is for lex
* compatibility.
*/
#define YY_START ((yy_start - 1) / 2)
#define YYSTATE YY_START
/* Action number for EOF rule of a given start state. */
#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
/* Special action meaning "start processing a new file". */
#define YY_NEW_FILE yyrestart(yyin)
#define YY_END_OF_BUFFER_CHAR 0
/* Size of default input buffer. */
#define YY_BUF_SIZE 16384
typedef struct yy_buffer_state *YY_BUFFER_STATE;
extern int yyleng;
extern FILE *yyin, *yyout;
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
/* The funky do-while in the following #define is used to turn the definition
* int a single C statement (which needs a semi-colon terminator). This
* avoids problems with code like:
*
* if ( condition_holds )
* yyless( 5 );
* else
* do_something_else();
*
* Prior to using the do-while the compiler would get upset at the
* "else" because it interpreted the "if" statement as being all
* done when it reached the ';' after the yyless() call.
*/
/* Return all but the first 'n' matched characters back to the input stream. */
#define yyless(n) \
do { \
/* Undo effects of setting up yytext. */ \
*yy_cp = yy_hold_char; \
YY_RESTORE_YY_MORE_OFFSET \
yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
YY_DO_BEFORE_ACTION; /* set up yytext again */ \
} while (0)
#define unput(c) yyunput(c, yytext_ptr)
/* The following is because we cannot portably get our hands on size_t
* (without autoconf's help, which isn't available because we want
* flex-generated scanners to compile on their own).
*/
typedef unsigned int yy_size_t;
struct yy_buffer_state {
FILE *yy_input_file;
char *yy_ch_buf; /* input buffer */
char *yy_buf_pos; /* current position in input buffer */
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
yy_size_t yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
* delete it.
*/
int yy_is_our_buffer;
/* Whether this is an "interactive" input source; if so, and
* if we're using stdio for input, then we want to use getc()
* instead of fread(), to make sure we stop fetching input after
* each newline.
*/
int yy_is_interactive;
/* Whether we're considered to be at the beginning of a line.
* If so, '^' rules will be active on the next match, otherwise
* not.
*/
int yy_at_bol;
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
int yy_buffer_status;
#define YY_BUFFER_NEW 0
#define YY_BUFFER_NORMAL 1
/* When an EOF's been seen but there's still some text to process
* then we mark the buffer as YY_EOF_PENDING, to indicate that we
* shouldn't try reading from the input source any more. We might
* still have a bunch of tokens to match, though, because of
* possible backing-up.
*
* When we actually see the EOF, we change the status to "new"
* (via yyrestart()), so that the user can continue scanning by
* just pointing yyin at a new input file.
*/
#define YY_BUFFER_EOF_PENDING 2
};
static YY_BUFFER_STATE yy_current_buffer = 0;
/* We provide macros for accessing buffer states in case in the
* future we want to put the buffer states in a more general
* "scanner state".
*/
#define YY_CURRENT_BUFFER yy_current_buffer
/* yy_hold_char holds the character lost when yytext is formed. */
static char yy_hold_char;
static int yy_n_chars; /* number of characters read into yy_ch_buf */
int yyleng;
/* Points to current character in buffer. */
static char *yy_c_buf_p = (char *)0;
static int yy_init = 1; /* whether we need to initialize */
static int yy_start = 0; /* start state number */
/* Flag which is used to allow yywrap()'s to do buffer switches
* instead of setting up a fresh yyin. A bit of a hack ...
*/
static int yy_did_buffer_switch_on_eof;
void yyrestart YY_PROTO((FILE * input_file));
void yy_switch_to_buffer YY_PROTO((YY_BUFFER_STATE new_buffer));
void yy_load_buffer_state YY_PROTO((void));
YY_BUFFER_STATE yy_create_buffer YY_PROTO((FILE * file, int size));
void yy_delete_buffer YY_PROTO((YY_BUFFER_STATE b));
void yy_init_buffer YY_PROTO((YY_BUFFER_STATE b, FILE *file));
void yy_flush_buffer YY_PROTO((YY_BUFFER_STATE b));
#define YY_FLUSH_BUFFER yy_flush_buffer(yy_current_buffer)
YY_BUFFER_STATE yy_scan_buffer YY_PROTO((char *base, yy_size_t size));
YY_BUFFER_STATE yy_scan_string YY_PROTO((yyconst char *yy_str));
YY_BUFFER_STATE yy_scan_bytes YY_PROTO((yyconst char *bytes, int len));
static void *yy_flex_alloc YY_PROTO((yy_size_t));
static void *yy_flex_realloc YY_PROTO((void *, yy_size_t));
static void yy_flex_free YY_PROTO((void *));
#define yy_new_buffer yy_create_buffer
#define yy_set_interactive(is_interactive) \
{ \
if (!yy_current_buffer) \
yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE); \
yy_current_buffer->yy_is_interactive = is_interactive; \
}
#define yy_set_bol(at_bol) \
{ \
if (!yy_current_buffer) \
yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE); \
yy_current_buffer->yy_at_bol = at_bol; \
}
#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
#define FLEX_DEBUG
typedef unsigned char YY_CHAR;
FILE *yyin = (FILE *)0, *yyout = (FILE *)0;
typedef int yy_state_type;
#define FLEX_DEBUG
extern char *yytext;
#define yytext_ptr yytext
static yy_state_type yy_get_previous_state YY_PROTO((void));
static yy_state_type yy_try_NUL_trans YY_PROTO((yy_state_type current_state));
static int yy_get_next_buffer YY_PROTO((void));
static void yy_fatal_error YY_PROTO((yyconst char msg[]));
/* Done after the current pattern has been matched and before the
* corresponding action - sets up yytext.
*/
#define YY_DO_BEFORE_ACTION \
yytext_ptr = yy_bp; \
yyleng = (int)(yy_cp - yy_bp); \
yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \
yy_c_buf_p = yy_cp;
#define YY_NUM_RULES 47
#define YY_END_OF_BUFFER 48
static yyconst short int yy_accept[163] = {
0, 0, 0, 0, 0, 48, 47, 1, 37, 3, 35, 2, 36, 47, 46, 38, 45,
1, 3, 2, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 44, 45, 43, 41, 42, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 24,
0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 25, 17, 0, 0, 20,
22, 30, 0, 0, 0, 0, 0, 0, 19, 0, 0, 7, 0, 29, 0, 0,
26, 13, 0, 0, 0, 0, 14, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0,
16, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 9,
0, 21, 8, 31, 6, 0, 0, 34, 0, 0, 28, 0, 0, 32, 33, 4, 0,
15, 12, 0, 0, 0, 0, 0, 0, 0, 11, 0};
static yyconst int yy_ec[256] = {
0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4, 5, 1, 1,
1, 1, 6, 6, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 6, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 9, 1, 1,
10, 1, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
static yyconst int yy_meta[36] = {0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
static yyconst short int yy_base[166] = {
0, 0, 10, 18, 20, 180, 181, 23, 181, 172, 181, 171, 0, 19, 181,
181, 46, 34, 170, 169, 0, 10, 29, 34, 156, 147, 148, 23, 48, 46,
3, 160, 38, 34, 136, 181, 163, 181, 181, 181, 181, 181, 140, 138, 142,
141, 154, 153, 44, 40, 181, 135, 132, 129, 44, 135, 181, 129, 136, 58,
147, 136, 124, 129, 68, 141, 126, 132, 122, 136, 126, 123, 117, 119, 130,
117, 123, 118, 181, 115, 181, 181, 113, 120, 181, 181, 181, 65, 122, 107,
118, 104, 114, 181, 119, 114, 181, 109, 181, 116, 99,
181, 181, 116, 112, 114, 105, 181, 98, 88, 86, 107, 181, 91, 99, 93,
105, 91, 181, 96, 181, 83, 97, 89, 96, 95, 82, 81, 76, 94, 91,
86, 73, 181, 181, 88, 181, 181, 181, 181, 66, 78, 181, 69, 80, 181,
74, 70, 181, 181, 181, 73, 181, 181, 67, 56, 58, 72, 52, 68, 28,
181, 181, 96, 98, 6};
static yyconst short int yy_def[166] = {
0, 163, 163, 164, 164, 162, 162, 162, 162, 162, 162, 162, 165, 162, 162,
162, 162, 162, 162, 162, 165, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 0, 162, 162, 162};
static yyconst short int yy_nxt[217] = {
0, 6, 7, 7, 8, 9, 10, 11, 20, 6, 13, 6, 7, 7, 8,
9, 10, 11, 59, 6, 13, 6, 15, 6, 15, 17, 17, 16, 60, 16,
21, 22, 23, 24, 25, 26, 17, 17, 27, 42, 43, 28, 29, 30, 31,
32, 161, 52, 33, 34, 35, 44, 53, 36, 45, 37, 47, 46, 38, 48,
62, 57, 39, 54, 64, 65, 63, 73, 74, 75, 40, 80, 76, 55, 81,
85, 41, 58, 56, 91, 109, 160, 159, 158, 157, 156, 155, 154, 153, 152,
151, 86, 150, 149, 148, 110, 92, 12, 12, 14, 14,
147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133,
132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118,
117, 116, 115, 114, 113, 112, 111, 108, 107, 106, 105, 104, 103, 102, 101,
100, 99, 98, 97, 96, 95, 94, 93, 90, 89, 88, 87, 84, 83, 82,
79, 78, 77, 72, 71, 70, 69, 68, 67, 36, 66, 61, 51, 50, 49,
19, 18, 19, 18, 162, 5, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162};
static yyconst short int yy_chk[217] = {
0, 1, 1, 1, 1, 1, 1, 1, 165, 1, 1, 2, 2, 2, 2,
2, 2, 2, 30, 2, 2, 3, 3, 4, 4, 7, 7, 3, 30, 4,
13, 13, 13, 13, 13, 13, 17, 17, 13, 21, 21, 13, 13, 13, 13,
13, 160, 27, 13, 13, 16, 22, 27, 16, 22, 16, 23, 22, 16, 23,
32, 29, 16, 28, 33, 33, 32, 48, 48, 49, 16, 54, 49, 28, 54,
59, 16, 29, 28, 64, 87, 159, 158, 157, 156, 155, 154, 151, 147, 146,
144, 59, 143, 141, 140, 87, 64, 163, 163, 164, 164,
135, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 119, 117,
116, 115, 114, 113, 111, 110, 109, 108, 106, 105, 104, 103, 100, 99, 97,
95, 94, 92, 91, 90, 89, 88, 83, 82, 79, 77, 76, 75, 74, 73,
72, 71, 70, 69, 68, 67, 66, 65, 63, 62, 61, 60, 58, 57, 55,
53, 52, 51, 47, 46, 45, 44, 43, 42, 36, 34, 31, 26, 25, 24,
19, 18, 11, 9, 5, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
162};
static yy_state_type yy_last_accepting_state;
static char *yy_last_accepting_cpos;
extern int yy_flex_debug;
int yy_flex_debug = 0;
static yyconst short int yy_rule_linenum[47] = {
0, 47, 48, 51, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
82, 83, 84, 86, 89, 101, 103, 113, 114, 115, 116, 117, 118, 120, 125};
/* The intent behind this definition is that it'll catch
* any uses of REJECT which flex missed.
*/
#define REJECT reject_used_but_not_detected
#define yymore() yymore_used_but_not_detected
#define YY_MORE_ADJ 0
#define YY_RESTORE_YY_MORE_OFFSET
char *yytext;
#line 1 "ast.flex"
#define INITIAL 0
/*
* A scanner definition for COOL ASTs.
*/
#line 5 "ast.flex"
#include "ast_parse.h"
#include "stringtab.h"
#include "utils.h"
extern FILE *ast_file; /* we read from this file */
/* define YY_INPUT so we read from the FILE fin:
* This change makes it possible to use this scanner in
* the Cool compiler.
*/
#undef YY_INPUT
#define YY_INPUT(buf, result, max_size) \
if ((result = fread((char *)buf, sizeof(char), max_size, ast_file)) < 0) \
YY_FATAL_ERROR("read() in flex scanner failed");
char string_buf[MAX_STR_CONST]; /* to assemble string constants */
char *string_buf_ptr;
extern int verbose_flag;
YYSTYPE cool_yylval; /* needed to link ast code with utilities.cc */
#define yywrap() 1
#define STRING 1
#line 519 "ast-lex.cc"
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap YY_PROTO((void));
#else
extern int yywrap YY_PROTO((void));
#endif
#endif
#ifndef YY_NO_UNPUT
static void yyunput YY_PROTO((int c, char *buf_ptr));
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy YY_PROTO((char *, yyconst char *, int));
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen YY_PROTO((yyconst char *));
#endif
#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput YY_PROTO((void));
#else
static int input YY_PROTO((void));
#endif
#endif
#if YY_STACK_USED
static int yy_start_stack_ptr = 0;
static int yy_start_stack_depth = 0;
static int *yy_start_stack = 0;
#ifndef YY_NO_PUSH_STATE
static void yy_push_state YY_PROTO((int new_state));
#endif
#ifndef YY_NO_POP_STATE
static void yy_pop_state YY_PROTO((void));
#endif
#ifndef YY_NO_TOP_STATE
static int yy_top_state YY_PROTO((void));
#endif
#else
#define YY_NO_PUSH_STATE 1
#define YY_NO_POP_STATE 1
#define YY_NO_TOP_STATE 1
#endif
#ifdef YY_MALLOC_DECL
YY_MALLOC_DECL
#else
#if __STDC__
#ifndef __cplusplus
#include <stdlib.h>
#endif
#else
/* Just try to get by without declaring the routines. This will fail
* miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
* or sizeof(void*) != sizeof(int).
*/
#endif
#endif
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
#define YY_READ_BUF_SIZE 8192
#endif
/* Copy whatever the last rule matched to the standard output. */
#ifndef ECHO
/* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite().
*/
#define ECHO (void)fwrite(yytext, yyleng, 1, yyout)
#endif
/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
* is returned in "result".
*/
#ifndef YY_INPUT
#define YY_INPUT(buf, result, max_size) \
if (yy_current_buffer->yy_is_interactive) { \
int c = '*', n; \
for (n = 0; n < max_size && (c = getc(yyin)) != EOF && c != '\n'; ++n) \
buf[n] = (char)c; \
if (c == '\n') \
buf[n++] = (char)c; \
if (c == EOF && ferror(yyin)) \
YY_FATAL_ERROR("input in flex scanner failed"); \
result = n; \
} else if (((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin)) \
YY_FATAL_ERROR("input in flex scanner failed");
#endif
/* No semi-colon after return; correct usage is to write "yyterminate();" -
* we don't want an extra ';' after the "return" because that will cause
* some compilers to complain about unreachable statements.
*/
#ifndef yyterminate
#define yyterminate() return YY_NULL
#endif
/* Number of entries by which start-condition stack grows. */
#ifndef YY_START_STACK_INCR
#define YY_START_STACK_INCR 25
#endif
/* Report a fatal error. */
#ifndef YY_FATAL_ERROR
#define YY_FATAL_ERROR(msg) yy_fatal_error(msg)
#endif
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
#define YY_DECL int yylex YY_PROTO((void))
#endif
/* Code executed at the beginning of each rule, after yytext and yyleng
* have been set up.
*/
#ifndef YY_USER_ACTION
#define YY_USER_ACTION
#endif
/* Code executed at the end of each rule. */
#ifndef YY_BREAK
#define YY_BREAK break;
#endif
#define YY_RULE_SETUP YY_USER_ACTION
YY_DECL {
register yy_state_type yy_current_state;
register char *yy_cp = NULL, *yy_bp = NULL;
register int yy_act;
#line 45 "ast.flex"
#line 673 "ast-lex.cc"
if (yy_init) {
yy_init = 0;
#ifdef YY_USER_INIT
YY_USER_INIT;
#endif
if (!yy_start)
yy_start = 1; /* first start state */
if (!yyin)
yyin = stdin;
if (!yyout)
yyout = stdout;
if (!yy_current_buffer)
yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
yy_load_buffer_state();
}
while (1) /* loops until end-of-file is reached */
{
yy_cp = yy_c_buf_p;
/* Support of yytext. */
*yy_cp = yy_hold_char;
/* yy_bp points to the position in yy_ch_buf of the start of
* the current run.
*/
yy_bp = yy_cp;
yy_current_state = yy_start;
yy_match:
do {
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
if (yy_accept[yy_current_state]) {
yy_last_accepting_state = yy_current_state;
yy_last_accepting_cpos = yy_cp;
}
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
yy_current_state = (int)yy_def[yy_current_state];
if (yy_current_state >= 163)
yy_c = yy_meta[(unsigned int)yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
++yy_cp;
} while (yy_base[yy_current_state] != 181);
yy_find_action:
yy_act = yy_accept[yy_current_state];
if (yy_act == 0) { /* have to back up */
yy_cp = yy_last_accepting_cpos;
yy_current_state = yy_last_accepting_state;
yy_act = yy_accept[yy_current_state];
}
YY_DO_BEFORE_ACTION;
do_action: /* This label is used only to access EOF actions. */
if (yy_flex_debug) {
if (yy_act == 0)
fprintf(stderr, "--scanner backing up\n");
else if (yy_act < 47)
fprintf(stderr, "--accepting rule at line %d (\"%s\")\n",
yy_rule_linenum[yy_act], yytext);
else if (yy_act == 47)
fprintf(stderr, "--accepting default rule (\"%s\")\n", yytext);
else if (yy_act == 48)
fprintf(stderr, "--(end of buffer or a NUL)\n");
else
fprintf(stderr, "--EOF (start condition %d)\n", YY_START);
}
switch (yy_act) { /* beginning of action switch */
case 0: /* must back up */
/* undo the effects of YY_DO_BEFORE_ACTION */
*yy_cp = yy_hold_char;
yy_cp = yy_last_accepting_cpos;
yy_current_state = yy_last_accepting_state;
goto yy_find_action;
case 1:
YY_RULE_SETUP
#line 47 "ast.flex"
{
}
YY_BREAK
case 2:
YY_RULE_SETUP
#line 48 "ast.flex"
{
yylval.symbol = inttable.add_string(std::string(yytext, yyleng));
return (INT_CONST);
}
YY_BREAK
case 3:
YY_RULE_SETUP
#line 51 "ast.flex"
{
yylval.lineno = atoi(yytext + 1);
return (LINENO);
}
YY_BREAK
case 4:
YY_RULE_SETUP
#line 54 "ast.flex"
{
return (PROGRAM);
}
YY_BREAK
case 5:
YY_RULE_SETUP
#line 55 "ast.flex"
{
return (CLASS);
}
YY_BREAK
case 6:
YY_RULE_SETUP
#line 56 "ast.flex"
{
return (METHOD);
}
YY_BREAK
case 7:
YY_RULE_SETUP
#line 57 "ast.flex"
{
return (ATTR);
}
YY_BREAK
case 8:
YY_RULE_SETUP
#line 58 "ast.flex"
{
return (FORMAL);
}
YY_BREAK
case 9:
YY_RULE_SETUP
#line 59 "ast.flex"
{
return (BRANCH);
}
YY_BREAK
case 10:
YY_RULE_SETUP
#line 60 "ast.flex"
{
return (ASSIGN);
}
YY_BREAK
case 11:
YY_RULE_SETUP
#line 61 "ast.flex"
{
return (STATIC_DISPATCH);
}
YY_BREAK
case 12:
YY_RULE_SETUP
#line 62 "ast.flex"
{
return (DISPATCH);
}
YY_BREAK
case 13:
YY_RULE_SETUP
#line 63 "ast.flex"
{
return (COND);
}
YY_BREAK
case 14:
YY_RULE_SETUP
#line 64 "ast.flex"
{
return (LOOP);
}
YY_BREAK
case 15:
YY_RULE_SETUP
#line 65 "ast.flex"
{
return (TYPCASE);
}
YY_BREAK
case 16:
YY_RULE_SETUP
#line 66 "ast.flex"
{
return (BLOCK);
}
YY_BREAK
case 17:
YY_RULE_SETUP
#line 67 "ast.flex"
{
return (LET);
}
YY_BREAK
case 18:
YY_RULE_SETUP
#line 68 "ast.flex"
{
return (PLUS);
}
YY_BREAK
case 19:
YY_RULE_SETUP
#line 69 "ast.flex"
{
return (SUB);
}
YY_BREAK
case 20:
YY_RULE_SETUP
#line 70 "ast.flex"
{
return (MUL);
}
YY_BREAK
case 21:
YY_RULE_SETUP
#line 71 "ast.flex"
{
return (DIVIDE);
}
YY_BREAK
case 22:
YY_RULE_SETUP
#line 72 "ast.flex"
{
return (NEG);
}
YY_BREAK
case 23:
YY_RULE_SETUP
#line 73 "ast.flex"
{
return (LESSTHAN);
}
YY_BREAK
case 24:
YY_RULE_SETUP
#line 74 "ast.flex"
{
return (EQUAL);
}
YY_BREAK
case 25:
YY_RULE_SETUP
#line 75 "ast.flex"
{
return (LEQ);
}
YY_BREAK
case 26:
YY_RULE_SETUP
#line 76 "ast.flex"
{
return (COMP);
}
YY_BREAK
case 27:
YY_RULE_SETUP
#line 77 "ast.flex"
{
return (INT);
}
YY_BREAK
case 28:
YY_RULE_SETUP
#line 78 "ast.flex"
{
return (STR);
}
YY_BREAK
case 29:
YY_RULE_SETUP
#line 79 "ast.flex"
{
return (BOOL);
}
YY_BREAK
case 30:
YY_RULE_SETUP
#line 80 "ast.flex"
{
return (NEW);
}
YY_BREAK
case 31:
YY_RULE_SETUP
#line 81 "ast.flex"
{
return (ISVOID);
}
YY_BREAK
case 32:
YY_RULE_SETUP
#line 82 "ast.flex"
{
return (NO_EXPR);
}
YY_BREAK
case 33:
YY_RULE_SETUP
#line 83 "ast.flex"
{
return (NO_TYPE);
}
YY_BREAK
case 34:
YY_RULE_SETUP
#line 84 "ast.flex"
{
return (OBJECT);
}
YY_BREAK
case 35:
YY_RULE_SETUP
#line 86 "ast.flex"
{
return (*yytext);
}
YY_BREAK
case 36:
YY_RULE_SETUP
#line 89 "ast.flex"
{
yylval.symbol = idtable.add_string(std::string(yytext, yyleng));
return (IDENT);
}
YY_BREAK
/*
* String constants (C syntax, taken from lexdoc(1) )
* Escape sequence \c is accepted for all characters c. Except for
* \n \t \b \f, the result is c.
*
*/
case 37:
YY_RULE_SETUP
#line 101 "ast.flex"
string_buf_ptr = string_buf;
BEGIN(STRING);
YY_BREAK
case 38:
YY_RULE_SETUP
#line 103 "ast.flex"
{
/* saw closing quote - all done */
BEGIN(INITIAL);
*string_buf_ptr = '\0';
yylval.symbol = stringtable.add_string(std::string(string_buf));
return (STR_CONST);
}
YY_BREAK
case 39:
YY_RULE_SETUP
#line 113 "ast.flex"
{
*string_buf_ptr++ = '\n';
}
YY_BREAK
case 40:
YY_RULE_SETUP
#line 114 "ast.flex"
{
*string_buf_ptr++ = '\t';
}
YY_BREAK
case 41:
YY_RULE_SETUP
#line 115 "ast.flex"
{
*string_buf_ptr++ = '\b';
}
YY_BREAK
case 42:
YY_RULE_SETUP
#line 116 "ast.flex"
{
*string_buf_ptr++ = '\f';
}
YY_BREAK
case 43:
YY_RULE_SETUP
#line 117 "ast.flex"
{
*string_buf_ptr++ = '\\';
}
YY_BREAK
case 44:
YY_RULE_SETUP
#line 118 "ast.flex"
{
*string_buf_ptr++ = '\"';
}
YY_BREAK
case 45:
YY_RULE_SETUP
#line 120 "ast.flex"
{
/* unprintable characters are represented as octal numbers */
*string_buf_ptr++ = strtol(yytext + 1, 0, 8);
}
YY_BREAK
case 46:
YY_RULE_SETUP
#line 125 "ast.flex"
{
*string_buf_ptr++ = yytext[0];
}
YY_BREAK
case YY_STATE_EOF(INITIAL):
case YY_STATE_EOF(STRING):
#line 127 "ast.flex"
{
yyterminate();
}
YY_BREAK
case 47:
YY_RULE_SETUP
#line 129 "ast.flex"
ECHO;
YY_BREAK
#line 1031 "ast-lex.cc"
case YY_END_OF_BUFFER: {
/* Amount of text matched not including the EOB char. */
int yy_amount_of_matched_text = (int)(yy_cp - yytext_ptr) - 1;
/* Undo the effects of YY_DO_BEFORE_ACTION. */
*yy_cp = yy_hold_char;
YY_RESTORE_YY_MORE_OFFSET
if (yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW) {
/* We're scanning a new file or input source. It's
* possible that this happened because the user
* just pointed yyin at a new source and called
* yylex(). If so, then we have to assure
* consistency between yy_current_buffer and our
* globals. Here is the right place to do so, because
* this is the first action (other than possibly a
* back-up) that will match for the new input source.
*/
yy_n_chars = yy_current_buffer->yy_n_chars;
yy_current_buffer->yy_input_file = yyin;
yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
}
/* Note that here we test for yy_c_buf_p "<=" to the position
* of the first EOB in the buffer, since yy_c_buf_p will
* already have been incremented past the NUL character
* (since all states make transitions on EOB to the
* end-of-buffer state). Contrast this with the test
* in input().
*/
if (yy_c_buf_p <=
&yy_current_buffer
->yy_ch_buf[yy_n_chars]) { /* This was really a NUL. */
yy_state_type yy_next_state;
yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
yy_current_state = yy_get_previous_state();
/* Okay, we're now positioned to make the NUL
* transition. We couldn't have
* yy_get_previous_state() go ahead and do it
* for us because it doesn't know how to deal
* with the possibility of jamming (and we don't
* want to build jamming into it because then it
* will run more slowly).
*/
yy_next_state = yy_try_NUL_trans(yy_current_state);
yy_bp = yytext_ptr + YY_MORE_ADJ;
if (yy_next_state) {
/* Consume the NUL. */
yy_cp = ++yy_c_buf_p;
yy_current_state = yy_next_state;
goto yy_match;
}
else {
yy_cp = yy_c_buf_p;
goto yy_find_action;
}
}
else
switch (yy_get_next_buffer()) {
case EOB_ACT_END_OF_FILE: {
yy_did_buffer_switch_on_eof = 0;
if (yywrap()) {
/* Note: because we've taken care in
* yy_get_next_buffer() to have set up
* yytext, we can now set up
* yy_c_buf_p so that if some total
* hoser (like flex itself) wants to
* call the scanner after we return the
* YY_NULL, it'll still work - another
* YY_NULL will get returned.
*/
yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
yy_act = YY_STATE_EOF(YY_START);
goto do_action;
}
else {
if (!yy_did_buffer_switch_on_eof)
YY_NEW_FILE;
}
break;
}
case EOB_ACT_CONTINUE_SCAN:
yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
yy_current_state = yy_get_previous_state();
yy_cp = yy_c_buf_p;
yy_bp = yytext_ptr + YY_MORE_ADJ;
goto yy_match;
case EOB_ACT_LAST_MATCH:
yy_c_buf_p = &yy_current_buffer->yy_ch_buf[yy_n_chars];
yy_current_state = yy_get_previous_state();
yy_cp = yy_c_buf_p;
yy_bp = yytext_ptr + YY_MORE_ADJ;
goto yy_find_action;
}
break;
}
default:
YY_FATAL_ERROR("fatal flex scanner internal error--no action found");
} /* end of action switch */
} /* end of scanning one token */
} /* end of yylex */
/* yy_get_next_buffer - try to read in a new buffer
*
* Returns a code representing an action:
* EOB_ACT_LAST_MATCH -
* EOB_ACT_CONTINUE_SCAN - continue scanning from current position
* EOB_ACT_END_OF_FILE - end of file
*/
static int yy_get_next_buffer() {
register char *dest = yy_current_buffer->yy_ch_buf;
register char *source = yytext_ptr;
register int number_to_move, i;
int ret_val;
if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
YY_FATAL_ERROR("fatal flex scanner internal error--end of buffer missed");
if (yy_current_buffer->yy_fill_buffer ==
0) { /* Don't try to fill the buffer, so this is an EOF. */
if (yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1) {
/* We matched a single character, the EOB, so
* treat this as a final EOF.
*/
return EOB_ACT_END_OF_FILE;
}
else {
/* We matched some text prior to the EOB, first
* process it.
*/
return EOB_ACT_LAST_MATCH;
}
}
/* Try to read more data. */
/* First move last chars to start of buffer. */
number_to_move = (int)(yy_c_buf_p - yytext_ptr) - 1;
for (i = 0; i < number_to_move; ++i)
*(dest++) = *(source++);
if (yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING)
/* don't do the read, it's not guaranteed to return an EOF,
* just force an EOF
*/
yy_current_buffer->yy_n_chars = yy_n_chars = 0;
else {
int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1;
while (num_to_read <= 0) { /* Not enough room in the buffer - grow it. */
#ifdef YY_USES_REJECT
YY_FATAL_ERROR("input buffer overflow, can't enlarge buffer because "
"scanner uses REJECT");
#else
/* just a shorter name for the current buffer */
YY_BUFFER_STATE b = yy_current_buffer;
int yy_c_buf_p_offset = (int)(yy_c_buf_p - b->yy_ch_buf);
if (b->yy_is_our_buffer) {
int new_size = b->yy_buf_size * 2;
if (new_size <= 0)
b->yy_buf_size += b->yy_buf_size / 8;
else
b->yy_buf_size *= 2;
b->yy_ch_buf = (char *)
/* Include room in for 2 EOB chars. */
yy_flex_realloc((void *)b->yy_ch_buf, b->yy_buf_size + 2);
} else
/* Can't grow it, we don't own it. */
b->yy_ch_buf = 0;
if (!b->yy_ch_buf)
YY_FATAL_ERROR("fatal error - scanner input buffer overflow");
yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1;
#endif
}
if (num_to_read > YY_READ_BUF_SIZE)
num_to_read = YY_READ_BUF_SIZE;
/* Read in more data. */
YY_INPUT((&yy_current_buffer->yy_ch_buf[number_to_move]), yy_n_chars,
num_to_read);
yy_current_buffer->yy_n_chars = yy_n_chars;
}
if (yy_n_chars == 0) {
if (number_to_move == YY_MORE_ADJ) {
ret_val = EOB_ACT_END_OF_FILE;
yyrestart(yyin);
}
else {
ret_val = EOB_ACT_LAST_MATCH;
yy_current_buffer->yy_buffer_status = YY_BUFFER_EOF_PENDING;
}
}
else
ret_val = EOB_ACT_CONTINUE_SCAN;
yy_n_chars += number_to_move;
yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
return ret_val;
}
/* yy_get_previous_state - get the state just before the EOB char was reached */
static yy_state_type yy_get_previous_state() {
register yy_state_type yy_current_state;
register char *yy_cp;
yy_current_state = yy_start;
for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp) {
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
if (yy_accept[yy_current_state]) {
yy_last_accepting_state = yy_current_state;
yy_last_accepting_cpos = yy_cp;
}
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
yy_current_state = (int)yy_def[yy_current_state];
if (yy_current_state >= 163)
yy_c = yy_meta[(unsigned int)yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
}
return yy_current_state;
}
/* yy_try_NUL_trans - try to make a transition on the NUL character
*
* synopsis
* next_state = yy_try_NUL_trans( current_state );
*/
#ifdef YY_USE_PROTOS
static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state)
#else
static yy_state_type
yy_try_NUL_trans(yy_current_state) yy_state_type yy_current_state;
#endif
{
register int yy_is_jam;
register char *yy_cp = yy_c_buf_p;
register YY_CHAR yy_c = 1;
if (yy_accept[yy_current_state]) {
yy_last_accepting_state = yy_current_state;
yy_last_accepting_cpos = yy_cp;
}
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
yy_current_state = (int)yy_def[yy_current_state];
if (yy_current_state >= 163)
yy_c = yy_meta[(unsigned int)yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
yy_is_jam = (yy_current_state == 162);
return yy_is_jam ? 0 : yy_current_state;
}
#ifndef YY_NO_UNPUT
#ifdef YY_USE_PROTOS
static void yyunput(int c, register char *yy_bp)
#else
static void yyunput(c, yy_bp) int c;
register char *yy_bp;
#endif
{
register char *yy_cp = yy_c_buf_p;
/* undo effects of setting up yytext */
*yy_cp = yy_hold_char;
if (yy_cp < yy_current_buffer->yy_ch_buf +
2) { /* need to shift things up to make room */
/* +2 for EOB chars. */
register int number_to_move = yy_n_chars + 2;
register char *dest =
&yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size + 2];
register char *source = &yy_current_buffer->yy_ch_buf[number_to_move];
while (source > yy_current_buffer->yy_ch_buf)
*--dest = *--source;
yy_cp += (int)(dest - source);
yy_bp += (int)(dest - source);
yy_current_buffer->yy_n_chars = yy_n_chars = yy_current_buffer->yy_buf_size;
if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
YY_FATAL_ERROR("flex scanner push-back overflow");
}
*--yy_cp = (char)c;
yytext_ptr = yy_bp;
yy_hold_char = *yy_cp;
yy_c_buf_p = yy_cp;
}
#endif /* ifndef YY_NO_UNPUT */
#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput()
#else
static int input()
#endif
{
int c;
*yy_c_buf_p = yy_hold_char;
if (*yy_c_buf_p == YY_END_OF_BUFFER_CHAR) {
/* yy_c_buf_p now points to the character we want to return.
* If this occurs *before* the EOB characters, then it's a
* valid NUL; if not, then we've hit the end of the buffer.
*/
if (yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars])
/* This was really a NUL. */
*yy_c_buf_p = '\0';
else { /* need more input */
int offset = yy_c_buf_p - yytext_ptr;
++yy_c_buf_p;
switch (yy_get_next_buffer()) {
case EOB_ACT_LAST_MATCH:
/* This happens because yy_g_n_b()
* sees that we've accumulated a
* token and flags that we need to
* try matching the token before
* proceeding. But for input(),
* there's no matching to consider.
* So convert the EOB_ACT_LAST_MATCH
* to EOB_ACT_END_OF_FILE.
*/
/* Reset buffer status. */
yyrestart(yyin);
/* fall through */
case EOB_ACT_END_OF_FILE: {
if (yywrap())
return EOF;
if (!yy_did_buffer_switch_on_eof)
YY_NEW_FILE;
#ifdef __cplusplus
return yyinput();
#else
return input();
#endif
}
case EOB_ACT_CONTINUE_SCAN:
yy_c_buf_p = yytext_ptr + offset;
break;
}
}
}
c = *(unsigned char *)yy_c_buf_p; /* cast for 8-bit char's */
*yy_c_buf_p = '\0'; /* preserve yytext */
yy_hold_char = *++yy_c_buf_p;
return c;
}
#endif /* YY_NO_INPUT */
#ifdef YY_USE_PROTOS
void yyrestart(FILE *input_file)
#else
void yyrestart(input_file) FILE *input_file;
#endif
{
if (!yy_current_buffer)
yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
yy_init_buffer(yy_current_buffer, input_file);
yy_load_buffer_state();
}
#ifdef YY_USE_PROTOS
void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer)
#else
void yy_switch_to_buffer(new_buffer) YY_BUFFER_STATE new_buffer;
#endif
{
if (yy_current_buffer == new_buffer)
return;
if (yy_current_buffer) {
/* Flush out information for old buffer. */
*yy_c_buf_p = yy_hold_char;
yy_current_buffer->yy_buf_pos = yy_c_buf_p;
yy_current_buffer->yy_n_chars = yy_n_chars;
}
yy_current_buffer = new_buffer;
yy_load_buffer_state();
/* We don't actually know whether we did this switch during
* EOF (yywrap()) processing, but the only time this flag
* is looked at is after yywrap() is called, so it's safe
* to go ahead and always set it.
*/
yy_did_buffer_switch_on_eof = 1;
}
#ifdef YY_USE_PROTOS
void yy_load_buffer_state(void)
#else
void yy_load_buffer_state()
#endif
{
yy_n_chars = yy_current_buffer->yy_n_chars;
yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
yyin = yy_current_buffer->yy_input_file;
yy_hold_char = *yy_c_buf_p;
}
#ifdef YY_USE_PROTOS
YY_BUFFER_STATE yy_create_buffer(FILE *file, int size)
#else
YY_BUFFER_STATE yy_create_buffer(file, size) FILE *file;
int size;
#endif
{
YY_BUFFER_STATE b;
b = (YY_BUFFER_STATE)yy_flex_alloc(sizeof(struct yy_buffer_state));
if (!b)
YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
b->yy_buf_size = size;
/* yy_ch_buf has to be 2 characters longer than the size given because
* we need to put in 2 end-of-buffer characters.
*/
b->yy_ch_buf = (char *)yy_flex_alloc(b->yy_buf_size + 2);
if (!b->yy_ch_buf)
YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
b->yy_is_our_buffer = 1;
yy_init_buffer(b, file);
return b;
}
#ifdef YY_USE_PROTOS
void yy_delete_buffer(YY_BUFFER_STATE b)
#else
void yy_delete_buffer(b) YY_BUFFER_STATE b;
#endif
{
if (!b)
return;
if (b == yy_current_buffer)
yy_current_buffer = (YY_BUFFER_STATE)0;
if (b->yy_is_our_buffer)
yy_flex_free((void *)b->yy_ch_buf);
yy_flex_free((void *)b);
}
#ifdef YY_USE_PROTOS
void yy_init_buffer(YY_BUFFER_STATE b, FILE *file)
#else
void yy_init_buffer(b, file) YY_BUFFER_STATE b;
FILE *file;
#endif
{
yy_flush_buffer(b);
b->yy_input_file = file;
b->yy_fill_buffer = 1;
#if YY_ALWAYS_INTERACTIVE
b->yy_is_interactive = 1;
#else
#if YY_NEVER_INTERACTIVE
b->yy_is_interactive = 0;
#else
b->yy_is_interactive = file ? (isatty(fileno(file)) > 0) : 0;
#endif
#endif
}
#ifdef YY_USE_PROTOS
void yy_flush_buffer(YY_BUFFER_STATE b)
#else
void yy_flush_buffer(b) YY_BUFFER_STATE b;
#endif
{
if (!b)
return;
b->yy_n_chars = 0;
/* We always need two end-of-buffer characters. The first causes
* a transition to the end-of-buffer state. The second causes
* a jam in that state.
*/
b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
b->yy_buf_pos = &b->yy_ch_buf[0];
b->yy_at_bol = 1;
b->yy_buffer_status = YY_BUFFER_NEW;
if (b == yy_current_buffer)
yy_load_buffer_state();
}
#ifndef YY_NO_SCAN_BUFFER
#ifdef YY_USE_PROTOS
YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size)
#else
YY_BUFFER_STATE yy_scan_buffer(base, size) char *base;
yy_size_t size;
#endif
{
YY_BUFFER_STATE b;
if (size < 2 || base[size - 2] != YY_END_OF_BUFFER_CHAR ||
base[size - 1] != YY_END_OF_BUFFER_CHAR)
/* They forgot to leave room for the EOB's. */
return 0;
b = (YY_BUFFER_STATE)yy_flex_alloc(sizeof(struct yy_buffer_state));
if (!b)
YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()");
b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
b->yy_input_file = 0;
b->yy_n_chars = b->yy_buf_size;
b->yy_is_interactive = 0;
b->yy_at_bol = 1;
b->yy_fill_buffer = 0;
b->yy_buffer_status = YY_BUFFER_NEW;
yy_switch_to_buffer(b);
return b;
}
#endif
#ifndef YY_NO_SCAN_STRING
#ifdef YY_USE_PROTOS
YY_BUFFER_STATE yy_scan_string(yyconst char *yy_str)
#else
YY_BUFFER_STATE yy_scan_string(yy_str) yyconst char *yy_str;
#endif
{
int len;
for (len = 0; yy_str[len]; ++len)
;
return yy_scan_bytes(yy_str, len);
}
#endif
#ifndef YY_NO_SCAN_BYTES
#ifdef YY_USE_PROTOS
YY_BUFFER_STATE yy_scan_bytes(yyconst char *bytes, int len)
#else
YY_BUFFER_STATE yy_scan_bytes(bytes, len) yyconst char *bytes;
int len;
#endif
{
YY_BUFFER_STATE b;
char *buf;
yy_size_t n;
int i;
/* Get memory for full buffer, including space for trailing EOB's. */
n = len + 2;
buf = (char *)yy_flex_alloc(n);
if (!buf)
YY_FATAL_ERROR("out of dynamic memory in yy_scan_bytes()");
for (i = 0; i < len; ++i)
buf[i] = bytes[i];
buf[len] = buf[len + 1] = YY_END_OF_BUFFER_CHAR;
b = yy_scan_buffer(buf, n);
if (!b)
YY_FATAL_ERROR("bad buffer in yy_scan_bytes()");
/* It's okay to grow etc. this buffer, and we should throw it
* away when we're done.
*/
b->yy_is_our_buffer = 1;
return b;
}
#endif
#ifndef YY_NO_PUSH_STATE
#ifdef YY_USE_PROTOS
static void yy_push_state(int new_state)
#else
static void yy_push_state(new_state) int new_state;
#endif
{
if (yy_start_stack_ptr >= yy_start_stack_depth) {
yy_size_t new_size;
yy_start_stack_depth += YY_START_STACK_INCR;
new_size = yy_start_stack_depth * sizeof(int);
if (!yy_start_stack)
yy_start_stack = (int *)yy_flex_alloc(new_size);
else
yy_start_stack = (int *)yy_flex_realloc((void *)yy_start_stack, new_size);
if (!yy_start_stack)
YY_FATAL_ERROR("out of memory expanding start-condition stack");
}
yy_start_stack[yy_start_stack_ptr++] = YY_START;
BEGIN(new_state);
}
#endif
#ifndef YY_NO_POP_STATE
static void yy_pop_state() {
if (--yy_start_stack_ptr < 0)
YY_FATAL_ERROR("start-condition stack underflow");
BEGIN(yy_start_stack[yy_start_stack_ptr]);
}
#endif
#ifndef YY_NO_TOP_STATE
static int yy_top_state() { return yy_start_stack[yy_start_stack_ptr - 1]; }
#endif
#ifndef YY_EXIT_FAILURE
#define YY_EXIT_FAILURE 2
#endif
#ifdef YY_USE_PROTOS
static void yy_fatal_error(yyconst char msg[])
#else
static void yy_fatal_error(msg) char msg[];
#endif
{
(void)fprintf(stderr, "%s\n", msg);
exit(YY_EXIT_FAILURE);
}
/* Redefine yyless() so it works in section 3 code. */
#undef yyless
#define yyless(n) \
do { \
/* Undo effects of setting up yytext. */ \
yytext[yyleng] = yy_hold_char; \
yy_c_buf_p = yytext + n; \
yy_hold_char = *yy_c_buf_p; \
*yy_c_buf_p = '\0'; \
yyleng = n; \
} while (0)
/* Internal utility routines. */
#ifndef yytext_ptr
#ifdef YY_USE_PROTOS
static void yy_flex_strncpy(char *s1, yyconst char *s2, int n)
#else
static void yy_flex_strncpy(s1, s2, n) char *s1;
yyconst char *s2;
int n;
#endif
{
register int i;
for (i = 0; i < n; ++i)
s1[i] = s2[i];
}
#endif
#ifdef YY_NEED_STRLEN
#ifdef YY_USE_PROTOS
static int yy_flex_strlen(yyconst char *s)
#else
static int yy_flex_strlen(s) yyconst char *s;
#endif
{
register int n;
for (n = 0; s[n]; ++n)
;
return n;
}
#endif
#ifdef YY_USE_PROTOS
static void *yy_flex_alloc(yy_size_t size)
#else
static void *yy_flex_alloc(size) yy_size_t size;
#endif
{
return (void *)malloc(size);
}
#ifdef YY_USE_PROTOS
static void *yy_flex_realloc(void *ptr, yy_size_t size)
#else
static void *yy_flex_realloc(ptr, size) void *ptr;
yy_size_t size;
#endif
{
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
* that use void* generic pointers. It works with the latter
* because both ANSI C and C++ allow castless assignment from
* any pointer type to void*, and deal with argument conversions
* as though doing an assignment.
*/
return (void *)realloc((char *)ptr, size);
}
#ifdef YY_USE_PROTOS
static void yy_flex_free(void *ptr)
#else
static void yy_flex_free(ptr) void *ptr;
#endif
{
free(ptr);
}
#if YY_MAIN
int main() {
yylex();
return 0;
}
#endif
#line 129 "ast.flex"
//
// See copyright.h for copyright notice and limitation of liability
// and disclaimer of warranty provisions.
//
#include "copyright.h"
#ifndef _UTILS_H_
#define _UTILS_H_
#include "stringtab.h"
#include <ostream>
std::string pad(int n);
void print_escaped_string(std::ostream &str, const std::string &s);
void dump_Boolean(std::ostream &stream, int padding, bool b);
void dump_Symbol(std::ostream &s, int n, Symbol sym);
#endif
//
// See copyright.h for copyright notice and limitation of liability
// and disclaimer of warranty provisions.
//
#include "copyright.h"
#ifndef TREE_H
#define TREE_H
///////////////////////////////////////////////////////////////////////////
//
// file: tree.h
//
// This file defines the basic class of tree node and list
//
///////////////////////////////////////////////////////////////////////////
#include "utils.h"
#include <iostream>
/////////////////////////////////////////////////////////////////////
//
// tree_node
//
// All APS nodes are derived from tree_node. There is a
// protected field:
// int line_number line in the source file from which this node came;
// this is read from a global variable when the
// node is created.
//
//
//
// The public methods are:
// tree_node()
// builds a new tree_node. The type field is NULL, the
// line_number is set to the value of the global yylineno.
//
// void dump(std::ostream& s,int n);
// dump is a pretty printer for tree nodes. The std::ostream argument
// is the output stream on which the node is to be printed; n is
// the number of spaces to indent the output.
//
// int get_line_number(); return the line number
// Symbol get_type(); return the type
//
// tree_node *set(tree_node *t)
// sets the line number and type of "this" to the values in
// the argument tree_node. Returns "this".
//
//
////////////////////////////////////////////////////////////////////////////
class tree_node {
protected:
int line_number; // stash the line number when node is made
public:
tree_node();
virtual tree_node *copy() = 0;
virtual void dump(std::ostream &stream, int n) = 0;
int get_line_number();
tree_node *set(tree_node *);
virtual ~tree_node() {}
};
///////////////////////////////////////////////////////////////////
//
// Lists of APS objects are implemented by the "list_node"
// template. List elements have type Elem. The interface is:
//
// tree_node *copy()
// list_node<Elem> *copy_list()
//
// These functions have identical behavior; they return a deep
// copy of the list (i.e., all elements of the list are copied).
// When possible, the second function should be used, as it
// has a more accurate result type. The "copy" function is for
// copying an entire APS tree of which a list is just one component
// (see the definition of copy() in class tree_node).
//
// Elem nth(int n);
// returns the nth element of a list. If the list has fewer than n
// elements, an error is generated.
//
// int first();
// int next(int n);
// int more(int n);
// These three functions define a simple iterator for stepping through
// list elements in order. If l is a list, a typical use would be:
//
// for(int i = l->first(); l->more(i); i = l->next(i))
// ... operate on l->nth(i) ...
//
//
// int len()
// returns the length of the list
//
// nth_length(int n, int &len);
// Returns the nth element of the list or NULL if there are not n elements.
// "len" is set to the length of the list. This method is used internally
// by the APS package to efficiently traverse the list representation.
//
// static list_node<Elem> *nil();
// static list_node<Elem> *single(Elem);
// static list_node<Elem> *append(list_node<Elem> *, list_node<Elem> *);
//
// These three functions construct an empty list, a list of one element,
// and append two lists, respectively. Note that the functions are static;
// there is no "this" parameter. Example uses:
//
// list_node<Elem>::nil();
// list_node<Elem>::single(e); where "e" has type Elem
// list_node<Elem>::append(l1,l2);
//
//////////////////////////////////////////////////////////////////////////////
template <class Elem> class list_node;
template <class Elem> class list_node_iterator {
list_node<Elem> *list;
int index;
public:
list_node_iterator(list_node<Elem> *list_) : list(list_), index(0) {}
list_node_iterator(list_node<Elem> *list_, int index_)
: list(list_), index(index_) {}
list_node_iterator<Elem> &operator++() {
++index;
return *this;
}
Elem operator*() const { return list->nth(index); }
bool operator!=(const list_node_iterator<Elem> &rhs) const {
return index != rhs.index;
}
};
template <class Elem> class list_node : public tree_node {
public:
tree_node *copy() { return copy_list(); }
Elem nth(int n);
//
// The next three define a simple iterator.
//
int first() { return 0; }
int next(int n) { return n + 1; }
int more(int n) { return (n < len()); }
virtual list_node<Elem> *copy_list() = 0;
virtual int len() = 0;
virtual Elem nth_length(int n, int &len) = 0;
static list_node<Elem> *nil();
static list_node<Elem> *single(Elem);
static list_node<Elem> *append(list_node<Elem> *l1, list_node<Elem> *l2);
};
template <class Elem> list_node_iterator<Elem> begin(list_node<Elem> &list) {
return list_node_iterator<Elem>(&list);
}
template <class Elem> list_node_iterator<Elem> end(list_node<Elem> &list) {
return list_node_iterator<Elem>(&list, list.len());
}
template <class Elem> list_node_iterator<Elem> begin(list_node<Elem> *list) {
return list_node_iterator<Elem>(list);
}
template <class Elem> list_node_iterator<Elem> end(list_node<Elem> *list) {
return list_node_iterator<Elem>(list, list->len());
}
template <class Elem> class nil_node : public list_node<Elem> {
public:
list_node<Elem> *copy_list();
int len();
Elem nth_length(int n, int &len);
void dump(std::ostream &stream, int n);
};
template <class Elem> class single_list_node : public list_node<Elem> {
Elem elem;
public:
single_list_node(Elem t) { elem = t; }
list_node<Elem> *copy_list();
int len();
Elem nth_length(int n, int &len);
void dump(std::ostream &stream, int n);
};
template <class Elem> class append_node : public list_node<Elem> {
private:
list_node<Elem> *some, *rest;
public:
append_node(list_node<Elem> *l1, list_node<Elem> *l2) {
some = l1;
rest = l2;
}
list_node<Elem> *copy_list();
int len();
Elem nth_length(int n, int &len);
void dump(std::ostream &stream, int n);
};
template <class Elem> single_list_node<Elem> *list(Elem x);
template <class Elem> append_node<Elem> *cons(Elem x, list_node<Elem> *l);
template <class Elem> append_node<Elem> *xcons(list_node<Elem> *l, Elem x);
template <class Elem> list_node<Elem> *list_node<Elem>::nil() {
return new nil_node<Elem>();
}
template <class Elem> list_node<Elem> *list_node<Elem>::single(Elem e) {
return new single_list_node<Elem>(e);
}
template <class Elem>
list_node<Elem> *list_node<Elem>::append(list_node<Elem> *l1,
list_node<Elem> *l2) {
return new append_node<Elem>(l1, l2);
}
///////////////////////////////////////////////////////////////////////////
//
// list_node::nth
//
// function to find the nth element of the list
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> Elem list_node<Elem>::nth(int n) {
int len;
Elem tmp = nth_length(n, len);
if (tmp) {
return tmp;
}
throw std::runtime_error("nth: outside the range of the list");
}
///////////////////////////////////////////////////////////////////////////
//
// nil_node::copy_list
//
// return the deep copy of the nil_node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> list_node<Elem> *nil_node<Elem>::copy_list() {
return new nil_node<Elem>();
}
///////////////////////////////////////////////////////////////////////////
//
// nil_node::len
//
// return the length of the nil_node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> int nil_node<Elem>::len() { return 0; }
///////////////////////////////////////////////////////////////////////////
//
// nil_node::nth_length
//
// return the nth element on the list
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> Elem nil_node<Elem>::nth_length(int, int &len) {
len = 0;
return NULL;
}
///////////////////////////////////////////////////////////////////////////
//
// nil_node::dump
//
// dump for list node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> void nil_node<Elem>::dump(std::ostream &stream, int n) {
stream << pad(n) << "(nil)\n";
}
///////////////////////////////////////////////////////////////////////////
//
// single_list_node::copy_list
//
// return the deep copy of the single_list_node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> list_node<Elem> *single_list_node<Elem>::copy_list() {
return new single_list_node<Elem>((Elem)elem->copy());
}
///////////////////////////////////////////////////////////////////////////
//
// single_list_node::len
//
// return the length of the single_list_node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> int single_list_node<Elem>::len() { return 1; }
///////////////////////////////////////////////////////////////////////////
//
// single_list_node::nth_length
//
// return the nth element on the list
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> Elem single_list_node<Elem>::nth_length(int n, int &len) {
len = 1;
if (n)
return NULL;
else
return elem;
}
///////////////////////////////////////////////////////////////////////////
//
// single_list_node::dump
//
// dump for list node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem>
void single_list_node<Elem>::dump(std::ostream &stream, int n) {
elem->dump(stream, n);
}
///////////////////////////////////////////////////////////////////////////
//
// append_node::copy_list
//
// return the deep copy of the append_node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> list_node<Elem> *append_node<Elem>::copy_list() {
return new append_node<Elem>(some->copy_list(), rest->copy_list());
}
///////////////////////////////////////////////////////////////////////////
//
// append_node::len
//
// return the length of the append_node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> int append_node<Elem>::len() {
return some->len() + rest->len();
}
///////////////////////////////////////////////////////////////////////////
//
// append_node::nth_length
//
// return the nth element on the list
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> Elem append_node<Elem>::nth_length(int n, int &len) {
int rlen;
Elem tmp = some->nth_length(n, len);
if (!tmp) {
tmp = rest->nth_length(n - len, rlen);
len += rlen;
}
return tmp;
}
///////////////////////////////////////////////////////////////////////////
//
// append_node::dump
//
// dump for list node
//
///////////////////////////////////////////////////////////////////////////
template <class Elem>
void append_node<Elem>::dump(std::ostream &stream, int n) {
int i, size;
size = len();
stream << pad(n) << "list\n";
for (i = 0; i < size; i++)
this->nth(i)->dump(stream, n + 2);
stream << pad(n) << "(end_of_list)\n";
}
///////////////////////////////////////////////////////////////////////////
//
// list
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> single_list_node<Elem> *list(Elem x) {
return new single_list_node<Elem>(x);
}
///////////////////////////////////////////////////////////////////////////
//
// cons
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> append_node<Elem> *cons(Elem x, list_node<Elem> *l) {
return new append_node<Elem>(list(x), l);
}
///////////////////////////////////////////////////////////////////////////
//
// xcons
//
///////////////////////////////////////////////////////////////////////////
template <class Elem> append_node<Elem> *xcons(list_node<Elem> *l, Elem x) {
return new append_node<Elem>(l, list(x));
}
#endif /* TREE_H */
//
// See copyright.h for copyright notice and limitation of liability
// and disclaimer of warranty provisions.
//
#include "copyright.h"
#ifndef _SYMTAB_H_
#define _SYMTAB_H_
#include <optional>
#include <unordered_map>
#include <vector>
// added to prevent clash with llvm::SymbolTable
namespace cool {
// SymbolTable<V> describes a symbol table mapping symbols of
// type `K` to data of type `V`. It is implemented as a
// vector of vectors of `SymtabEntry<K, V>`.
//
// `enterscope` makes the table point to a new scope whose parent
// is the scope it pointed to previously.
//
// `exitscope` makes the table point to the parent scope of the
// current scope. Note that the old child scope is not
// deallocated. One may save the state of a symbol table
// at a given point by copying it with `operator =`
//
// `insert(k, v)` adds a symbol table entry to the current scope of
// the symbol table mapping symbol `k` to data `v`.
//
// `find_in_scopes(k)` looks for the symbol `k` in all scopes starting at the
// top scope,
// returning the data item associated with the entry, or nullptr if
// not found.
//
// `find(s)` looks for the symbol `k` in the current scope only.
//
// `dump()` prints the symbols in the symbol table.
//
template <class V> class SymbolTable {
private:
using TableEntry = std::pair<Symbol, V *>;
using Scope = std::unordered_map<Symbol, V *>;
std::vector<Scope> scopes;
public:
SymbolTable() = default;
void enterscope() { this->scopes.emplace_back(); }
void exitscope() {
// It is an error to exit a scope that doesn't exist.
if (this->scopes.empty()) {
throw std::runtime_error(
"exitscope: Can't remove scope from an empty symbol table.");
}
this->scopes.pop_back();
}
void insert(const Symbol &k, V *v) {
// There must be at least one scope to add a symbol.
if (this->scopes.empty()) {
throw std::runtime_error("insert: Can't add a symbol without a scope.");
}
if (v == nullptr) {
throw std::runtime_error("insert: Can't add a nullptr value.");
}
this->scopes.back().emplace(k, v);
}
V *find(const Symbol &k) const {
if (this->scopes.empty()) {
throw std::runtime_error("probe: No scope in symbol table.");
}
auto it = this->scopes.back().find(k);
if (it == this->scopes.back().end()) {
return nullptr;
}
return it->second;
}
V *find_in_scopes(const Symbol &k) const {
for (auto it = this->scopes.rbegin(); it != this->scopes.rend(); ++it) {
auto entry = it->find(k);
if (entry != it->end()) {
return entry->second;
}
}
return nullptr;
}
void dump(std::ostream &s) const {
s << "SymbolTable(\n";
for (auto &scope : this->scopes) {
s << " Scope(\n";
for (auto &[k, v] : scope) {
s << " " << k->get_string() << " -> " << v << "\n";
}
s << " )\n";
}
s << ")\n";
}
};
template <typename V>
std::ostream &operator<<(std::ostream &s, const SymbolTable<V> &symtab) {
symtab.dump(s);
return s;
}
} // namespace cool
#endif
// This file defines extra methods for classes in stringtab.h
// that are specific to code generation.
#ifndef STRINGTAB_HANDCODE_H
#define STRINGTAB_HANDCODE_H
#include <iostream>
class CgenClassTable;
namespace llvm { class GlobalVariable; }
// Extra methods added to classes in stringtab.h
#define StringEntry_EXTRAS \
void code_def(CgenClassTable *class_table); \
void code_ref(CgenClassTable *class_table); \
llvm::GlobalVariable* ptr;
#define IntEntry_EXTRAS \
void code_ref(CgenClassTable *class_table);
#define StrTable_EXTRAS \
void code_string_table(CgenClassTable *class_table); \
std::string get_file() const;
#endif /* STRINGTAB_HANDCODE_H */
// -*-Mode: C++;-*-
//
// See copyright.h for copyright notice and limitation of liability
// and disclaimer of warranty provisions.
//
#include "copyright.h"
#ifndef _STRINGTAB_H_
#define _STRINGTAB_H_
#include "stringtab.handcode.h"
#include <cassert>
#include <ostream>
#include <string>
#include <unordered_map>
class Entry {
protected:
std::string str;
int index;
public:
Entry() = default;
Entry(std::string s, int i) : str(std::move(s)), index(i) {}
const std::string &get_string() const { return str; }
int get_index() const { return index; }
};
using Symbol = Entry *;
inline std::ostream &operator<<(std::ostream &s, const Entry &sym) {
return s << "{" << sym.get_string() << ", " << sym.get_index() << "}\n";
}
//
// There are three kinds of string table entries:
// a true string, an string representation of an identifier, and
// a string representation of an integer.
//
// Having separate tables is convenient for code generation. Different
// data definitions are generated for string constants (StringEntry) and
// integer constants (IntEntry). Identifiers (IdEntry) don't produce
// static data definitions.
//
// code_def and code_ref are used by the code to produce definitions and
// references (respectively) to constants.
//
class StringEntry : public Entry {
public:
StringEntry() = default;
StringEntry(std::string s, int i) : Entry(std::move(s), i) {}
#ifdef StringEntry_EXTRAS
StringEntry_EXTRAS
#endif
};
class IdEntry : public Entry {
public:
IdEntry() = default;
IdEntry(std::string s, int i) : Entry(std::move(s), i) {}
};
class IntEntry : public Entry {
public:
IntEntry() = default;
IntEntry(std::string s, int i) : Entry(std::move(s), i) {}
#ifdef IntEntry_EXTRAS
IntEntry_EXTRAS
#endif
};
//////////////////////////////////////////////////////////////////////////
//
// String Tables
//
//////////////////////////////////////////////////////////////////////////
template <typename Entry> class StringTable {
protected:
std::unordered_map<std::string, Entry> _table;
public:
Symbol add_string(const std::string &s) {
if (_table.find(s) == _table.end()) {
_table[s] = Entry(s, _table.size());
}
// unordered_map pointer is stable, so we are safe here.
return &_table.find(s)->second;
}
Symbol lookup_string(const std::string &s) {
auto found = _table.find(s);
return found == _table.end() ? nullptr : &found->second;
}
};
class IdTable : public StringTable<IdEntry> {};
class StrTable : public StringTable<StringEntry> {
public:
#ifdef StrTable_EXTRAS
StrTable_EXTRAS
#endif
};
class IntTable : public StringTable<IntEntry> {
public:
#ifdef IntTable_EXTRAS
IntTable_EXTRAS
#endif
};
extern IdTable idtable;
extern IntTable inttable;
extern StrTable stringtable;
#endif
/*
Copyright (c) 1995,1996 The Regents of the University of California.
All rights reserved.
Permission to use, copy, modify, and distribute this software for any
purpose, without fee, and without written agreement is hereby granted,
provided that the above copyright notice and the following two
paragraphs appear in all copies of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
//
// The following include files must come first.
#ifndef COOL_TREE_HANDCODE_H
#define COOL_TREE_HANDCODE_H
#include "stringtab.h"
#include "symtab.h"
#include "tree.h"
#include "utils.h"
#include <iostream>
#include <string>
#include <optional>
class CgenEnvironment;
class CgenNode;
class Program_class;
typedef Program_class *Program;
class Class__class;
typedef Class__class *Class_;
class Feature_class;
typedef Feature_class *Feature;
class Formal_class;
typedef Formal_class *Formal;
class Expression_class;
typedef Expression_class *Expression;
class Case_class;
typedef Case_class *Case;
typedef list_node<Class_> Classes_class;
typedef Classes_class *Classes;
typedef list_node<Feature> Features_class;
typedef Features_class *Features;
typedef list_node<Formal> Formals_class;
typedef Formals_class *Formals;
typedef list_node<Expression> Expressions_class;
typedef Expressions_class *Expressions;
typedef list_node<Case> Cases_class;
typedef Cases_class *Cases;
namespace llvm {
class Value;
class Function;
class BasicBlock;
}
// Abstract classes:
#define Program_EXTRAS \
virtual void dump_with_types(std::ostream &, int) = 0; \
virtual void cgen(const std::optional<std::string> &) = 0;
#define Class__EXTRAS virtual void dump_with_types(std::ostream &, int) = 0;
#define Feature_EXTRAS \
virtual void dump_with_types(std::ostream &, int) = 0; \
virtual void layout_feature(CgenNode *cls) = 0; \
virtual llvm::Value *code(CgenEnvironment *) = 0; \
virtual Symbol get_name() = 0;
#define Expression_EXTRAS \
virtual void dump_with_types(std::ostream &, int) = 0; \
virtual llvm::Value *code(CgenEnvironment *) = 0; \
Symbol type; \
Symbol get_type() { return type; } \
Expression set_type(Symbol s) { \
type = s; \
return this; \
} \
virtual int no_code() { return 0; } /* ## */ \
void dump_type(std::ostream &, int); \
Expression_class() { type = (Symbol)NULL; }
#define program_EXTRAS \
void dump_with_types(std::ostream &, int); \
void cgen(const std::optional<std::string> &);
#define class__EXTRAS \
Symbol get_name() { return name; } \
Symbol get_parent() { return parent; } \
Symbol get_filename() { return filename; } \
void dump_with_types(std::ostream &, int);
#define Feature_SHARED_EXTRAS \
void dump_with_types(std::ostream &, int); \
void layout_feature(CgenNode *cls); \
Symbol get_name() { return name; }
#define method_EXTRAS \
virtual Symbol get_return_type() { return return_type; } \
llvm::Value* code(CgenEnvironment *) override; \
llvm::Function* fn; \
std::string qualified_name;
#define attr_EXTRAS \
llvm::Value *code(CgenEnvironment *) override; \
llvm::Value* val;
#define Formal_EXTRAS \
virtual Symbol get_type_decl() = 0; /* ## */ \
virtual Symbol get_name() = 0; /* ## */ \
virtual void dump_with_types(std::ostream &, int) = 0;
#define formal_EXTRAS \
Symbol get_type_decl() { return type_decl; } /* ## */ \
Symbol get_name() { return name; } /* ## */ \
void dump_with_types(std::ostream &, int);
#define Case_EXTRAS \
virtual Symbol get_type_decl() = 0; \
virtual void code(llvm::Value *, llvm::Value *, llvm::Value*, llvm::BasicBlock*, \
CgenEnvironment *) = 0; \
virtual void dump_with_types(std::ostream &, int) = 0;
#define branch_EXTRAS \
Symbol get_type_decl() { return type_decl; } \
Expression get_expr() { return expr; } \
void code(llvm::Value *expr_val, llvm::Value *tag, llvm::Value* mem, llvm::BasicBlock* sbb, \
CgenEnvironment *env); \
void dump_with_types(std::ostream &, int);
#define Expression_SHARED_EXTRAS \
llvm::Value *code(CgenEnvironment *); \
void dump_with_types(std::ostream &, int);
#define no_expr_EXTRAS /* ## */ \
int no_code() { return 1; } /* ## */
#endif /* COOL_TREE_HANDCODE_H */
#ifndef COOL_TREE_H
#define COOL_TREE_H
/*
file: cool_tree.h
This file defines classes for each phylum and constructor
(Partly copied over from dumptype.cc)
It may help to know the inheritance hierarchy of the classes
that define the structure of the Cool AST.
In the list below, the outer classes are the Phyla
which group together related kinds of abstract tree nodes
(e.g., the two kinds of Features and the many different kinds of Expression).
The inner, indented classes inherit from the nearest Phyla class;
these are the concrete classes that appear in the AST.
Program_class
program_class
Class__class
class_class
Feature_class
method_class (_class omitted below)
attr
Formal_class
formal
Case_class
branch
Expression_class
assign
static_dispatch
dispatch
cond
loop
typcase
block
let
plus
sub
mul
divide
neg
lt
eq
leq
comp
int_const
bool_const
string_const
new_
isvoid
no_expr
object
All of the Phyla inherit from the tree_node class.
Some AST nodes have lists of other tree nodes as components. Lists in the
AST are built using the class list_node defined in tree.h. The list
classes in the Cool AST are:
Classes a list of Class_
Features a list of Feature
Expressions a list of Expression
Cases a list of Case
*/
#include "cool_tree.handcode.h"
#include "tree.h"
#include "utils.h"
class CgenClassTable;
// define the class for phylum
// define simple phylum - Program
typedef class Program_class *Program;
class Program_class : public tree_node {
public:
tree_node *copy() { return copy_Program(); }
virtual Program copy_Program() = 0;
CgenClassTable *class_table;
#ifdef Program_EXTRAS
Program_EXTRAS
#endif
};
// define simple phylum - Class_
typedef class Class__class *Class_;
class Class__class : public tree_node {
public:
tree_node *copy() { return copy_Class_(); }
virtual Class_ copy_Class_() = 0;
#ifdef Class__EXTRAS
Class__EXTRAS
#endif
};
// define simple phylum - Feature
typedef class Feature_class *Feature;
class Feature_class : public tree_node {
public:
tree_node *copy() { return copy_Feature(); }
virtual Feature copy_Feature() = 0;
#ifdef Feature_EXTRAS
Feature_EXTRAS
#endif
};
// define simple phylum - Formal
typedef class Formal_class *Formal;
class Formal_class : public tree_node {
public:
tree_node *copy() { return copy_Formal(); }
virtual Formal copy_Formal() = 0;
#ifdef Formal_EXTRAS
Formal_EXTRAS
#endif
};
// define simple phylum - Expression
typedef class Expression_class *Expression;
class Expression_class : public tree_node {
public:
tree_node *copy() { return copy_Expression(); }
virtual Expression copy_Expression() = 0;
#ifdef Expression_EXTRAS
Expression_EXTRAS
#endif
};
// define simple phylum - Case
typedef class Case_class *Case;
class Case_class : public tree_node {
public:
tree_node *copy() { return copy_Case(); }
virtual Case copy_Case() = 0;
#ifdef Case_EXTRAS
Case_EXTRAS
#endif
};
// define the class for phylum - LIST
// define list phlyum - Classes
typedef list_node<Class_> Classes_class;
typedef Classes_class *Classes;
// define list phlyum - Features
typedef list_node<Feature> Features_class;
typedef Features_class *Features;
// define list phlyum - Formals
typedef list_node<Formal> Formals_class;
typedef Formals_class *Formals;
// define list phlyum - Expressions
typedef list_node<Expression> Expressions_class;
typedef Expressions_class *Expressions;
// define list phlyum - Cases
typedef list_node<Case> Cases_class;
typedef Cases_class *Cases;
// define the class for constructors
// define constructor - program
class program_class : public Program_class {
protected:
Classes classes;
public:
program_class(Classes a1) { classes = a1; }
Program copy_Program();
void dump(std::ostream &stream, int n);
#ifdef Program_SHARED_EXTRAS
Program_SHARED_EXTRAS
#endif
#ifdef program_EXTRAS
program_EXTRAS
#endif
};
// define constructor - class_
class class__class : public Class__class {
protected:
Symbol name;
Symbol parent;
Features features;
Symbol filename;
public:
class__class(Symbol a1, Symbol a2, Features a3, Symbol a4) {
name = a1;
parent = a2;
features = a3;
filename = a4;
}
Class_ copy_Class_();
void dump(std::ostream &stream, int n);
#ifdef Class__SHARED_EXTRAS
Class__SHARED_EXTRAS
#endif
#ifdef class__EXTRAS
class__EXTRAS
#endif
};
// define constructor - method
class method_class : public Feature_class {
protected:
Symbol name;
Formals formals;
Symbol return_type;
Expression expr;
public:
method_class(Symbol a1, Formals a2, Symbol a3, Expression a4) {
name = a1;
formals = a2;
return_type = a3;
expr = a4;
}
Feature copy_Feature();
void dump(std::ostream &stream, int n);
#ifdef Feature_SHARED_EXTRAS
Feature_SHARED_EXTRAS
#endif
#ifdef method_EXTRAS
method_EXTRAS
#endif
};
// define constructor - attr
class attr_class : public Feature_class {
protected:
Symbol name;
Symbol type_decl;
Expression init;
public:
attr_class(Symbol a1, Symbol a2, Expression a3) {
name = a1;
type_decl = a2;
init = a3;
}
Feature copy_Feature();
void dump(std::ostream &stream, int n);
#ifdef Feature_SHARED_EXTRAS
Feature_SHARED_EXTRAS
#endif
#ifdef attr_EXTRAS
attr_EXTRAS
#endif
};
// define constructor - formal
class formal_class : public Formal_class {
protected:
Symbol name;
Symbol type_decl;
public:
formal_class(Symbol a1, Symbol a2) {
name = a1;
type_decl = a2;
}
Formal copy_Formal();
void dump(std::ostream &stream, int n);
#ifdef Formal_SHARED_EXTRAS
Formal_SHARED_EXTRAS
#endif
#ifdef formal_EXTRAS
formal_EXTRAS
#endif
};
// define constructor - branch
class branch_class : public Case_class {
protected:
Symbol name;
Symbol type_decl;
Expression expr;
public:
branch_class(Symbol a1, Symbol a2, Expression a3) {
name = a1;
type_decl = a2;
expr = a3;
}
Case copy_Case();
void dump(std::ostream &stream, int n);
#ifdef Case_SHARED_EXTRAS
Case_SHARED_EXTRAS
#endif
#ifdef branch_EXTRAS
branch_EXTRAS
#endif
};
// define constructor - assign
class assign_class : public Expression_class {
protected:
Symbol name;
Expression expr;
public:
assign_class(Symbol a1, Expression a2) {
name = a1;
expr = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef assign_EXTRAS
assign_EXTRAS
#endif
};
// define constructor - static_dispatch
class static_dispatch_class : public Expression_class {
protected:
Expression expr;
Symbol type_name;
Symbol name;
Expressions actual;
public:
static_dispatch_class(Expression a1, Symbol a2, Symbol a3, Expressions a4) {
expr = a1;
type_name = a2;
name = a3;
actual = a4;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef static_dispatch_EXTRAS
static_dispatch_EXTRAS
#endif
};
// define constructor - dispatch
class dispatch_class : public Expression_class {
protected:
Expression expr;
Symbol name;
Expressions actual;
public:
dispatch_class(Expression a1, Symbol a2, Expressions a3) {
expr = a1;
name = a2;
actual = a3;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef dispatch_EXTRAS
dispatch_EXTRAS
#endif
};
// define constructor - cond
class cond_class : public Expression_class {
protected:
Expression pred;
Expression then_exp;
Expression else_exp;
public:
cond_class(Expression a1, Expression a2, Expression a3) {
pred = a1;
then_exp = a2;
else_exp = a3;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef cond_EXTRAS
cond_EXTRAS
#endif
};
// define constructor - loop
class loop_class : public Expression_class {
protected:
Expression pred;
Expression body;
public:
loop_class(Expression a1, Expression a2) {
pred = a1;
body = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef loop_EXTRAS
loop_EXTRAS
#endif
};
// define constructor - typcase
class typcase_class : public Expression_class {
protected:
Expression expr;
Cases cases;
public:
typcase_class(Expression a1, Cases a2) {
expr = a1;
cases = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef typcase_EXTRAS
typcase_EXTRAS
#endif
};
// define constructor - block
class block_class : public Expression_class {
protected:
Expressions body;
public:
block_class(Expressions a1) { body = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef block_EXTRAS
block_EXTRAS
#endif
};
// define constructor - let
class let_class : public Expression_class {
protected:
Symbol identifier;
Symbol type_decl;
Expression init;
Expression body;
public:
let_class(Symbol a1, Symbol a2, Expression a3, Expression a4) {
identifier = a1;
type_decl = a2;
init = a3;
body = a4;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef let_EXTRAS
let_EXTRAS
#endif
};
// define constructor - plus
class plus_class : public Expression_class {
protected:
Expression e1;
Expression e2;
public:
plus_class(Expression a1, Expression a2) {
e1 = a1;
e2 = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef plus_EXTRAS
plus_EXTRAS
#endif
};
// define constructor - sub
class sub_class : public Expression_class {
protected:
Expression e1;
Expression e2;
public:
sub_class(Expression a1, Expression a2) {
e1 = a1;
e2 = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef sub_EXTRAS
sub_EXTRAS
#endif
};
// define constructor - mul
class mul_class : public Expression_class {
protected:
Expression e1;
Expression e2;
public:
mul_class(Expression a1, Expression a2) {
e1 = a1;
e2 = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef mul_EXTRAS
mul_EXTRAS
#endif
};
// define constructor - divide
class divide_class : public Expression_class {
protected:
Expression e1;
Expression e2;
public:
divide_class(Expression a1, Expression a2) {
e1 = a1;
e2 = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef divide_EXTRAS
divide_EXTRAS
#endif
};
// define constructor - neg
class neg_class : public Expression_class {
protected:
Expression e1;
public:
neg_class(Expression a1) { e1 = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef neg_EXTRAS
neg_EXTRAS
#endif
};
// define constructor - lt
class lt_class : public Expression_class {
protected:
Expression e1;
Expression e2;
public:
lt_class(Expression a1, Expression a2) {
e1 = a1;
e2 = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef lt_EXTRAS
lt_EXTRAS
#endif
};
// define constructor - eq
class eq_class : public Expression_class {
protected:
Expression e1;
Expression e2;
public:
eq_class(Expression a1, Expression a2) {
e1 = a1;
e2 = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef eq_EXTRAS
eq_EXTRAS
#endif
};
// define constructor - leq
class leq_class : public Expression_class {
protected:
Expression e1;
Expression e2;
public:
leq_class(Expression a1, Expression a2) {
e1 = a1;
e2 = a2;
}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef leq_EXTRAS
leq_EXTRAS
#endif
};
// define constructor - comp
class comp_class : public Expression_class {
protected:
Expression e1;
public:
comp_class(Expression a1) { e1 = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef comp_EXTRAS
comp_EXTRAS
#endif
};
// define constructor - int_const
class int_const_class : public Expression_class {
protected:
Symbol token;
public:
int_const_class(Symbol a1) { token = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef int_const_EXTRAS
int_const_EXTRAS
#endif
};
// define constructor - bool_const
class bool_const_class : public Expression_class {
protected:
bool val;
public:
bool_const_class(bool a1) { val = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef bool_const_EXTRAS
bool_const_EXTRAS
#endif
};
// define constructor - string_const
class string_const_class : public Expression_class {
protected:
Symbol token;
public:
string_const_class(Symbol a1) { token = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef string_const_EXTRAS
string_const_EXTRAS
#endif
};
// define constructor - new_
class new__class : public Expression_class {
protected:
Symbol type_name;
public:
new__class(Symbol a1) { type_name = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef new__EXTRAS
new__EXTRAS
#endif
};
// define constructor - isvoid
class isvoid_class : public Expression_class {
protected:
Expression e1;
public:
isvoid_class(Expression a1) { e1 = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef isvoid_EXTRAS
isvoid_EXTRAS
#endif
};
// define constructor - no_expr
class no_expr_class : public Expression_class {
protected:
public:
no_expr_class() {}
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef no_expr_EXTRAS
no_expr_EXTRAS
#endif
};
// define constructor - object
class object_class : public Expression_class {
protected:
Symbol name;
public:
object_class(Symbol a1) { name = a1; }
Expression copy_Expression();
void dump(std::ostream &stream, int n);
#ifdef Expression_SHARED_EXTRAS
Expression_SHARED_EXTRAS
#endif
#ifdef object_EXTRAS
object_EXTRAS
#endif
};
// define the prototypes of the interface
Classes nil_Classes();
Classes single_Classes(Class_);
Classes append_Classes(Classes, Classes);
Features nil_Features();
Features single_Features(Feature);
Features append_Features(Features, Features);
Formals nil_Formals();
Formals single_Formals(Formal);
Formals append_Formals(Formals, Formals);
Expressions nil_Expressions();
Expressions single_Expressions(Expression);
Expressions append_Expressions(Expressions, Expressions);
Cases nil_Cases();
Cases single_Cases(Case);
Cases append_Cases(Cases, Cases);
Program program(Classes);
Class_ class_(Symbol, Symbol, Features, Symbol);
Feature method(Symbol, Formals, Symbol, Expression);
Feature attr(Symbol, Symbol, Expression);
Formal formal(Symbol, Symbol);
Case branch(Symbol, Symbol, Expression);
Expression assign(Symbol, Expression);
Expression static_dispatch(Expression, Symbol, Symbol, Expressions);
Expression dispatch(Expression, Symbol, Expressions);
Expression cond(Expression, Expression, Expression);
Expression loop(Expression, Expression);
Expression typcase(Expression, Cases);
Expression block(Expressions);
Expression let(Symbol, Symbol, Expression, Expression);
Expression plus(Expression, Expression);
Expression sub(Expression, Expression);
Expression mul(Expression, Expression);
Expression divide(Expression, Expression);
Expression neg(Expression);
Expression lt(Expression, Expression);
Expression eq(Expression, Expression);
Expression leq(Expression, Expression);
Expression comp(Expression);
Expression int_const(Symbol);
Expression bool_const(bool);
Expression string_const(Symbol);
Expression new_(Symbol);
Expression isvoid(Expression);
Expression no_expr();
Expression object(Symbol);
#endif
#pragma once
/*
This is the Lab1 skeleton cgen header. As given, it contains only basic
functionality. You will need to add members to each of the classes
to get them to perform their desired functions. Document your important
design decisions below. We should be able to read your documentation and
get a general overview of how your compiler generates code. For instance,
how does your compiler generate structures for classes, how is inheritance
modeled, how do you handle dynamic binding, etc.
*/
// ------------------ INSERT DESIGN DOCUMENTATION HERE --------------------- //
/*
* Types for classes are declared when its CgenNode is installed to deal with circular dependencies
*
*/
// ----------------------------- END DESIGN DOCS --------------------------- //
#include "cool_tree.h"
// #include "stringtab.h"
// #include "symtab.h"
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/DIBuilder.h>
#include "llvm/IR/DebugInfoMetadata.h"
#include <llvm/Support/raw_ostream.h>
#if defined _MSC_VER && !defined __clang__
#define __attribute(...)
#endif
class CgenNode;
#pragma region "CgenClassTable"
// CgenClassTable represents the top level of a Cool program, which is
// basically a list of classes. The class table is used to look up classes
// (CgenNodes) by name, and it also handles global code generation tasks.
// The CgenClassTable constructor is where you'll find the entry point for
// code generation for an entire Cool program.
class CgenClassTable : public cool::SymbolTable<CgenNode> {
public:
// CgenClassTable constructor begins and ends the code generation process
CgenClassTable(Classes);
private:
// The following creates an inheritance graph from a list of classes.
// The graph is implemented as a tree of `CgenNode', and class names
// are placed in the base class symbol table.
void install_basic_classes();
void install_classes(Classes cs);
void install_class(CgenNode *nd);
void install_special_class(CgenNode *nd);
void build_inheritance_tree();
void set_relations(CgenNode *nd);
// Create declarations for C runtime functions we need to generate code
void setup_external_functions();
void setup_classes(CgenNode *c, int depth);
// Setup each class in the table and prepare for code generation phase
void setup();
// Code generation functions. You need to write these functions.
void code_module();
void code_classes(CgenNode *c);
void code_constants();
void code_main();
/* Util functions */
CgenNode *root(); // Get the root of the class Tree, i.e. Object
public:
int get_num_classes() const { return current_tag; }
private:
// Class lists and current class tag
std::vector<CgenNode *> nds, special_nds;
int current_tag;
public:
// LLVM Util
llvm::Function *create_llvm_function(const std::string &funcName,
llvm::Type *retType,
llvm::ArrayRef<llvm::Type *> argTypes,
bool isVarArgs);
llvm::Function *create_function(const std::string &name,
llvm::Type *ret_type,
llvm::ArrayRef<llvm::Type *> arg_types,
llvm::GlobalValue::LinkageTypes linkage);
llvm::Function *create_var_function(const std::string &name,
llvm::Type *ret_type,
llvm::ArrayRef<llvm::Type *> arg_types,
llvm::GlobalValue::LinkageTypes
linkage);
// CgenClassTable owns the current LLVM module and everything attached.
// One program, one class table, one module.
llvm::LLVMContext context;
llvm::IRBuilder<> builder;
llvm::Module the_module;
llvm::DIBuilder di_builder;
llvm::DIFile* di_file;
llvm::DICompileUnit* di_cu;
llvm::Type *i1;
llvm::Type *i8;
llvm::PointerType *ptr;
llvm::Type *i32;
llvm::Type *void_;
llvm::DIBasicType* di1;
llvm::DIBasicType* di8;
llvm::DIBasicType* di32;
llvm::DIDerivedType* dptr;
llvm::DIBasicType* dvoid;
};
#pragma endregion
#pragma region "CgenNode"
// Each CgenNode corresponds to a Cool class. As such, it is responsible for
// performing code generation on the class level. This includes laying out
// the class attributes, creating the necessary Types for the class and
// generating code for each of its methods.
class CgenNode : public class__class {
public:
enum Basicness { Basic, NotBasic };
CgenNode(Class_ c, Basicness bstatus, CgenClassTable *class_table)
: class__class((const class__class &) *c), parentnd(0), children(0),
basic_status(bstatus), class_table(class_table), tag(-1), ctx(class_table->context),
i1(class_table->i1), i8(class_table->i8), ptr(class_table->ptr),
i32(class_table->i32), void_(class_table->void_),
type(nullptr), vtable_type(nullptr), vtable(nullptr),
di_builder(class_table->di_builder)
{}
// Relationships with other nodes in the tree
void set_parent(CgenNode *p)
{
assert(this->parentnd == nullptr && p != nullptr);
p->children.push_back(this);
this->parentnd = p;
}
std::optional<CgenNode*> get_direct_parent() const
{
if (parentnd->basic())
return std::nullopt;
return parentnd;
}
int basic() const { return basic_status == Basic; }
std::vector<CgenNode *> &get_children() { return children; }
void set_max_child(int mc) { max_child = mc; }
int get_max_child() const { return max_child; }
// Accessors for other provided fields
int get_tag() const { return tag; }
CgenClassTable *get_classtable() const { return class_table; }
llvm::StructType *type;
llvm::StructType *vtable_type;
llvm::GlobalVariable *vtable;
llvm::DIType* dtype;
std::string get_type_name() const { return name->get_string(); }
std::string get_vtable_type_name() const
{
return "_" + get_type_name() + "_vtable";
}
std::string get_vtable_name() const
{
return "_" + get_type_name() + "_vtable_prototype";
}
std::string get_init_function_name() const { return get_type_name() + "_new"; }
// Class setup. You need to write the body of this function.
void setup(int tag, int depth);
// Layout the methods and attributes for code generation
void layout_features();
// Class codegen. You need to write the body of this function.
void code_class();
// Codegen for the init function of every class
void code_init_function(CgenEnvironment *env) const;
void make_vtable_type(CgenEnvironment *env);
std::vector<std::pair<method_class *, llvm::FunctionType *> > methods;
std::vector<std::pair<attr_class *, llvm::Type *> > attributes;
llvm::Function *create_function(const std::string &fName, llvm::FunctionType *ty) const
{
return llvm::Function::Create(ty, llvm::GlobalValue::ExternalLinkage,
this->name->get_string() + "_" + fName,
this->class_table->the_module);
}
static llvm::FunctionType *create_functionty(llvm::Type *retType,
llvm::ArrayRef<llvm::Type *> argTypes)
{
return llvm::FunctionType::get(retType, argTypes, false);
}
void make_vtable_prototype(CgenEnvironment *env);
void premake_type()
{
assert(type == nullptr);
this->type = llvm::StructType::create(ctx,
this->name->get_string());
assert(type != nullptr);
}
void premake_debug_type();
llvm::DIBuilder &di_builder;
std::vector<llvm::Metadata*> dfeats;
private:
CgenNode *parentnd; // Parent of class
std::vector<CgenNode *> children; // Children of class
Basicness basic_status; // `Basic' or 'NotBasic'
CgenClassTable *class_table;
// Class tag. Should be unique for each class in the tree
int tag, max_child;
llvm::LLVMContext &ctx;
llvm::Type *i1;
llvm::Type *i8;
llvm::PointerType *ptr;
llvm::Type *i32;
llvm::Type *void_;
void make_type_forrealz(CgenEnvironment *env);
void make_debug_type(CgenEnvironment* env);
};
#pragma endregion
#pragma region "CgenEnvironment"
// CgenEnvironment provides the environment for code generation of a method.
// Its main task is to provide a mapping from Cool names to LLVM Values.
// This mapping needs to be maintained as scopes are entered and exited, new
// variables are declared, and so on. CgenEnvironment is also a good place
// to put non-local information you will need during code generation. Two
// examples are the current CgenNode and the current Function.
class CgenEnvironment {
public:
// Class CgenEnvironment should be constructed by a class prior to code
// generation for each method. You may need to add parameters to this
// constructor.
CgenEnvironment(CgenNode *cur_class)
: cur_class(cur_class),
class_table(*cur_class->get_classtable()),
context(class_table.context),
builder(class_table.builder), the_module(class_table.the_module), data_layout(&the_module),
i1(class_table.i1), i8(class_table.i8), ptr(class_table.ptr),
i32(class_table.i32), void_(class_table.void_)
{
vars.enterscope();
}
CgenNode *get_class() const { return cur_class; }
void set_class(CgenNode *c) { cur_class = c; }
// Must return the CgenNode for a class given the symbol of its name
CgenNode *type_to_class(Symbol t) const;
std::pair<llvm::Type*, llvm::Value*> find_in_scopes(Symbol name) const;
std::optional<llvm::Value*> find_if_exists(Symbol name) const;
void add_binding(Symbol name, llvm::Value *val_ptr)
{
vars.insert(name, val_ptr);
}
void open_scope() { vars.enterscope(); }
void close_scope() { vars.exitscope(); }
// LLVM Utils:
// Create a new llvm function in the current module with class name appended
llvm::Function *get_function(Symbol name) const
{
return the_module.getFunction(name->get_string());
}
// Insert a new BasicBlock at the end of the current function (the function
// that builder is in)
llvm::BasicBlock *new_bb_at_end(const std::string &name)
{
return llvm::BasicBlock::Create(context, name,
builder.GetInsertBlock()->getParent());
}
// Insert an alloca instruction in the head BasicBlock of the current
// function, such that this alloca is available in all BasicBlocks of the
// function.
llvm::AllocaInst *insert_alloca_at_head(llvm::Type *ty);
llvm::AllocaInst *insert_alloca_at_head(llvm::Type *, llvm::Twine const &);
// Get or insert a BasicBlock with the name "abort" which calls the ::abort
// function. This block will be inserted at the end of the given function,
// without moving the builder.
llvm::BasicBlock *get_or_insert_abort_block(llvm::Function *f);
llvm::Type *as_type(Symbol) const __attribute((pure));
llvm::Type *as_mostly_boxed_type(Symbol) const __attribute((pure));
llvm::DIType* as_boxed_dtype(Symbol) const __attribute((pure));
llvm::Value* default_value(llvm::Type*) const __attribute((pure));
// Generate any code necessary to convert from given Value* to
// dest_type, assuming it has already been checked to be compatible
llvm::Value* conform(llvm::Value* src, llvm::Type* dest_type) __attribute((pure));
private:
// mapping from variable names to memory locations
cool::SymbolTable<llvm::Value> vars;
CgenNode *cur_class;
public:
CgenClassTable &class_table;
// These are references to the current LLVM context and module,
// and they point to the ones in CgenClassTable.
llvm::LLVMContext &context;
llvm::IRBuilder<> &builder;
llvm::Module &the_module;
llvm::DataLayout data_layout;
llvm::Type *i1;
llvm::Type *i8;
llvm::PointerType *ptr;
llvm::Type *i32;
llvm::Type *void_;
};
#pragma endregion
#ifndef _AST_PARSE_H
#define _AST_PARSE_H
//
// See copyright.h for copyright notice and limitation of liability
// and disclaimer of warranty provisions.
//
#include "copyright.h"
class Entry;
typedef Entry *Symbol;
#define MAX_STR_CONST 1025
#define YY_NO_UNPUT
#define yylval ast_yylval
#define yylex ast_yylex
#include "tree.h"
typedef class Program_class *Program;
typedef class Class__class *Class_;
typedef class Feature_class *Feature;
typedef class Formal_class *Formal;
typedef class Expression_class *Expression;
typedef class Case_class *Case;
typedef list_node<Class_> Classes_class;
typedef Classes_class *Classes;
typedef list_node<Feature> Features_class;
typedef Features_class *Features;
typedef list_node<Formal> Formals_class;
typedef Formals_class *Formals;
typedef list_node<Expression> Expressions_class;
typedef Expressions_class *Expressions;
typedef list_node<Case> Cases_class;
typedef Cases_class *Cases;
#ifndef BISON_AST_TAB_H
#define BISON_AST_TAB_H
#ifndef YYSTYPE
typedef union {
int lineno;
bool boolean;
Symbol symbol;
Program program;
Class_ class_;
Classes classes;
Feature feature;
Features features;
Formal formal;
Formals formals;
Case case_;
Cases cases;
Expression expression;
Expressions expressions;
} yystype;
#define YYSTYPE yystype
#define YYSTYPE_IS_TRIVIAL 1
#endif
#define PROGRAM 257
#define CLASS 258
#define METHOD 259
#define ATTR 260
#define FORMAL 261
#define BRANCH 262
#define ASSIGN 263
#define STATIC_DISPATCH 264
#define DISPATCH 265
#define COND 266
#define LOOP 267
#define TYPCASE 268
#define BLOCK 269
#define LET 270
#define PLUS 271
#define SUB 272
#define MUL 273
#define DIVIDE 274
#define NEG 275
#define LESSTHAN 276
#define EQUAL 277
#define LEQ 278
#define COMP 279
#define INT 280
#define STR 281
#define BOOL 282
#define NEW 283
#define ISVOID 284
#define NO_EXPR 285
#define OBJECT 286
#define NO_TYPE 287
#define STR_CONST 288
#define INT_CONST 289
#define IDENT 290
#define LINENO 291
extern YYSTYPE yylval;
#endif /* not BISON_AST_TAB_H */
#endif
`src`: COOL codegen and frontend
`lib`: COOL AST and auxiliary code
`rt`: COOL runtime
load("//:pch.bzl", "pch")
cc_library(
name = "support",
srcs = glob(["lib/*.cc"]) + select({
"@bazel_tools//src/conditions:windows": [
"lib/win/getopt.c",
"lib/win/getopt.h",
"lib/win/unistd.h",
],
"//conditions:default": [],
}),
hdrs = [
"include/ast_parse.h",
"include/cool_tree.h",
"include/cool_tree.handcode.h",
"include/copyright.h",
"include/stringtab.h",
"include/stringtab.handcode.h",
"include/symtab.h",
"include/tree.h",
"include/utils.h",
],
includes = ["include"],
copts = ["-Os", "-std=c++17", "-Wno-register"],
deps = [],
)
pch(
name = "support_pch",
includes = [
"ast_parse.h",
"cool_tree.h",
"cool_tree.handcode.h",
"copyright.h",
"stringtab.h",
"stringtab.handcode.h",
"symtab.h",
"tree.h",
"utils.h",
],
deps = [":support"],
)
cc_library(
name = "runtime",
srcs = glob(["rt/*.c"]),
hdrs = glob(["rt/*.h"]),
copts = ["-Os", "-DNDEBUG"],
visibility = ["//visibility:public"],
)
cc_library(
name = "codegen",
srcs = ["src/cgen.cc"],
hdrs = ["include/cgen.h"],
deps = [
":support_pch",
":support",
"//llvm:ir_headers_pch",
"//llvm:support_pch",
"//llvm:Core",
"//llvm:Support",
],
copts = ["-std=c++17"]
)
cc_binary(
name = "cgen",
deps = [":codegen"],
visibility = ["//visibility:public"],
)