ParseNode gen_vardef_simple(const ParseNode & type, std::string name) { ParseNode newnode = ParseNode(gen_flex(Term{ TokenMeta::NT_VARIABLEDEFINE, name }), nullptr); newnode.addchild(new ParseNode(type)); // type newnode.addchild(new ParseNode(gen_flex(Term{ TokenMeta::NT_VOID, "" }), nullptr)); // variable_desc ParseNode kv = gen_keyvalue(gen_token(Term{ TokenMeta::UnknownVariant, name })); ParseNode pt = gen_paramtable(kv); newnode.addchild(new ParseNode(pt)); // type return newnode; }
ParseNode gen_argtable(ParseNode & dimen_slice) { ParseNode newnode = ParseNode(); bool isdimen = false; int sliceid = 0; /* if the array has 2 dimensions, sliceid is 0..1 */ dimen_slice.fs.CurrentTerm.what = ""; for (sliceid = 0; sliceid < dimen_slice.child.size(); sliceid++) { if (sliceid != 0) { dimen_slice.fs.CurrentTerm.what += ", "; } if (dimen_slice.fs.CurrentTerm.token == TokenMeta::NT_DIMENSLICE) { // dimen_slice // slice or slice/exp isdimen = true; newnode.addchild(new ParseNode(*dimen_slice.child[sliceid])); if (dimen_slice.child[sliceid]->fs.CurrentTerm.token == TokenMeta::NT_SLICE) { // slice if (dimen_slice.child[sliceid]->child.size() == 2) { /* from, to */ sprintf(codegen_buf, "%s, %s", dimen_slice.child[sliceid]->child[0]->fs.CurrentTerm.what.c_str() , dimen_slice.child[sliceid]->child[1]->fs.CurrentTerm.what.c_str()); } else { // size sprintf(codegen_buf, "%s", dimen_slice.child[sliceid]->child[0]->fs.CurrentTerm.what.c_str()); } } else { // exp sprintf(codegen_buf, "%s", dimen_slice.child[sliceid]->fs.CurrentTerm.what.c_str()); } } else if(dimen_slice.fs.CurrentTerm.token == TokenMeta::NT_ARGTABLE_PURE){ // NT_ARGTABLE_PURE // exp isdimen = false; newnode.addchild(new ParseNode(*dimen_slice.child[sliceid])); sprintf(codegen_buf, "%s", dimen_slice.child[sliceid]->fs.CurrentTerm.what.c_str()); } else { print_error("Illegal argtable", dimen_slice); } dimen_slice.fs.CurrentTerm.what += codegen_buf; } if (isdimen) { // %%s.slice(%s) // should not set codegen_buf here sprintf(codegen_buf, "/* deprecated */ slice(%%s, %s)", dimen_slice.fs.CurrentTerm.what.c_str()); newnode.fs.CurrentTerm = Term{ TokenMeta::NT_PARAMTABLE_DIMENSLICE, string(codegen_buf) }; } else { sprintf(codegen_buf, "%s", dimen_slice.fs.CurrentTerm.what.c_str()); newnode.fs.CurrentTerm = Term{ TokenMeta::NT_ARGTABLE_PURE, string(codegen_buf) }; } return newnode; }
ParseNode gen_case(const ParseNode & dimen_slice, ParseNode & suite) { // one case ParseNode newnode = ParseNode(); suite.fs.CurrentTerm.what = tabber(suite.fs.CurrentTerm.what); newnode.fs.CurrentTerm = Term{ TokenMeta::NT_CASE, "" }; ParseNode select; newnode.addchild(new ParseNode(select)); // case newnode.addchild(new ParseNode(dimen_slice)); // dimen_slice newnode.addchild(new ParseNode(suite)); // suite return newnode; }
ParseNode gen_keyvalue(const ParseNode & variable) { /* paramtable is used in function decl */ /* this paramtable has only one value */ sprintf(codegen_buf, "%s", variable.fs.CurrentTerm.what.c_str()); ParseNode newnode = ParseNode(gen_flex(Term{ TokenMeta::NT_VARIABLEINITIAL, string(codegen_buf) }), nullptr); newnode.addchild(new ParseNode(variable)); // type newnode.addchild(new ParseNode(gen_flex(Term{ TokenMeta::NT_VARIABLEINITIALDUMMY, string("void") }), &newnode, nullptr)); // void is dummy initial // instead of return a NT_PARAMTABLE, now return NT_KEYVALUE node return newnode; }
ParseNode gen_keyvalue_from_arraybuilder(const ParseNode & variable, const ParseNode & initial) { /* paramtable is used in function decl */ /* this paramtable has only one value */ /* 因为使用forarray作为数组, 故需要知道类型信息, 不在此处赋值, 在上层的var_def赋初值 */ sprintf(codegen_buf, "%s.init(%s)", variable.fs.CurrentTerm.what.c_str(), initial.fs.CurrentTerm.what.c_str()); ParseNode newnode = ParseNode(gen_flex(Term{ TokenMeta::NT_VARIABLEINITIAL, string(codegen_buf) }), nullptr); newnode.addchild(new ParseNode(variable)); // type newnode.addchild(new ParseNode(initial)); // void is dummy initial // instead of return a NT_PARAMTABLE, now return NT_KEYVALUE node return newnode; }
ParseNode gen_paramtable(ParseNode & paramtable_elem) { ParseNode newnode = ParseNode(); if (paramtable_elem.fs.CurrentTerm.token == TokenMeta::NT_DIMENSLICE || paramtable_elem.fs.CurrentTerm.token == TokenMeta::NT_ARGTABLE_PURE) { // promote dimen_slice to paramtable return gen_argtable(paramtable_elem); } else if(paramtable_elem.fs.CurrentTerm.token == TokenMeta::NT_KEYVALUE){ newnode.addchild(new ParseNode(paramtable_elem)); // keyvalue sprintf(codegen_buf, "%s", paramtable_elem.fs.CurrentTerm.what.c_str()); newnode.fs.CurrentTerm = Term{ TokenMeta::NT_PARAMTABLE, string(codegen_buf) }; return newnode; } else if (paramtable_elem.fs.CurrentTerm.token == TokenMeta::NT_PARAMTABLE || paramtable_elem.fs.CurrentTerm.token == TokenMeta::NT_PARAMTABLE_DIMENSLICE) { // get a paramtable from dimen_slice newnode = paramtable_elem; return newnode; } else { newnode = paramtable_elem; print_error("Illegal gen_paramtable arg", newnode); return newnode; } }
ParseNode gen_empty_suite() { ParseNode * newnode = new ParseNode(); ParseNode & stmt = ParseNode(gen_flex(Term{ TokenMeta::NT_SUITE, "\n" }), newnode); newnode->fs.CurrentTerm = Term{ TokenMeta::NT_SUITE, "\n" }; newnode->addchild(new ParseNode(stmt)); // stmt newnode = flattern_bin(newnode); return *newnode; }
ParseNode gen_array_generate_stmt(const ParseNode & _generate_stmt) { /* give generate stmt */ ParseNode newnode = ParseNode(); ParseNode * exp = _generate_stmt.child[0]; ParseNode * index = _generate_stmt.child[1]; ParseNode * from = _generate_stmt.child[2]; ParseNode * to = _generate_stmt.child[3]; //print_error("LBound don't agree", _generate_stmt); sprintf(codegen_buf, "for(int %s = %s; %s < %s; %s++){\n%s(%s) = %s;\n}", index->fs.CurrentTerm.what.c_str(), from->fs.CurrentTerm.what.c_str() /* exp_from */ , index->fs.CurrentTerm.what.c_str(), to->fs.CurrentTerm.what.c_str() /* exp_to */, index->fs.CurrentTerm.what.c_str() /* index variable inc */ , "\t%s" /* array variable name */, index->fs.CurrentTerm.what.c_str() /* index variable */, exp->fs.CurrentTerm.what.c_str()); newnode.fs.CurrentTerm = Term{ TokenMeta::NT_ARRAYBUILDER_EXP, string(codegen_buf) }; newnode.addchild(new ParseNode(*exp)); // exp newnode.addchild(new ParseNode(*index)); // index variable newnode.addchild(new ParseNode(*from)); // exp_from newnode.addchild(new ParseNode(*to)); // exp_to return newnode; }
ParseNode gen_promote_paramtable(const ParseNode paramtable) { const ParseNode * pn = ¶mtable; ParseNode newnode = ParseNode(gen_flex(Term{ TokenMeta::NT_PARAMTABLE, "" }), nullptr); do { // for all non-flatterned paramtable for (int i = 0; i < pn->child.size(); i++) { newnode.addchild(new ParseNode(gen_promote_exp_to_keyvalue(*pn->child[i]))); } if (pn->child.size() >= 2) { /* if pn->child.size() == 0, this is an empty paramtable(this function takes no arguments) */ /* if the paramtable is not flatterned pn->child[1] is a right-recursive paramtable node */ pn = pn->child[1]; } } while (pn->child.size() == 2 && pn->child[1]->fs.CurrentTerm.token == TokenMeta::NT_PARAMTABLE); return newnode; }
ParseNode gen_select(const ParseNode & exp, const ParseNode & case_stmt) { ParseNode newnode = ParseNode(); string codegen = ""; for (int i = 0; i < case_stmt.child.size(); i++) { ParseNode & case_stmt_elem = *case_stmt.child[i]; ParseNode & dimen_slice = *case_stmt_elem.child[1]; /* 0 -- case 1 -- dimen_slice 2 -- stmt(case body) */ if (dimen_slice.fs.CurrentTerm.token == TokenMeta::NT_DIMENSLICE) { // NT_DIMENSLICE string dsstr; for (int sliceid = 0; sliceid < dimen_slice.child.size(); sliceid++) { if (sliceid == 0) { sprintf(codegen_buf, "(%s >= %s && %s < %s)", exp.fs.CurrentTerm.what.c_str(), dimen_slice.child[sliceid]->child[0]->fs.CurrentTerm.what.c_str(), exp.fs.CurrentTerm.what.c_str(), dimen_slice.child[sliceid]->child[1]->fs.CurrentTerm.what.c_str()); } else { sprintf(codegen_buf, " || (%s >= %s && %s < %s)", exp.fs.CurrentTerm.what.c_str(), dimen_slice.child[sliceid]->child[0]->fs.CurrentTerm.what.c_str(), exp.fs.CurrentTerm.what.c_str(), dimen_slice.child[sliceid]->child[1]->fs.CurrentTerm.what.c_str()); } dsstr += string(codegen_buf); } if (i == 0) { sprintf(codegen_buf, "if(%s){\n%s}\n", dsstr.c_str(), case_stmt_elem.child[2]->fs.CurrentTerm.what.c_str()); } else { sprintf(codegen_buf, "else if(%s){\n%s}\n", dsstr.c_str(), case_stmt_elem.child[2]->fs.CurrentTerm.what.c_str()); } } else { // NT_ARGTABLE_PURE string choice = ""; if (i == 0) { choice = "if("; sprintf(codegen_buf, "if(%s == %s){\n%s}\n", exp.fs.CurrentTerm.what.c_str(), dimen_slice.child[0]->fs.CurrentTerm.what.c_str(), case_stmt_elem.child[2]->fs.CurrentTerm.what.c_str()); } else { choice = "else if("; sprintf(codegen_buf, "else if(%s == %s){\n%s}\n", exp.fs.CurrentTerm.what.c_str(), dimen_slice.child[0]->fs.CurrentTerm.what.c_str(), case_stmt_elem.child[2]->fs.CurrentTerm.what.c_str()); } for (int j = 0; j < dimen_slice.child.size(); j++) { if (j == 0) { sprintf(codegen_buf, "%s == %s", exp.fs.CurrentTerm.what.c_str(), dimen_slice.child[j]->fs.CurrentTerm.what.c_str()); } else { sprintf(codegen_buf, "|| (%s == %s)", exp.fs.CurrentTerm.what.c_str(), dimen_slice.child[j]->fs.CurrentTerm.what.c_str()); } choice += codegen_buf; } sprintf(codegen_buf, "){\n%s}\n", case_stmt_elem.child[2]->fs.CurrentTerm.what.c_str()); choice += codegen_buf; sprintf(codegen_buf, "%s", choice.c_str()); } codegen += codegen_buf; } newnode.fs.CurrentTerm = Term{ TokenMeta::NT_SELECT, codegen }; ParseNode select = ParseNode(); newnode.addchild(new ParseNode(select)); // select newnode.addchild(new ParseNode(exp)); // exp newnode.addchild(new ParseNode(case_stmt)); // suite return newnode; }
ParseNode gen_vardef(const ParseNode & type_spec, const ParseNode & variable_desc, const ParseNode & paramtable) { ParseNode newnode = ParseNode(); string arr_decl = ""; string var_decl = ""; bool do_arr = false; VariableDescAttr * vardescattr = dynamic_cast<VariableDescAttr *>(variable_desc.attr); ParseNode * slice = vardescattr->desc.slice; ParseNode * spec_typename = promote_type(type_spec, vardescattr); // reset type according to kind if (slice == nullptr) { // slice == nullptr if this is not array /* must assure no ParseNode * is nullptr */ slice = new ParseNode(gen_flex(Term{ TokenMeta::NT_VOID, "" }), nullptr); } else { do_arr = true; } newnode.addchild(spec_typename); // type newnode.addchild(slice); // variable_desc ParseNode * pn = new ParseNode(gen_promote_paramtable(paramtable)); newnode.addchild(pn); // paramtable newnode.attr = new VariableDescAttr(*dynamic_cast<VariableDescAttr *>(variable_desc.attr)); // attr if (do_arr) { // ARRAY arr_decl = gen_vardef_array(pn, spec_typename, slice, vardescattr); newnode.fs.CurrentTerm = Term{ TokenMeta::NT_VARIABLEDEFINE, arr_decl }; } else { // SCALAR sprintf(codegen_buf, gen_vardef_typestr(vardescattr).c_str(), spec_typename->fs.CurrentTerm.what.c_str()); string typestr = string(codegen_buf); var_decl += typestr; bool hitted = false; // 是否至少有一个变量,因为有的变量定义可能是函数的声明,这在c++规范是不允许的,所以可能出现空int,空逗号的情况。 /* enumerate paramtable */ // pn is flattened for (int i = 0; i < pn->child.size(); i++) { ParseNode * this_variable = new ParseNode(*pn->child[i]); // skip if it is a function // TODO no module currently if (get_function("", this_variable->fs.CurrentTerm.what)) { continue; } if (hitted) { var_decl += ", "; } hitted = true; sprintf(codegen_buf, "%s", this_variable->child[0]->fs.CurrentTerm.what.c_str()); var_decl += codegen_buf; /* initial value */ if (this_variable->child[1]->fs.CurrentTerm.token != TokenMeta::NT_VARIABLEINITIALDUMMY) { /* if initial value is not dummy but `exp` */ var_decl += " = "; var_decl += this_variable->child[1]->fs.CurrentTerm.what; } /* desc */ this_variable->attr = vardescattr->clone(); } var_decl += ";"; if (!hitted) { // all function declarations var_decl = ""; } newnode.fs.CurrentTerm = Term{ TokenMeta::NT_VARIABLEDEFINE, var_decl }; } // end if // set all elements' attr in paramtable for (int i = 0; i < pn->child.size(); i++) { pn->child[i]->attr = newnode.attr->clone(); } return newnode; }
ParseNode gen_interface(const ParseNode & wrappers) { ParseNode newnode = ParseNode(gen_flex(Term{TokenMeta::NT_INTERFACE, ""/*wrappers.fs.CurrentTerm.what*/}), nullptr); newnode.addchild(new ParseNode(wrappers)); return newnode; }
ParseNode gen_array_generate_paramtable(const ParseNode & argtable) { /* give initial value */ /* `B(1:2:3)` can be either a single-element argtable or a exp, this can probably lead to reduction conflicts, so merge rules */ /* NOTE fortran use a 1d list to initialize a 2d(or higher) array, however, contrary to c++ and most other language does, it store them in a **conlumn - first order**. for a 2d array, it means you a order of a(1)(1)->a(2)(1)->a(lb_1)(1)->a(1)(2) */ ParseNode newnode = ParseNode(); vector<ParseNode *> slices; vector<ParseNode *> hiddens; std::vector<std::string> ans; string fi; for (int i = 0; i < argtable.child.size() + 1; i++) { int stat = 0; if (i == argtable.child.size()) { stat = 0; }else { if (argtable.child[i]->fs.CurrentTerm.token == TokenMeta::NT_EXPRESSION) { if (argtable.child[i]/* NT_EXPRESSION */->child[0]->fs.CurrentTerm.token == TokenMeta::NT_FUCNTIONARRAY) { // slice stat = 1; slices.push_back(argtable.child[i]->child[0]); } else if (argtable.child[i]/* NT_EXPRESSION */->child[0]->fs.CurrentTerm.token == TokenMeta::NT_HIDDENDO) { // hidden_do stat = 2; hiddens.push_back(argtable.child[i]->child[0]); } } else { /* for1array<_Container_value_type> & farr, const std::vector<int> & lower_bound , const std::vector<int> & size, const std::vector<T> & values */ // set in gen_vardef.cpp sprintf(codegen_buf, "init_for1array(%%s, %%s, %%s, std::vector<%%s>{%s});\n", /* value */ argtable.fs.CurrentTerm.what.c_str()); goto CAN_ONLY_GEN_ONE; } } if (stat != 1 && !slices.empty()) { for (int i = 0; i < slices.size(); i++) { ans.push_back(slices[i]->fs.CurrentTerm.what); } slices.clear(); } if (stat != 2 && !hiddens.empty()) { for (int i = 0; i < hiddens.size(); i++) { ans.push_back(hiddens[i]->fs.CurrentTerm.what); } hiddens.clear(); } } for (int i = 0; i < ans.size(); i++) { if (i != 0) fi += " + "; fi += ans[i]; } sprintf(codegen_buf, "%%s = %s;\n", /* value */ fi.c_str()); CAN_ONLY_GEN_ONE: newnode.fs.CurrentTerm = Term{ TokenMeta::NT_ARRAYBUILDER_VALUE, string(codegen_buf) }; newnode.addchild(new ParseNode(argtable)); // argtable return newnode; }
ParseNode gen_stmt(const ParseNode & content, const std::string & rules) { sprintf(codegen_buf, rules.c_str() , content.fs.CurrentTerm.what.c_str()); ParseNode newnode = ParseNode(gen_flex(Term{ TokenMeta::NT_STATEMENT, string(codegen_buf) }), nullptr); newnode.addchild(new ParseNode(content)); return newnode; }
ParseNode gen_paramtable(ParseNode & paramtable_elem, ParseNode & paramtable) { ParseNode newnode = ParseNode(gen_flex(Term{ TokenMeta::NT_PARAMTABLE, "" }), nullptr); bool dimen1 = false, dimen2 = false, arg1 = false, arg2 = false, va1 = false, va2 = false;; if (paramtable_elem.fs.CurrentTerm.token == TokenMeta::NT_DIMENSLICE) { dimen1 = true; } if (paramtable_elem.fs.CurrentTerm.token == TokenMeta::NT_ARGTABLE_PURE) { arg1 = true; } if (TokenMeta::iselement(paramtable_elem.fs.CurrentTerm.token)) { va1 = true; } if (paramtable.fs.CurrentTerm.token == TokenMeta::NT_PARAMTABLE_DIMENSLICE) { dimen2 = true; } if (paramtable.fs.CurrentTerm.token == TokenMeta::NT_ARGTABLE_PURE) { arg2 = true; } if (TokenMeta::iselement(paramtable.fs.CurrentTerm.token)) { va2 = true; } if (paramtable_elem.fs.CurrentTerm.token == TokenMeta::NT_KEYVALUE && paramtable.fs.CurrentTerm.token == TokenMeta::NT_PARAMTABLE) { // all keyvalue pair newnode = gen_flattern(paramtable_elem, paramtable, "%s, %s", TokenMeta::NT_PARAMTABLE); } else if(paramtable.fs.CurrentTerm.token == TokenMeta::NT_PARAMTABLE){ // there is keyvalue pair // this is possible because of rule `dimen_slice : exp ',' paramtable ` // there is keyvalue if (dimen1) { // promote dimen_slice to paramtable for (int i = 0; i < paramtable_elem.child.size(); i++) { newnode.addchild(new ParseNode(*paramtable_elem.child[i])); } } else { // do not promote exp to keyvalue // TODO newnode.addchild(new ParseNode(paramtable_elem)); } // assume paramtable is flatterned for (int i = 0; i < paramtable.child.size(); i++) { newnode.addchild(new ParseNode(*paramtable.child[i])); } sprintf(codegen_buf, "%s, %s", paramtable_elem.fs.CurrentTerm.what.c_str(), paramtable.fs.CurrentTerm.what.c_str()); newnode.fs.CurrentTerm.what = string(codegen_buf); } else if ((dimen1 || arg1 || va1) && (dimen2 || arg2 || va2)) { // all dimen_slice or argument_pure or variable newnode = ParseNode(gen_flex(Term{ (dimen1 || dimen2) ? TokenMeta::NT_PARAMTABLE_DIMENSLICE : TokenMeta::NT_ARGTABLE_PURE, "" }), nullptr); if (dimen1 || arg1) { for (int i = 0; i < paramtable_elem.child.size(); i++) { newnode.addchild(new ParseNode(*paramtable_elem.child[i])); } } else { newnode.addchild(new ParseNode(paramtable_elem)); } // assume paramtable is flatterned if (dimen2 || arg2) { for (int i = 0; i < paramtable.child.size(); i++) { newnode.addchild(new ParseNode(*paramtable.child[i])); } } else { newnode.addchild(new ParseNode(paramtable)); } sprintf(codegen_buf, "%s, %s", paramtable_elem.fs.CurrentTerm.what.c_str(), paramtable.fs.CurrentTerm.what.c_str()); newnode.fs.CurrentTerm.what = string(codegen_buf); } else { print_error("bad param table"); } return newnode; }