static int choice(int p1,int p2) { if(P_IS(p1,P_NOT_ALLOWED)) return p2; if(P_IS(p2,P_NOT_ALLOWED)) return p1; if(P_IS(p2,P_CHOICE)) { int p21,p22; Choice(p2,p21,p22); p1=choice(p1,p21); return choice(p1,p22); } if(samechoice(p1,p2)) return p1; if(nullable(p1) && (P_IS(p2,P_EMPTY))) return p1; if(nullable(p2) && (P_IS(p1,P_EMPTY))) return p2; return newChoice(p1,p2); }
void TypeConstraint::verifyFail(const Func* func, int paramNum, const TypedValue* tv) const { Transl::VMRegAnchor _; std::ostringstream fname; fname << func->fullName()->data() << "()"; const StringData* tn = typeName(); if (isSelf()) { selfToTypeName(func, &tn); } else if (isParent()) { parentToTypeName(func, &tn); } auto const givenType = describe_actual_type(tv); if (isExtended()) { // Extended type hints raise warnings instead of recoverable // errors for now, to ease migration (we used to not check these // at all at runtime). assert(nullable() && "only nullable extended type hints are currently supported"); raise_warning( "Argument %d to %s must be of type ?%s, %s given", paramNum + 1, fname.str().c_str(), tn->data(), givenType); } else { raise_recoverable_error( "Argument %d passed to %s must be an instance of %s, %s given", paramNum + 1, fname.str().c_str(), tn->data(), givenType); } }
/* ** p^n */ static int lp_star (lua_State *L) { int size1; int n = (int)luaL_checkinteger(L, 2); TTree *tree1 = getpatt(L, 1, &size1); if (n >= 0) { /* seq tree1 (seq tree1 ... (seq tree1 (rep tree1))) */ TTree *tree = newtree(L, (n + 1) * (size1 + 1)); if (nullable(tree1)) luaL_error(L, "loop body may accept empty string"); while (n--) /* repeat 'n' times */ tree = seqaux(tree, tree1, size1); tree->tag = TRep; memcpy(sib1(tree), tree1, size1 * sizeof(TTree)); } else { /* choice (seq tree1 ... choice tree1 true ...) true */ TTree *tree; n = -n; /* size = (choice + seq + tree1 + true) * n, but the last has no seq */ tree = newtree(L, n * (size1 + 3) - 1); for (; n > 1; n--) { /* repeat (n - 1) times */ tree->tag = TChoice; tree->u.ps = n * (size1 + 3) - 2; sib2(tree)->tag = TTrue; tree = sib1(tree); tree = seqaux(tree, tree1, size1); } tree->tag = TChoice; tree->u.ps = size1 + 1; sib2(tree)->tag = TTrue; memcpy(sib1(tree), tree1, size1 * sizeof(TTree)); } copyktable(L, 1); return 1; }
int rx_cmatch(char *rx,char *s,int n) { int p=compile(rx); if(!errors) { char *end=s+n; int u; SKIP_SPACE: for(;;) { if(s==end) return nullable(p); s+=u_get(&u,s); if(!xmlc_white_space(u)) break; } for(;;) { if(p==notAllowed) return 0; if(xmlc_white_space(u)) { u=' '; p=drv(p,u); if(p==notAllowed) { for(;;) { if(s==end) return 1; s+=u_get(&u,s); if(!xmlc_white_space(u)) return 0; } } else goto SKIP_SPACE; } p=drv(p,u); if(s==end) goto SKIP_SPACE; s+=u_get(&u,s); } } else return 0; }
bool TypeConstraint::checkPrimitive(DataType dt) const { assert(m_type.m_dt != KindOfObject); assert(dt != KindOfRef); if (nullable() && IS_NULL_TYPE(dt)) return true; return equivDataTypes(m_type.m_dt, dt); }
/* Parser parsing * create first follow nullable and table then parsing token * finally output parsing tree * */ void Parser:: startParsing(vector<Token*> tokens){ vector<Nonterminal*>::iterator itr; vector<list<string> > starting_Production; list<string> body; //find nullable for( itr = non_terminals.begin(); itr!= non_terminals.end(); ++itr ){ (*itr) -> nullable = nullable( (*itr) -> term ); } // add a production: S -> Program $ Nonterminal* startState = new Nonterminal("S"); startState -> nullable = non_terminals[0] -> nullable; non_terminals.push_back( startState ); body.push_back( non_terminals[0]-> term ); body.push_back( "$" ); starting_Production.push_back(body); grammar.insert( make_pair("S", starting_Production) ); //find first for( itr = non_terminals.begin(); itr!= non_terminals.end(); ++itr ){ if ( (*itr) -> first.empty() ){ (*itr) -> first = first( (*itr) -> term ); } } set<string>:: iterator itr2; //find follow follow(); //output set.txt include nullable first and follow outputSet(); // build Parsing table by if nullalbe is exist for(itr = non_terminals.begin(); itr != non_terminals.end(); ++itr){ if( (*itr)->nullable ){ for(set<string>::iterator follow_itr = (*itr) -> follow.begin(); \ follow_itr != (*itr) -> follow.end(); ++follow_itr ){ if( (*itr)->first.find( (*follow_itr) ) == (*itr)->first.end() ){ map<string, map<string, int> >::iterator non_terminal_find_itr = parsingTable.find( (*itr)-> term ); if ( non_terminal_find_itr == parsingTable.end() ){ //parsingTable.insert( make_pair((*itr), ) ); } else{ non_terminal_find_itr -> second.insert( make_pair(*follow_itr, (*itr)-> production_nullable ) ); } } } } } // output table outputParingTable(); // create Parsing Tree and ouput it createParsingTree(tokens); }
static int drv(int p,int c) { int p1,p2,cf,cl,cn,ret,m; assert(!P_IS(p,P_ERROR)); m=new_memo(p,c); if(m!=-1) return M_RET(m); switch(P_TYP(p)) { case P_NOT_ALLOWED: case P_EMPTY: ret=notAllowed; break; case P_CHOICE: Choice(p,p1,p2); ret=choice(drv(p1,c),drv(p2,c)); break; case P_GROUP: Group(p,p1,p2); {int p11=group(drv(p1,c),p2); ret=nullable(p1)?choice(p11,drv(p2,c)):p11;} break; case P_ONE_OR_MORE: OneOrMore(p,p1); ret=group(drv(p1,c),choice(empty,p)); break; case P_EXCEPT: Except(p,p1,p2); ret=nullable(drv(p1,c))&&!nullable(drv(p2,c))?empty:notAllowed; break; case P_RANGE: Range(p,cf,cl); ret=cf<=c&&c<=cl?empty:notAllowed; break; case P_CLASS: Class(p,cn); ret=in_class(c,cn)?empty:notAllowed; break; case P_ANY: ret=empty; break; case P_CHAR: Char(p,cf); ret=c==cf?empty:notAllowed; break; default: ret=0; assert(0); } new_memo(p,c); M_SET(ret); accept_m(); return ret; }
int nullable(regex *r) { int ind, k = 1; switch(r->type) { case COMPL: return !nullable(r->operands[0]); case KLEENE: return 1; case OR: k = 0; case AND: case CONCAT: for(ind = 0; ind < r->oplen; ++ind) if(nullable(r->operands[ind]) - k) return !k; return k; case SET: return 0; } exit(1); }
int rx_match(char *rx,char *s,int n) { int p=compile(rx); if(!errors) { char *end=s+n; int u; for(;;) { if(p==notAllowed) return 0; if(s==end) return nullable(p); s+=u_get(&u,s); p=drv(p,u); } } else return 0; }
TEST_F(TestCFG, BNF) { auto test = CFG::create(BNF()); ASSERT_NO_THROW(test << "<S> ::= 'a'<A>'b' | ''"); ASSERT_NO_THROW(test << "<A> ::= 'a'<A> | 'b'<A> | ''"); EXPECT_EQ(set({"a", "b"}), test.getTerminals()); EXPECT_EQ(set({"<S>", "<A>"}), test.getNonTerminals()); test.clear(); test << "<S> ::= <S>'s' | <B><C><D>"; test << "<A> ::= <S><A>'a' | ''"; test << "<B> ::= <C>'c'"; test << "<C> ::= <B>'b' | <S>'s' | <A>"; test << "<D> ::= <D>'d' | <D><B> | ''"; ASSERT_EQ(set({"c"}), test.first("<S>")); ASSERT_EQ(set({"c"}), test.first("<A>")); ASSERT_EQ(set({"c"}), test.first("<B>")); ASSERT_EQ(set({"c"}), test.first("<C>")); ASSERT_EQ(set({"c", "d"}), test.first("<D>")); ASSERT_FALSE(test.nullable("<S>")); ASSERT_TRUE(test.nullable("<A>")); ASSERT_FALSE(test.nullable("<B>")); ASSERT_TRUE(test.nullable("<C>")); ASSERT_TRUE(test.nullable("<D>")); }
TEST_F(TestCFG, DidacticNotation) { auto test = CFG::create(DidacticNotation()); ASSERT_NO_THROW(test << "S -> a A b | "); ASSERT_NO_THROW(test << "A -> a A | b A | "); EXPECT_EQ(set({"a", "b"}), test.getTerminals()); EXPECT_EQ(set({"S", "A"}), test.getNonTerminals()); test.clear(); test << "S -> S s | B C D"; test << "A -> S A a | "; test << "B -> C c"; test << "C -> B b | S s | A"; test << "D -> D d | D B | "; ASSERT_EQ(set({"c"}), test.first("S")); ASSERT_EQ(set({"c"}), test.first("A")); ASSERT_EQ(set({"c"}), test.first("B")); ASSERT_EQ(set({"c"}), test.first("C")); ASSERT_EQ(set({"c", "d"}), test.first("D")); ASSERT_FALSE(test.nullable("S")); ASSERT_TRUE(test.nullable("A")); ASSERT_FALSE(test.nullable("B")); ASSERT_TRUE(test.nullable("C")); ASSERT_TRUE(test.nullable("D")); }
/********************************************************************** * * set_pos * * Sets nullable, firstpos and lastpos in whole tree. */ static bool set_pos(void) { REG1 int i; REG2 node_t* tnode = rbuf.tree; for (i = 0; i <= rbuf.root; i++, tnode++) { nullable(tnode); if ((tnode->firstpos = calloc(rbuf.setsize, 1)) == NULL) return FALSE; firstpos(i, tnode); if ((tnode->lastpos = calloc(rbuf.setsize, 1)) == NULL) return FALSE; lastpos(i, tnode); } return TRUE; }
/* ** Check whether a tree has potential infinite loops */ static int checkloops (TTree *tree) { tailcall: if (tree->tag == TRep && nullable(sib1(tree))) return 1; else if (tree->tag == TGrammar) return 0; /* sub-grammars already checked */ else { switch (numsiblings[tree->tag]) { case 1: /* return checkloops(sib1(tree)); */ tree = sib1(tree); goto tailcall; case 2: if (checkloops(sib1(tree))) return 1; /* else return checkloops(sib2(tree)); */ tree = sib2(tree); goto tailcall; default: assert(numsiblings[tree->tag] == 0); return 0; } } }
/* ** Check whether a rule can be left recursive; raise an error in that ** case; otherwise return 1 iff pattern is nullable. ** The return value is used to check sequences, where the second pattern ** is only relevant if the first is nullable. ** Parameter 'nb' works as an accumulator, to allow tail calls in ** choices. ('nb' true makes function returns true.) ** Assume ktable at the top of the stack. */ static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed, int nb) { tailcall: switch (tree->tag) { case TChar: case TSet: case TAny: case TFalse: return nb; /* cannot pass from here */ case TTrue: case TBehind: /* look-behind cannot have calls */ return 1; case TNot: case TAnd: case TRep: /* return verifyrule(L, sib1(tree), passed, npassed, 1); */ tree = sib1(tree); nb = 1; goto tailcall; case TCapture: case TRunTime: /* return verifyrule(L, sib1(tree), passed, npassed, nb); */ tree = sib1(tree); goto tailcall; case TCall: /* return verifyrule(L, sib2(tree), passed, npassed, nb); */ tree = sib2(tree); goto tailcall; case TSeq: /* only check 2nd child if first is nb */ if (!verifyrule(L, sib1(tree), passed, npassed, 0)) return nb; /* else return verifyrule(L, sib2(tree), passed, npassed, nb); */ tree = sib2(tree); goto tailcall; case TChoice: /* must check both children */ nb = verifyrule(L, sib1(tree), passed, npassed, nb); /* return verifyrule(L, sib2(tree), passed, npassed, nb); */ tree = sib2(tree); goto tailcall; case TRule: if (npassed >= MAXRULES) return verifyerror(L, passed, npassed); else { passed[npassed++] = tree->key; /* return verifyrule(L, sib1(tree), passed, npassed); */ tree = sib1(tree); goto tailcall; } case TGrammar: return nullable(tree); /* sub-grammar cannot be left recursive */ default: assert(0); return 0; } }
TupleSchema* TableCatalogDelegate::createTupleSchema(catalog::Table const& catalogTable, bool isXDCR) { // Columns: // Column is stored as map<std::string, Column*> in Catalog. We have to // sort it by Column index to preserve column order. auto numColumns = catalogTable.columns().size(); bool needsDRTimestamp = isXDCR && catalogTable.isDRed(); TupleSchemaBuilder schemaBuilder(numColumns, needsDRTimestamp ? 1 : 0); // number of hidden columns std::map<std::string, catalog::Column*>::const_iterator colIterator; for (colIterator = catalogTable.columns().begin(); colIterator != catalogTable.columns().end(); colIterator++) { auto catalogColumn = colIterator->second; schemaBuilder.setColumnAtIndex(catalogColumn->index(), static_cast<ValueType>(catalogColumn->type()), static_cast<int32_t>(catalogColumn->size()), catalogColumn->nullable(), catalogColumn->inbytes()); } if (needsDRTimestamp) { // Create a hidden timestamp column for a DRed table in an // active-active context. // // Column will be marked as not nullable in TupleSchema, // because we never expect a null value here, but this is not // actually enforced at runtime. schemaBuilder.setHiddenColumnAtIndex(0, VALUE_TYPE_BIGINT, 8, // field size in bytes false); // nulls not allowed } return schemaBuilder.build(); }
/* build nullable * */ bool Parser:: nullable(string term){ map<string, vector<list<string> > >::iterator itr = grammar.find(term); int production_null_index = 0; // record which production produce nullable bool isNullable = true; // iterator each prduction for( vector<list<string> >::iterator itr2 = (itr->second).begin(); itr2 != (itr-> second).end(); ++itr2 ){ // iterator body term for( list<string>::iterator itr3 = (*itr2).begin(); itr3 != (*itr2).end(); ++itr3 ){ // is nullable if( (*itr3).compare("epsilon") == 0 ){ break; } // is a terminal or is a nullable non_terminal else if( isTerminal( (*itr3) ) || !nullable(*itr3) ){ isNullable = false; break; } } if( isNullable ){ // readcord which production produce nullable map<string, Nonterminal*>::iterator non_terminal = non_terminals_map.find(term); non_terminal->second->production_nullable = production_null_index; return true; } // reset and go to next production isNullable = true; production_null_index += 1; } return false; }
static int newGroup(int p1,int p2) {P_newbinop(P_GROUP,p1,p2); setNullable(nullable(p1)&&nullable(p2)); return accept_p();}
static int newChoice(int p1,int p2) {P_newbinop(P_CHOICE,p1,p2); setNullable(nullable(p1)||nullable(p2)); return accept_p();}
static int newOneOrMore(int p1) {P_newunop(P_ONE_OR_MORE,p1); setNullable(nullable(p1)); return accept_p();}
void TypeConstraint::init() { if (UNLIKELY(s_typeNamesToTypes.empty())) { const struct Pair { const StringData* name; Type type; } pairs[] = { { StringData::GetStaticString("bool"), { KindOfBoolean, MetaType::Precise }}, { StringData::GetStaticString("boolean"), { KindOfBoolean, MetaType::Precise }}, { StringData::GetStaticString("int"), { KindOfInt64, MetaType::Precise }}, { StringData::GetStaticString("integer"), { KindOfInt64, MetaType::Precise }}, { StringData::GetStaticString("real"), { KindOfDouble, MetaType::Precise }}, { StringData::GetStaticString("double"), { KindOfDouble, MetaType::Precise }}, { StringData::GetStaticString("float"), { KindOfDouble, MetaType::Precise }}, { StringData::GetStaticString("string"), { KindOfString, MetaType::Precise }}, { StringData::GetStaticString("array"), { KindOfArray, MetaType::Precise }}, { StringData::GetStaticString("resource"), { KindOfResource, MetaType::Precise }}, { StringData::GetStaticString("self"), { KindOfObject, MetaType::Self }}, { StringData::GetStaticString("parent"), { KindOfObject, MetaType::Parent }}, { StringData::GetStaticString("callable"), { KindOfObject, MetaType::Callable }}, }; for (unsigned i = 0; i < sizeof(pairs) / sizeof(Pair); ++i) { s_typeNamesToTypes[pairs[i].name] = pairs[i].type; } } if (m_typeName && isExtended()) { assert(nullable() && "Only nullable extended type hints are implemented"); } if (blacklistedName(m_typeName)) { m_typeName = nullptr; } if (m_typeName == nullptr) { m_type.m_dt = KindOfInvalid; m_type.m_metatype = MetaType::Precise; return; } Type dtype; TRACE(5, "TypeConstraint: this %p type %s, nullable %d\n", this, m_typeName->data(), nullable()); if (!mapGet(s_typeNamesToTypes, m_typeName, &dtype) || !(hhType() || dtype.m_dt == KindOfArray || dtype.isParent() || dtype.isSelf())) { TRACE(5, "TypeConstraint: this %p no such type %s, treating as object\n", this, m_typeName->data()); m_type = { KindOfObject, MetaType::Precise }; m_namedEntity = Unit::GetNamedEntity(m_typeName); TRACE(5, "TypeConstraint: NamedEntity: %p\n", m_namedEntity); return; } m_type = dtype; assert(m_type.m_dt != KindOfStaticString); assert(IMPLIES(isParent(), m_type.m_dt == KindOfObject)); assert(IMPLIES(isSelf(), m_type.m_dt == KindOfObject)); assert(IMPLIES(isCallable(), m_type.m_dt == KindOfObject)); }
bool TypeConstraint::check(const TypedValue* tv, const Func* func) const { assert(hasConstraint()); // This is part of the interpreter runtime; perf matters. if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } if (nullable() && IS_NULL_TYPE(tv->m_type)) return true; if (tv->m_type == KindOfObject) { if (!isObjectOrTypedef()) return false; // Perfect match seems common enough to be worth skipping the hash // table lookup. if (m_typeName->isame(tv->m_data.pobj->getVMClass()->name())) { if (shouldProfile()) Class::profileInstanceOf(m_typeName); return true; } const Class *c = nullptr; const bool selfOrParentOrCallable = isSelf() || isParent() || isCallable(); if (selfOrParentOrCallable) { if (isSelf()) { selfToClass(func, &c); } else if (isParent()) { parentToClass(func, &c); } else { assert(isCallable()); return f_is_callable(tvAsCVarRef(tv)); } } else { // We can't save the Class* since it moves around from request // to request. assert(m_namedEntity); c = Unit::lookupClass(m_namedEntity); } if (shouldProfile() && c) { Class::profileInstanceOf(c->preClass()->name()); } if (c && tv->m_data.pobj->instanceof(c)) { return true; } return !selfOrParentOrCallable && checkTypedefObj(tv); } if (isObjectOrTypedef()) { switch (tv->m_type) { case KindOfArray: if (interface_supports_array(m_typeName)) { return true; } break; case KindOfString: case KindOfStaticString: if (interface_supports_string(m_typeName)) { return true; } break; case KindOfInt64: if (interface_supports_int(m_typeName)) { return true; } break; case KindOfDouble: if (interface_supports_double(m_typeName)) { return true; } break; default: break; } if (isCallable()) { return f_is_callable(tvAsCVarRef(tv)); } return isPrecise() && checkTypedefNonObj(tv); } return equivDataTypes(m_type.m_dt, tv->m_type); }