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: SKELETONRead 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)#endifextern 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 wellas fixed names used by the runtime system. Feel free to add yourown definitions as you see fit.*********************************************************************/EXTERN Symbol// required classesObject,IO, String, Int, Bool, Main,// class methodscool_abort, type_name, cool_copy, out_string, out_int, in_string, in_int,length, concat, substr,// class membersval,// special symbolsNo_class, // symbol that can't be the name of any user-defined classNo_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// extrasarg, 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 generationCgenClassTable::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_DBGthe_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 constantsenterscope();// Create an inheritance tree with one CgenNode per class.install_basic_classes();install_classes(classes);build_inheritance_tree();// First passsetup();// Second passcode_module();// Done with code generation: exit scopesexitscope();#ifdef EMIT_DBG// finalize debug infodi_builder.finalize();#endif}// Creates AST nodes for the basic classes and installs them in the class listvoid 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 tablevoid 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 laternd->premake_type();// nd->premake_debug_type();}// Add this CgenNode to the special class list and the lookup tablevoid 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_treevoid 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 Lab1void 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 bytecreate_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 CgenNodevoid 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 CgenNodevoid CgenClassTable::code_module(){code_constants();code_classes(root());code_main();if (cgen_debug)std::cerr << "\n";}void CgenClassTable::code_classes(CgenNode* c){// emit Object firstif (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 classesfor (auto* i: classes)code_classes(i);}// Create global definitions for constant Cool objectsvoid 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 i32auto* fn = create_function("main", i32, {},GlobalValue::ExternalLinkage);// Define an entry basic blockauto* bb = BasicBlock::Create(this->context, "main_entry_point", fn);builder.SetInsertPoint(bb);// Call Main_new() to create a Mainauto* main_new = the_module.getFunction("Main_new");assertm(main_new, "Main_new exists");auto* main = builder.CreateCall(main_new, {});// Call Main_mainauto* main_main = the_module.getFunction("Main_main");assertm(main_main, "Main_main exists");auto* main_returned = builder.CreateCall(main_main, {main});// Always return 0builder.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 methodsCoding string, int, and boolean constantsCool 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 havetype stringEntry. stringEntry methods are defined both for stringconstant definitions and references.All integer constants are listed in the global "inttable" and havetype 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 constantsvoid 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 constantvoid 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 existif (!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 outfor (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 typeassert(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 initenv->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 neededauto* attrptr = env->builder.CreateStructGEP(type, hptr, i + 1, "n.attrptr_" + attributes.at(i).first->get_name()->get_string());// make sure we default initif (val == ConstantPointerNull::get(env->ptr))env->builder.CreateStore(env->conform(env->default_value(attributes.at(i).second), env->ptr), attrptr);elseenv->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 namestd::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 / cxxRecordif (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 vtableif (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 symbolCgenNode* 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 bbreturn new AllocaInst(ty, 0, "", &entry_bb);} else {// Insert before the first instruction of this bbreturn 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 bbreturn new AllocaInst(ty, 0, msg, &entry_bb);} else {// Insert before the first instruction of this bbreturn 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 Boolif (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 Boolauto* r = insert_alloca_at_head(ptr, "box.i1");// create a new Boolauto* b = builder.CreateCall(bool_new->getFunctionType(), bool_new, {});// store the ptr to the bool so we can return it laterbuilder.CreateStore(b, r);// upconvert to a cboolauto* c = builder.CreateZExt(src, i8);// initalize the boolauto* bptr1 = builder.CreateLoad(ptr, r);builder.CreateCall(bool_init->getFunctionType(), bool_init, {bptr1, c});// return the initalized boolreturn 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 Intauto* r = insert_alloca_at_head(ptr, "box.i32");// create a new Intauto* b = builder.CreateCall(int_new->getFunctionType(), int_new, {});// store the ptr to the int so we can return it laterbuilder.CreateStore(b, r);// initalize the intauto* iptr1 = builder.CreateLoad(ptr, r);builder.CreateCall(int_init->getFunctionType(), int_init, {iptr1, src});// return the initalized intreturn builder.CreateLoad(ptr, r, "boxed.i32");}default: llvm_unreachable("Unsupported integer width to conform to");}}// rawdog a gep and hope for the bestif (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 methodsFill in the following methods to produce code for theappropriate expression. You may add or remove parametersas you wish, but if you do, remember to change the parametersof 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 bodyValue* 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 argsassert(fn->arg_size() == formals->len() + 1);for (auto* arg = fn->arg_begin(); arg != fn->arg_end(); ++arg) {int idx = arg->getArgNo();// store argauto* arg_ptr = env->insert_alloca_at_head(arg->getType());env->builder.CreateStore(arg, arg_ptr);// name and bind argif (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 argsValue* 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 attributeassert(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 selfauto [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 nowauto 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 resultauto* 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 branchesauto* truebb = BasicBlock::Create(env->context, "true", fn);auto* falsebb = BasicBlock::Create(env->context, "false", fn);// and a basic block for the resultauto* mergebb = BasicBlock::Create(env->context, "merge", fn);// branchenv->builder.SetInsertPoint(startbb);Value* cond = env->conform(pred->code(env), env->i1);env->builder.CreateCondBr(cond, truebb, falsebb);// emit trueenv->builder.SetInsertPoint(truebb);env->builder.CreateStore(then_exp->code(env), res);env->builder.CreateBr(mergebb); // jump to merge to close bb// emit falseenv->builder.SetInsertPoint(falsebb);env->builder.CreateStore(else_exp->code(env), res);env->builder.CreateBr(mergebb); // jump to merge to close bb// load and return resultenv->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 endauto* 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 conditionalenv->builder.SetInsertPoint(startbb);env->builder.CreateBr(condbb);// emit conditionalenv->builder.SetInsertPoint(condbb);// check loop conditionalValue* cond = env->conform(pred->code(env), env->i1);env->builder.CreateCondBr(cond, loopbb, endbb);// emit loopenv->builder.SetInsertPoint(loopbb);body->code(env);// end bb by jumping to conditionalenv->builder.CreateBr(condbb);// emit endenv->builder.SetInsertPoint(endbb);// loops return voidreturn 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 variableauto* var_ptr = env->insert_alloca_at_head(ty, "let");// store inital code to var_ptrValue* initial_val = init->code(env);if (!ConstantPointerNull::classof(initial_val))env->builder.CreateStore(initial_val, var_ptr);else // otherwise init with default valueenv->builder.CreateStore(env->default_value(ty), var_ptr);// bind memory location so the body can use itenv->open_scope();env->add_binding(identifier, var_ptr);// return result of the let exprValue* 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 herereturn 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 attributeassert(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 selfauto [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 nowauto 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 nullptrreturn 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 argsauto args = map<Expression, Value*>(unfuck(actual), [env](Expression const& e) -> Value* {return e->code(env);});// figure out the calling classauto* caller_class = env->type_to_class(type_name);auto* caller = expr->code(env);// box primsif (caller->getType()->isIntegerTy()) {auto* orig = caller;caller = env->conform(orig, env->ptr);}// sanity check callerassert(caller->getType()->isPointerTy());if (cgen_debug)errs() << "\t\t\tLooking for " << as_string(name) << "\n";// figure out method index into vtableauto get_method_idx = [](CgenNode* cls, Symbol name) -> int {auto methods = cls->methods;// search in reverse so we get the overload instead of the originalfor (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 checkenv->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 successfulenv->builder.SetInsertPoint(validbb);// get method's signatureauto* method_ty = caller_class->methods.at(method_idx).second;// get pointer from vtableValue* 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 methodsauto* method = env->builder.CreateLoad(method_ty->getPointerTo(), method_ptr, "sd." + n);// build method argsstd::vector real_args{caller};real_args.reserve(1 + args.size());for (int i = 0; i < args.size(); ++i) { // make sure args are unboxed as neededreal_args.emplace_back(env->conform(args.at(i), method_ty->getParamType(i + 1)));}// call methodreturn 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 argsauto args = map<Expression, Value*>(unfuck(actual), [env](Expression const& e) -> Value* {return e->code(env);});// figure out the calling classauto* caller_class = env->type_to_class(expr->get_type());Value* caller = expr->code(env);// box primsif (caller->getType()->isIntegerTy()) {auto* orig = caller;caller = env->conform(orig, env->ptr);}// sanity check callerassert(caller->getType()->isPointerTy());if (cgen_debug)errs() << "\t\t\tLooking for " << as_string(name) << "\n";// figure out method index into vtableauto get_method_idx = [](CgenNode* cls, Symbol name) -> int {auto methods = cls->methods;// search in reverse so we get the overload instead of the originalfor (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 checkenv->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 successfulenv->builder.SetInsertPoint(validbb);// get vtable ptrauto* vtable_ptr = env->builder.CreateStructGEP(caller_class->type, caller, 0, "d.vtblptr");// load vtableauto* vtable = env->builder.CreateLoad(env->ptr, vtable_ptr, "d.vtbl");// get method's signatureauto* method_ty = caller_class->methods.at(method_idx).second;// get pointer from vtableValue* method_ptr = env->builder.CreateStructGEP(caller_class->vtable_type,vtable, method_idx + 3, "d.mptr"); // first three elems of the vtable aren't methodsauto* method = env->builder.CreateLoad(method_ty->getPointerTo(), method_ptr, "d." + n);// build method argsstd::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 methodif (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 primsif (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 checkenv->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 tagauto* 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 boxedauto* res = env->insert_alloca_at_head(env->ptr);// store nullptrenv->builder.CreateStore(ConstantPointerNull::get(env->ptr), res);// sort cases largest tag to smalleststd::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 matchenv->builder.CreateBr(abort);env->builder.SetInsertPoint(matchbb);// test if result is nullauto* 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 upenv->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 methodvoid method_class::layout_feature(CgenNode* cls){// if (cls->basic())// return; // handled by the runtimeauto* 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 ptrauto _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 functionauto* ty = CgenNode::create_functionty(env->as_mostly_boxed_type(return_type), real_args);fn = cls->create_function(as_string(get_name()), ty);#ifdef EMIT_DBGif (!cls->basic()) {// debug function typestd::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);}#endifcls->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 casesauto* 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 tagauto* 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 scopeenv->add_binding(name, branchptr);auto* res = expr->code(env);env->close_scope();// store into resultenv->builder.CreateStore(res, mem);env->builder.CreateBr(sbb);env->builder.SetInsertPoint(endbb);}// Assign this attribute a slot in the class structurevoid 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 infocls->dfeats.emplace_back(env->as_boxed_dtype(type_decl));#endifdelete 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 thingsif (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(...)#endiftypedef 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 implementsthe 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 __cplusplusextern "C" {#endifWINGETOPT_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_optresetextern 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 __cplusplusextern "C" {#endifstruct 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_GETOPTint 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_optresetint 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]#elseextern char __declspec(dllimport) *__progname;#endif#ifdef __CYGWIN__static char EMSG[] = "";#else#define EMSG ""#endifstatic 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 voidwarnx(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 intgcd(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 voidpermute_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;elsepos += 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 intparse_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++;} elsecurrent_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;elseoptopt = 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;elseoptopt = 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);} elsereturn (long_options[match].val);#undef IDENTICAL_INTERPRETATION}/** getopt_internal --* Parse argc/argv argument vector. Called by user level routines.*/static intgetopt_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);} elseoptarg = 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]*/intgetopt(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.*/intgetopt_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.*/intgetopt_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' functionsProgram 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 BisonClasses 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 treeFILE* ast_file = stdin; // we read the AST from standard inputextern int ast_yyparse(void); // entry point to the AST parserstd::string out_filename; // file name for generated codeint cgen_debug, curr_lineno; // for code genextern 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 defaultcgen_debug = 0;while ((c = getopt(argc, argv, "do:")) != -1) {switch (c) {#ifdef DEBUGcase 'd':cgen_debug = 1;break;#elsecase 'd':std::cerr << "No debugging available\n";break;#endifcase 'o': // set the name of the output fileout_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";#endifexit(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.yby 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 YYSTYPEtypedef 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 YYDEBUGstatic 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 YYTABLEdoesn't specify something else to do. Zero means the default is anerror. */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 115static 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 SoftwareFoundation, Inc.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* As a special exception, when this file is copied by Bison into aBison output file, you may use that output file without restriction.This special exception was added by the Free Software Foundationin version 1.24 of Bison. *//* This is the parser code that is written into each bison parser whenthe %semantic_parser declaration is not specified in the grammar.It was written by Richard Stallman by simplifying the hairy parserused when %semantic_parser is specified. *//* All symbols defined below should begin with yy or YY, to avoidinfringing on user name space. This should be done even for localvariables, as they might otherwise be expanded by user macros.There are some unavoidable exceptions within include files todefine necessary library symbols; they are noted "INFRINGES ONUSER 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_NEEDEDYYLTYPE 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 withN 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 donot 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. Thelocal variables YYSIZE and YYSTACKSIZE give the old and new number ofelements in the stack, and YYPTR gives the new location of thestack. Advance YYPTR to a properly aligned location for the nextstack. */#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 temporarilyto 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 actionsare run).When YYLLOC_DEFAULT is run, CURRENT is set the location of thefirst token. By default, to implement support for ranges, extendits 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 thatmultiple 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 onlyif the built-in stack extension method is used).Do not make this value too large; the results are undefined ifSIZE_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)#elseyystrlen(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' inYYDEST. */static char *#if defined(__STDC__) || defined(__cplusplus)yystpcpy(char *yydest, const char *yysrc)#elseyystpcpy(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 passedinto yyparse. The argument should have type void *.It should actually point to an object.Grammar actions can access the variable by casting itto 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_PARAMint yyparse(void *);#elseint 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 !YYPUREYY_DECL_VARIABLES#endif /* !YYPURE */int yyparse(YYPARSE_PARAM_ARG) YYPARSE_PARAM_DECL {/* If reentrant, generate the variables here. */#if YYPUREYY_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 yyoverflowto 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--)#endifYYSIZE_T yystacksize = YYINITDEPTH;/* The variables used to return semantic value and location from theaction routines. */YYSTYPE yyval;#if YYLSP_NEEDEDYYLTYPE yyloc;#endif/* When reducing, the number of symbols on the RHS of the reducedrule. */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 stackso that they stay on the same level as the state stack.The wasted elements are never initialized. */yyssp = yyss;yyvsp = yyvs;#if YYLSP_NEEDEDyylsp = yyls;#endifgoto yysetstate;/*------------------------------------------------------------.| yynewstate -- Push a new state, which is found in yystate. |`------------------------------------------------------------*/yynewstate:/* In all cases, when you get here, the value and location stackshave 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 ofthese so that the &'s don't force the real ones intomemory. */YYSTYPE *yyvs1 = yyvs;short *yyss1 = yyss;/* Each stack pointer address is followed by the size of thedata in use in that stack, in bytes. */#if YYLSP_NEEDEDYYLTYPE *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;#elseyyoverflow("parser stack overflow", &yyss1, yysize * sizeof(*yyssp),&yyvs1, yysize * sizeof(*yyvsp), &yystacksize);#endifyyss = yyss1;yyvs = yyvs1;}#else /* no yyoverflow */#ifndef YYSTACK_RELOCATEgoto 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_NEEDEDYYSTACK_RELOCATE(yyls);#endif#undef YYSTACK_RELOCATEif (yyss1 != yyssa)YYSTACK_FREE(yyss1);}#endif#endif /* no yyoverflow */yyssp = yyss + yysize - 1;yyvsp = yyvs + yysize - 1;#if YYLSP_NEEDEDyylsp = yyls + yysize - 1;#endifYYDPRINTF((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 YYEOFor 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 variableswhich 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 precisemeaning of a token, for further debugging info. */#ifdef YYPRINTYYPRINT(stderr, yychar, yylval);#endifYYFPRINTF(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 errorstatus. */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 ofthe lookahead token. This behavior is undocumented and Bisonusers should not rely upon it. Assigning to YYVALunconditionally makes the parser a bit smaller, and it avoids aGCC warning that YYVAL may be used uninitialized. */yyval = yyvsp[1 - yylen];#if YYLSP_NEEDED/* Similarly for the default location. Let the user run additionalcommands 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 whichare 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]]);}#endifswitch (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);elseyyval.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_NEEDEDyylsp -= yylen;#endif#if YYDEBUGif (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 statethat goes to, based on the state we popped back to and the rulenumber reduced by. */yyn = yyr1[yyn];yystate = yypgoto[yyn - YYNTBASE] + *yyssp;if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)yystate = yytable[yystate];elseyystate = 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_VERBOSEyyn = 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 inYYCHECK. */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);} elseyyerror("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 anerror, 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 errortoken. */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 tokensshould 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_NEEDEDyylsp--;#endif#if YYDEBUGif (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;#endifyystate = 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 yyoverflowif (yyss != yyssa)YYSTACK_FREE(yyss);#endifreturn 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 16384typedef 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_DEBUGtypedef unsigned char YY_CHAR;FILE *yyin = (FILE *)0, *yyout = (FILE *)0;typedef int yy_state_type;#define FLEX_DEBUGextern char *yytext;#define yytext_ptr yytextstatic 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 48static 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_OFFSETchar *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 __cplusplusextern "C" int yywrap YY_PROTO((void));#elseextern int yywrap YY_PROTO((void));#endif#endif#ifndef YY_NO_UNPUTstatic void yyunput YY_PROTO((int c, char *buf_ptr));#endif#ifndef yytext_ptrstatic void yy_flex_strncpy YY_PROTO((char *, yyconst char *, int));#endif#ifdef YY_NEED_STRLENstatic int yy_flex_strlen YY_PROTO((yyconst char *));#endif#ifndef YY_NO_INPUT#ifdef __cplusplusstatic int yyinput YY_PROTO((void));#elsestatic int input YY_PROTO((void));#endif#endif#if YY_STACK_USEDstatic int yy_start_stack_ptr = 0;static int yy_start_stack_depth = 0;static int *yy_start_stack = 0;#ifndef YY_NO_PUSH_STATEstatic void yy_push_state YY_PROTO((int new_state));#endif#ifndef YY_NO_POP_STATEstatic void yy_pop_state YY_PROTO((void));#endif#ifndef YY_NO_TOP_STATEstatic 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_DECLYY_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_ACTIONYY_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_INITYY_USER_INIT;#endifif (!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");elsefprintf(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_BREAKcase 2:YY_RULE_SETUP#line 48 "ast.flex"{yylval.symbol = inttable.add_string(std::string(yytext, yyleng));return (INT_CONST);}YY_BREAKcase 3:YY_RULE_SETUP#line 51 "ast.flex"{yylval.lineno = atoi(yytext + 1);return (LINENO);}YY_BREAKcase 4:YY_RULE_SETUP#line 54 "ast.flex"{return (PROGRAM);}YY_BREAKcase 5:YY_RULE_SETUP#line 55 "ast.flex"{return (CLASS);}YY_BREAKcase 6:YY_RULE_SETUP#line 56 "ast.flex"{return (METHOD);}YY_BREAKcase 7:YY_RULE_SETUP#line 57 "ast.flex"{return (ATTR);}YY_BREAKcase 8:YY_RULE_SETUP#line 58 "ast.flex"{return (FORMAL);}YY_BREAKcase 9:YY_RULE_SETUP#line 59 "ast.flex"{return (BRANCH);}YY_BREAKcase 10:YY_RULE_SETUP#line 60 "ast.flex"{return (ASSIGN);}YY_BREAKcase 11:YY_RULE_SETUP#line 61 "ast.flex"{return (STATIC_DISPATCH);}YY_BREAKcase 12:YY_RULE_SETUP#line 62 "ast.flex"{return (DISPATCH);}YY_BREAKcase 13:YY_RULE_SETUP#line 63 "ast.flex"{return (COND);}YY_BREAKcase 14:YY_RULE_SETUP#line 64 "ast.flex"{return (LOOP);}YY_BREAKcase 15:YY_RULE_SETUP#line 65 "ast.flex"{return (TYPCASE);}YY_BREAKcase 16:YY_RULE_SETUP#line 66 "ast.flex"{return (BLOCK);}YY_BREAKcase 17:YY_RULE_SETUP#line 67 "ast.flex"{return (LET);}YY_BREAKcase 18:YY_RULE_SETUP#line 68 "ast.flex"{return (PLUS);}YY_BREAKcase 19:YY_RULE_SETUP#line 69 "ast.flex"{return (SUB);}YY_BREAKcase 20:YY_RULE_SETUP#line 70 "ast.flex"{return (MUL);}YY_BREAKcase 21:YY_RULE_SETUP#line 71 "ast.flex"{return (DIVIDE);}YY_BREAKcase 22:YY_RULE_SETUP#line 72 "ast.flex"{return (NEG);}YY_BREAKcase 23:YY_RULE_SETUP#line 73 "ast.flex"{return (LESSTHAN);}YY_BREAKcase 24:YY_RULE_SETUP#line 74 "ast.flex"{return (EQUAL);}YY_BREAKcase 25:YY_RULE_SETUP#line 75 "ast.flex"{return (LEQ);}YY_BREAKcase 26:YY_RULE_SETUP#line 76 "ast.flex"{return (COMP);}YY_BREAKcase 27:YY_RULE_SETUP#line 77 "ast.flex"{return (INT);}YY_BREAKcase 28:YY_RULE_SETUP#line 78 "ast.flex"{return (STR);}YY_BREAKcase 29:YY_RULE_SETUP#line 79 "ast.flex"{return (BOOL);}YY_BREAKcase 30:YY_RULE_SETUP#line 80 "ast.flex"{return (NEW);}YY_BREAKcase 31:YY_RULE_SETUP#line 81 "ast.flex"{return (ISVOID);}YY_BREAKcase 32:YY_RULE_SETUP#line 82 "ast.flex"{return (NO_EXPR);}YY_BREAKcase 33:YY_RULE_SETUP#line 83 "ast.flex"{return (NO_TYPE);}YY_BREAKcase 34:YY_RULE_SETUP#line 84 "ast.flex"{return (OBJECT);}YY_BREAKcase 35:YY_RULE_SETUP#line 86 "ast.flex"{return (*yytext);}YY_BREAKcase 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_BREAKcase 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_BREAKcase 39:YY_RULE_SETUP#line 113 "ast.flex"{*string_buf_ptr++ = '\n';}YY_BREAKcase 40:YY_RULE_SETUP#line 114 "ast.flex"{*string_buf_ptr++ = '\t';}YY_BREAKcase 41:YY_RULE_SETUP#line 115 "ast.flex"{*string_buf_ptr++ = '\b';}YY_BREAKcase 42:YY_RULE_SETUP#line 116 "ast.flex"{*string_buf_ptr++ = '\f';}YY_BREAKcase 43:YY_RULE_SETUP#line 117 "ast.flex"{*string_buf_ptr++ = '\\';}YY_BREAKcase 44:YY_RULE_SETUP#line 118 "ast.flex"{*string_buf_ptr++ = '\"';}YY_BREAKcase 45:YY_RULE_SETUP#line 120 "ast.flex"{/* unprintable characters are represented as octal numbers */*string_buf_ptr++ = strtol(yytext + 1, 0, 8);}YY_BREAKcase 46:YY_RULE_SETUP#line 125 "ast.flex"{*string_buf_ptr++ = yytext[0];}YY_BREAKcase YY_STATE_EOF(INITIAL):case YY_STATE_EOF(STRING):#line 127 "ast.flex"{yyterminate();}YY_BREAKcase 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_OFFSETif (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;}}elseswitch (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_REJECTYY_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;elseb->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;}}elseret_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_PROTOSstatic yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state)#elsestatic yy_state_typeyy_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_PROTOSstatic void yyunput(int c, register char *yy_bp)#elsestatic 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 __cplusplusstatic int yyinput()#elsestatic 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 __cplusplusreturn yyinput();#elsereturn 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_PROTOSvoid yyrestart(FILE *input_file)#elsevoid 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_PROTOSvoid yy_switch_to_buffer(YY_BUFFER_STATE new_buffer)#elsevoid 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_PROTOSvoid yy_load_buffer_state(void)#elsevoid 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_PROTOSYY_BUFFER_STATE yy_create_buffer(FILE *file, int size)#elseYY_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_PROTOSvoid yy_delete_buffer(YY_BUFFER_STATE b)#elsevoid 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_PROTOSvoid yy_init_buffer(YY_BUFFER_STATE b, FILE *file)#elsevoid 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_INTERACTIVEb->yy_is_interactive = 1;#else#if YY_NEVER_INTERACTIVEb->yy_is_interactive = 0;#elseb->yy_is_interactive = file ? (isatty(fileno(file)) > 0) : 0;#endif#endif}#ifdef YY_USE_PROTOSvoid yy_flush_buffer(YY_BUFFER_STATE b)#elsevoid 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_PROTOSYY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size)#elseYY_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_PROTOSYY_BUFFER_STATE yy_scan_string(yyconst char *yy_str)#elseYY_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_PROTOSYY_BUFFER_STATE yy_scan_bytes(yyconst char *bytes, int len)#elseYY_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_PROTOSstatic void yy_push_state(int new_state)#elsestatic 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);elseyy_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_STATEstatic 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_STATEstatic 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_PROTOSstatic void yy_fatal_error(yyconst char msg[])#elsestatic 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_PROTOSstatic void yy_flex_strncpy(char *s1, yyconst char *s2, int n)#elsestatic 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_PROTOSstatic int yy_flex_strlen(yyconst char *s)#elsestatic int yy_flex_strlen(s) yyconst char *s;#endif{register int n;for (n = 0; s[n]; ++n);return n;}#endif#ifdef YY_USE_PROTOSstatic void *yy_flex_alloc(yy_size_t size)#elsestatic void *yy_flex_alloc(size) yy_size_t size;#endif{return (void *)malloc(size);}#ifdef YY_USE_PROTOSstatic void *yy_flex_realloc(void *ptr, yy_size_t size)#elsestatic 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_PROTOSstatic void yy_flex_free(void *ptr)#elsestatic void yy_flex_free(ptr) void *ptr;#endif{free(ptr);}#if YY_MAINint 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 madepublic: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;elsereturn 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::SymbolTablenamespace 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_EXTRASStringEntry_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_EXTRASIntEntry_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_EXTRASStrTable_EXTRAS#endif};class IntTable : public StringTable<IntEntry> {public:#ifdef IntTable_EXTRASIntTable_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 anypurpose, without fee, and without written agreement is hereby granted,provided that the above copyright notice and the following twoparagraphs appear in all copies of this software.IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FORDIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUTOF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OFCALIFORNIA 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 MERCHANTABILITYAND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER ISON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TOPROVIDE 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.hThis file defines classes for each phylum and constructor(Partly copied over from dumptype.cc)It may help to know the inheritance hierarchy of the classesthat define the structure of the Cool AST.In the list below, the outer classes are the Phylawhich 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_classprogram_classClass__classclass_classFeature_classmethod_class (_class omitted below)attrFormal_classformalCase_classbranchExpression_classassignstatic_dispatchdispatchcondlooptypcaseblockletplussubmuldivideneglteqleqcompint_constbool_conststring_constnew_isvoidno_exprobjectAll of the Phyla inherit from the tree_node class.Some AST nodes have lists of other tree nodes as components. Lists in theAST are built using the class list_node defined in tree.h. The listclasses in the Cool AST are:Classes a list of Class_Features a list of FeatureExpressions a list of ExpressionCases 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 - Programtypedef 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_EXTRASProgram_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__EXTRASClass__EXTRAS#endif};// define simple phylum - Featuretypedef class Feature_class *Feature;class Feature_class : public tree_node {public:tree_node *copy() { return copy_Feature(); }virtual Feature copy_Feature() = 0;#ifdef Feature_EXTRASFeature_EXTRAS#endif};// define simple phylum - Formaltypedef class Formal_class *Formal;class Formal_class : public tree_node {public:tree_node *copy() { return copy_Formal(); }virtual Formal copy_Formal() = 0;#ifdef Formal_EXTRASFormal_EXTRAS#endif};// define simple phylum - Expressiontypedef class Expression_class *Expression;class Expression_class : public tree_node {public:tree_node *copy() { return copy_Expression(); }virtual Expression copy_Expression() = 0;#ifdef Expression_EXTRASExpression_EXTRAS#endif};// define simple phylum - Casetypedef class Case_class *Case;class Case_class : public tree_node {public:tree_node *copy() { return copy_Case(); }virtual Case copy_Case() = 0;#ifdef Case_EXTRASCase_EXTRAS#endif};// define the class for phylum - LIST// define list phlyum - Classestypedef list_node<Class_> Classes_class;typedef Classes_class *Classes;// define list phlyum - Featurestypedef list_node<Feature> Features_class;typedef Features_class *Features;// define list phlyum - Formalstypedef list_node<Formal> Formals_class;typedef Formals_class *Formals;// define list phlyum - Expressionstypedef list_node<Expression> Expressions_class;typedef Expressions_class *Expressions;// define list phlyum - Casestypedef list_node<Case> Cases_class;typedef Cases_class *Cases;// define the class for constructors// define constructor - programclass 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_EXTRASProgram_SHARED_EXTRAS#endif#ifdef program_EXTRASprogram_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_EXTRASClass__SHARED_EXTRAS#endif#ifdef class__EXTRASclass__EXTRAS#endif};// define constructor - methodclass 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_EXTRASFeature_SHARED_EXTRAS#endif#ifdef method_EXTRASmethod_EXTRAS#endif};// define constructor - attrclass 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_EXTRASFeature_SHARED_EXTRAS#endif#ifdef attr_EXTRASattr_EXTRAS#endif};// define constructor - formalclass 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_EXTRASFormal_SHARED_EXTRAS#endif#ifdef formal_EXTRASformal_EXTRAS#endif};// define constructor - branchclass 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_EXTRASCase_SHARED_EXTRAS#endif#ifdef branch_EXTRASbranch_EXTRAS#endif};// define constructor - assignclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef assign_EXTRASassign_EXTRAS#endif};// define constructor - static_dispatchclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef static_dispatch_EXTRASstatic_dispatch_EXTRAS#endif};// define constructor - dispatchclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef dispatch_EXTRASdispatch_EXTRAS#endif};// define constructor - condclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef cond_EXTRAScond_EXTRAS#endif};// define constructor - loopclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef loop_EXTRASloop_EXTRAS#endif};// define constructor - typcaseclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef typcase_EXTRAStypcase_EXTRAS#endif};// define constructor - blockclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef block_EXTRASblock_EXTRAS#endif};// define constructor - letclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef let_EXTRASlet_EXTRAS#endif};// define constructor - plusclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef plus_EXTRASplus_EXTRAS#endif};// define constructor - subclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef sub_EXTRASsub_EXTRAS#endif};// define constructor - mulclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef mul_EXTRASmul_EXTRAS#endif};// define constructor - divideclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef divide_EXTRASdivide_EXTRAS#endif};// define constructor - negclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef neg_EXTRASneg_EXTRAS#endif};// define constructor - ltclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef lt_EXTRASlt_EXTRAS#endif};// define constructor - eqclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef eq_EXTRASeq_EXTRAS#endif};// define constructor - leqclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef leq_EXTRASleq_EXTRAS#endif};// define constructor - compclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef comp_EXTRAScomp_EXTRAS#endif};// define constructor - int_constclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef int_const_EXTRASint_const_EXTRAS#endif};// define constructor - bool_constclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef bool_const_EXTRASbool_const_EXTRAS#endif};// define constructor - string_constclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef string_const_EXTRASstring_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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef new__EXTRASnew__EXTRAS#endif};// define constructor - isvoidclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef isvoid_EXTRASisvoid_EXTRAS#endif};// define constructor - no_exprclass no_expr_class : public Expression_class {protected:public:no_expr_class() {}Expression copy_Expression();void dump(std::ostream &stream, int n);#ifdef Expression_SHARED_EXTRASExpression_SHARED_EXTRAS#endif#ifdef no_expr_EXTRASno_expr_EXTRAS#endif};// define constructor - objectclass 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_EXTRASExpression_SHARED_EXTRAS#endif#ifdef object_EXTRASobject_EXTRAS#endif};// define the prototypes of the interfaceClasses 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 basicfunctionality. You will need to add members to each of the classesto get them to perform their desired functions. Document your importantdesign decisions below. We should be able to read your documentation andget a general overview of how your compiler generates code. For instance,how does your compiler generate structures for classes, how is inheritancemodeled, 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(...)#endifclass 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 processCgenClassTable(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 codevoid setup_external_functions();void setup_classes(CgenNode *c, int depth);// Setup each class in the table and prepare for code generation phasevoid 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. Objectpublic:int get_num_classes() const { return current_tag; }private:// Class lists and current class tagstd::vector<CgenNode *> nds, special_nds;int current_tag;public:// LLVM Utilllvm::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::LinkageTypeslinkage);// 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 treevoid 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 fieldsint 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 generationvoid layout_features();// Class codegen. You need to write the body of this function.void code_class();// Codegen for the init function of every classvoid 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 classstd::vector<CgenNode *> children; // Children of classBasicness basic_status; // `Basic' or 'NotBasic'CgenClassTable *class_table;// Class tag. Should be unique for each class in the treeint 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 nameCgenNode *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 appendedllvm::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 compatiblellvm::Value* conform(llvm::Value* src, llvm::Type* dest_type) __attribute((pure));private:// mapping from variable names to memory locationscool::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 YYSTYPEtypedef 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 291extern 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"],)