TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list) { Token tok; auto ps = lex.start_span(); ::std::vector<Type_TraitPath> traits; ::std::vector<AST::LifetimeRef> lifetimes; do { if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { GET_TOK(tok, lex); lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) )); } else { AST::HigherRankedBounds hrbs; if( lex.lookahead(0) == TOK_RWORD_FOR ) { hrbs = Parse_HRB(lex); } traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); } } while( GET_TOK(tok, lex) == TOK_PLUS ); PUTBACK(tok, lex); return TypeRef(lex.end_span(mv$(ps)), TypeData::make_ErasedType({ mv$(traits), mv$(lifetimes) })); }
TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool allow_trait_list) { Token tok; auto ps = lex.start_span(); if( hrbs.empty() && !allow_trait_list ) { return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), Parse_Path(lex, PATH_GENERIC_TYPE)); } else { ::std::vector<Type_TraitPath> traits; ::std::vector<AST::LifetimeRef> lifetimes; traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); if( allow_trait_list ) { while( GET_TOK(tok, lex) == TOK_PLUS ) { if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { GET_TOK(tok, lex); lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) )); } else { if( lex.lookahead(0) == TOK_RWORD_FOR ) { hrbs = Parse_HRB(lex); } traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); } } PUTBACK(tok, lex); } if( !traits[0].hrbs.empty() || traits.size() > 1 || lifetimes.size() > 0 ) { if( lifetimes.empty()) lifetimes.push_back(AST::LifetimeRef()); return TypeRef(lex.end_span(mv$(ps)), mv$(traits), mv$(lifetimes)); } else { return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(traits.at(0).path)); } } }
/// Parse an entire macro_rules! block into a format that exec.cpp can use MacroRulesPtr Parse_MacroRules(TokenStream& lex) { TRACE_FUNCTION_F(""); Token tok; // Parse the patterns and replacements ::std::vector<MacroRule> rules; while( GET_TOK(tok, lex) != TOK_EOF ) { lex.putback(tok); rules.push_back( Parse_MacroRules_Var(lex) ); if(GET_TOK(tok, lex) != TOK_SEMICOLON) { CHECK_TOK(tok, TOK_EOF); break; } } DEBUG("- " << rules.size() << " rules"); ::std::vector<MacroRulesArm> rule_arms; // Re-parse the patterns into a unified form for(auto& rule : rules) { MacroRulesArm arm = MacroRulesArm( mv$(rule.m_pattern), mv$(rule.m_contents) ); enumerate_names(arm.m_pattern, arm.m_param_names); rule_arms.push_back( mv$(arm) ); } auto rv = new MacroRules( ); rv->m_hygiene = lex.getHygiene(); rv->m_rules = mv$(rule_arms); return MacroRulesPtr(rv); }
/// Parse a single arm of a macro_rules! block - `(foo) => (bar)` MacroRule Parse_MacroRules_Var(TokenStream& lex) { TRACE_FUNCTION; Token tok; MacroRule rule; // Pattern enum eTokenType close; switch(GET_TOK(tok, lex)) { case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break; case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break; default: throw ParseError::Unexpected(lex, tok); } // - Pattern entries ::std::vector< ::std::string> names; rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names); GET_CHECK_TOK(tok, lex, TOK_FATARROW); // Replacement switch(GET_TOK(tok, lex)) { case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break; case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break; default: throw ParseError::Unexpected(lex, tok); } rule.m_contents = Parse_MacroRules_Cont(lex, tok.type(), close, names); DEBUG("Rule - ["<<rule.m_pattern<<"] => "<<rule.m_contents<<""); return rule; }
static int _parse (SCAN *scan, int dim, double **buf) { /* --- parse normalization statistics */ int k, n = 0; /* loop variable, counter */ double *p; /* to access the statistics elements */ assert(scan); /* check the function arguments */ if ((sc_token(scan) != T_ID) /* check whether 'scales' follows */ || (strcmp(sc_value(scan), "scales") != 0)) ERR_STR("scales"); /* if not, abort the function */ GET_TOK(); /* consume 'scales' */ GET_CHR('='); /* consume '=' */ for (k = 0; (dim <= 0) || (k < dim); k++) { if (k > 0) { GET_CHR(',');} /* if not first, consume ',' */ if (k >= n) { /* if the statistics vector is full */ if (dim > 0) n = dim; /* compute the new vector size */ else n += (n > BLKSIZE) ? n >> 1 : BLKSIZE; p = (double*)realloc(*buf, (n+n) *sizeof(double)); if (!p) ERROR(E_NOMEM); /* enlarge the buffer vector */ *buf = p; /* and set the new vector, */ } /* then note factor and offset */ p = *buf +k +k; /* get the element to set */ GET_CHR('['); /* consume '[' */ if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP); p[0] = strtod(sc_value(scan), NULL); GET_TOK(); /* consume the offset */ GET_CHR(','); /* consume '[' */ if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP); p[1] = strtod(sc_value(scan), NULL); GET_TOK(); /* consume the factor */ GET_CHR(']'); /* consume '[' */ if ((dim <= 0) && (sc_token(scan) != ',')) { k++; break; } /* check for more scaling params. */ } GET_CHR(';'); /* consume ';' */ return k; /* return 'ok' */ } /* _parse() */
::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override { Token tok; auto lex = TTStream(sp, tt); if( ident != "" ) ERROR(sp, E0000, "asm! doesn't take an ident"); auto template_text = get_string(sp, lex, crate, mod); ::std::vector<::AST::ExprNode_Asm::ValRef> outputs; ::std::vector<::AST::ExprNode_Asm::ValRef> inputs; ::std::vector<::std::string> clobbers; ::std::vector<::std::string> flags; // Outputs if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); while( lex.lookahead(0) == TOK_STRING ) { //auto name = get_string(sp, lex); GET_CHECK_TOK(tok, lex, TOK_STRING); auto name = mv$(tok.str()); GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); auto val = Parse_Expr0(lex); GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); outputs.push_back( ::AST::ExprNode_Asm::ValRef { mv$(name), mv$(val) } ); if( lex.lookahead(0) != TOK_COMMA ) break; GET_TOK(tok, lex); } } else { } // Inputs if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); while( lex.lookahead(0) == TOK_STRING ) { GET_CHECK_TOK(tok, lex, TOK_STRING); auto name = mv$(tok.str()); GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); auto val = Parse_Expr0(lex); GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); inputs.push_back( ::AST::ExprNode_Asm::ValRef { mv$(name), mv$(val) } ); if( lex.lookahead(0) != TOK_COMMA ) break; GET_TOK(tok, lex); } } else { } // Clobbers if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); while( lex.lookahead(0) == TOK_STRING ) { GET_CHECK_TOK(tok, lex, TOK_STRING); clobbers.push_back( mv$(tok.str()) ); if( lex.lookahead(0) != TOK_COMMA ) break; GET_TOK(tok, lex); } } else { } // Flags if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); while( lex.lookahead(0) == TOK_STRING ) { GET_CHECK_TOK(tok, lex, TOK_STRING); flags.push_back( mv$(tok.str()) ); if( lex.lookahead(0) != TOK_COMMA ) break; GET_TOK(tok, lex); } } else { } // trailing `: voltaile` - TODO: Is this valid? if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); if( GET_TOK(tok, lex) == TOK_IDENT && tok.str() == "volatile" ) { flags.push_back( "volatile" ); } else { PUTBACK(tok, lex); } } else { } // has to be the end if( lex.lookahead(0) != TOK_EOF ) { ERROR(sp, E0000, "Unexpected token in asm! - " << lex.getToken()); } // Convert this into an AST node and insert as an intepolated expression ::AST::ExprNodeP rv = ::AST::ExprNodeP( new ::AST::ExprNode_Asm { mv$(template_text), mv$(outputs), mv$(inputs), mv$(clobbers), mv$(flags) } ); return box$( TTStreamO(sp, TokenTree(Token( InterpolatedFragment(InterpolatedFragment::EXPR, rv.release()) )))); }
TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) { //TRACE_FUNCTION; auto ps = lex.start_span(); Token tok; switch( GET_TOK(tok, lex) ) { case TOK_INTERPOLATED_TYPE: return mv$(tok.frag_type()); // '!' - Only ever used as part of function prototypes, but is kinda a type... not allowed here though case TOK_EXCLAM: return TypeRef( Span(tok.get_pos()), TypeData::make_Bang({}) ); // '_' = Wildcard (type inferrence variable) case TOK_UNDERSCORE: return TypeRef(Span(tok.get_pos())); // 'unsafe' - An unsafe function type case TOK_RWORD_UNSAFE: // 'extern' - A function type with an ABI case TOK_RWORD_EXTERN: // 'fn' - Rust function case TOK_RWORD_FN: PUTBACK(tok, lex); return Parse_Type_Fn(lex); case TOK_RWORD_IMPL: return Parse_Type_ErasedType(lex, allow_trait_list); // '<' - An associated type cast case TOK_LT: case TOK_DOUBLE_LT: { PUTBACK(tok, lex); auto path = Parse_Path(lex, PATH_GENERIC_TYPE); return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(path)); } // case TOK_RWORD_FOR: { auto hrls = Parse_HRB(lex); switch(LOOK_AHEAD(lex)) { case TOK_RWORD_UNSAFE: case TOK_RWORD_EXTERN: case TOK_RWORD_FN: return Parse_Type_Fn(lex, hrls); default: return Parse_Type_Path(lex, hrls, true); } } // <ident> - Either a primitive, or a path case TOK_IDENT: if( lex.lookahead(0) == TOK_EXCLAM ) { lex.getToken(); // TODO: path macros return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, mv$(tok.str()), lex)); } // or a primitive //if( auto ct = coretype_fromstring(tok.str()) ) //{ // return TypeRef(TypeRef::TagPrimitive(), Span(tok.get_pos()), ct); //} PUTBACK(tok, lex); return Parse_Type_Path(lex, {}, allow_trait_list); // - Fall through to path handling // '::' - Absolute path case TOK_DOUBLE_COLON: // 'self' - This relative path case TOK_RWORD_SELF: // 'super' - Parent relative path case TOK_RWORD_SUPER: // ':path' fragment case TOK_INTERPOLATED_PATH: PUTBACK(tok, lex); return Parse_Type_Path(lex, {}, allow_trait_list); // HACK! Convert && into & & case TOK_DOUBLE_AMP: lex.putback(Token(TOK_AMP)); // '&' - Reference type case TOK_AMP: { AST::LifetimeRef lifetime; // Reference tok = lex.getToken(); if( tok.type() == TOK_LIFETIME ) { lifetime = AST::LifetimeRef(/*lex.point_span(), */lex.get_ident(::std::move(tok))); tok = lex.getToken(); } bool is_mut = false; if( tok.type() == TOK_RWORD_MUT ) { is_mut = true; } else { PUTBACK(tok, lex); } return TypeRef(TypeRef::TagReference(), lex.end_span(mv$(ps)), ::std::move(lifetime), is_mut, Parse_Type(lex, false)); } // '*' - Raw pointer case TOK_STAR: // Pointer switch( GET_TOK(tok, lex) ) { case TOK_RWORD_MUT: // Mutable pointer return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), true, Parse_Type(lex, false)); case TOK_RWORD_CONST: // Immutable pointer return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), false, Parse_Type(lex, false)); default: throw ParseError::Unexpected(lex, tok, {TOK_RWORD_CONST, TOK_RWORD_MUT}); } throw ParseError::BugCheck("Reached end of Parse_Type:STAR"); // '[' - Array type case TOK_SQUARE_OPEN: { // Array TypeRef inner = Parse_Type(lex); if( GET_TOK(tok, lex) == TOK_SEMICOLON ) { // Sized array AST::Expr array_size = Parse_Expr(lex); GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); return TypeRef(TypeRef::TagSizedArray(), lex.end_span(mv$(ps)), mv$(inner), array_size.take_node()); } else if( tok.type() == TOK_SQUARE_CLOSE ) { return TypeRef(TypeRef::TagUnsizedArray(), lex.end_span(mv$(ps)), mv$(inner)); } else { throw ParseError::Unexpected(lex, tok/*, "; or ]"*/); } } // '(' - Tuple (or lifetime bounded trait) case TOK_PAREN_OPEN: { DEBUG("Tuple"); if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), {}); PUTBACK(tok, lex); TypeRef inner = Parse_Type(lex, true); if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) { // Type in parens, NOT a tuple GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); return inner; } else { ::std::vector<TypeRef> types; types.push_back( mv$(inner) ); while( GET_TOK(tok, lex) == TOK_COMMA ) { if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) break; else PUTBACK(tok, lex); types.push_back( Parse_Type(lex) ); } CHECK_TOK(tok, TOK_PAREN_CLOSE); return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), mv$(types)); } } default: throw ParseError::Unexpected(lex, tok); } throw ParseError::BugCheck("Reached end of Parse_Type"); }
TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs) { auto ps = lex.start_span(); TRACE_FUNCTION; Token tok; ::std::string abi = ""; bool is_unsafe = false; GET_TOK(tok, lex); // `unsafe` if( tok.type() == TOK_RWORD_UNSAFE ) { is_unsafe = true; GET_TOK(tok, lex); } // `exern` if( tok.type() == TOK_RWORD_EXTERN ) { if( GET_TOK(tok, lex) == TOK_STRING ) { abi = tok.str(); if( abi == "" ) ERROR(lex.point_span(), E0000, "Empty ABI"); GET_TOK(tok, lex); } else { abi = "C"; } } // `fn` CHECK_TOK(tok, TOK_RWORD_FN); ::std::vector<TypeRef> args; bool is_variadic = false; GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE ) { if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) { GET_TOK(tok, lex); is_variadic = true; break; } // Handle `ident: ` if( (lex.lookahead(0) == TOK_IDENT || lex.lookahead(0) == TOK_UNDERSCORE) && lex.lookahead(1) == TOK_COLON ) { GET_TOK(tok, lex); GET_TOK(tok, lex); } args.push_back( Parse_Type(lex) ); if( GET_TOK(tok, lex) != TOK_COMMA ) { PUTBACK(tok, lex); break; } } GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); // `-> RetType` TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos())); if( GET_TOK(tok, lex) == TOK_THINARROW ) { ret_type = Parse_Type(lex, false); } else { PUTBACK(tok, lex); } return TypeRef(TypeRef::TagFunction(), lex.end_span(mv$(ps)), mv$(hrbs), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type)); }
/// Parse the pattern of a macro_rules! arm ::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector< ::std::string>& names) { TRACE_FUNCTION; Token tok; ::std::vector<MacroPatEnt> ret; int depth = 0; while( GET_TOK(tok, lex) != close || depth > 0 ) { if( tok.type() == open ) { depth ++; } else if( tok.type() == close ) { if(depth == 0) throw ParseError::Generic(FMT("Unmatched " << Token(close) << " in macro pattern")); depth --; } switch(tok.type()) { case TOK_DOLLAR: switch( GET_TOK(tok, lex) ) { // TODO: Allow any reserved word case TOK_RWORD_TYPE: case TOK_RWORD_PUB: case TOK_IDENT: { ::std::string name = tok.type() == TOK_IDENT ? mv$(tok.str()) : FMT(tok); GET_CHECK_TOK(tok, lex, TOK_COLON); GET_CHECK_TOK(tok, lex, TOK_IDENT); ::std::string type = mv$(tok.str()); unsigned int idx = ::std::find( names.begin(), names.end(), name ) - names.begin(); if( idx == names.size() ) names.push_back( name ); if(0) ; else if( type == "tt" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_TT) ); else if( type == "pat" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_PAT) ); else if( type == "ident" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_IDENT) ); else if( type == "path" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_PATH) ); else if( type == "expr" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_EXPR) ); else if( type == "stmt" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_STMT) ); else if( type == "ty" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_TYPE) ); else if( type == "meta" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_META) ); else if( type == "block" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_BLOCK) ); else if( type == "item" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) ); else ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'"); break; } case TOK_PAREN_OPEN: { auto subpat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names); enum eTokenType joiner = TOK_NULL; GET_TOK(tok, lex); if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR ) { DEBUG("joiner = " << tok); joiner = tok.type(); GET_TOK(tok, lex); } DEBUG("tok = " << tok); switch(tok.type()) { case TOK_PLUS: DEBUG("$()+ " << subpat); ret.push_back( MacroPatEnt(Token(joiner), true, ::std::move(subpat)) ); break; case TOK_STAR: DEBUG("$()* " << subpat); ret.push_back( MacroPatEnt(Token(joiner), false, ::std::move(subpat)) ); break; default: throw ParseError::Unexpected(lex, tok); } break; } default: throw ParseError::Unexpected(lex, tok); } break; case TOK_EOF: throw ParseError::Unexpected(lex, tok); default: ret.push_back( MacroPatEnt(tok) ); break; } } return ret; }
/// Parse the contents (replacement) of a macro_rules! arm ::std::vector<MacroExpansionEnt> Parse_MacroRules_Cont( TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector< ::std::string>& var_names, ::std::map<unsigned int,bool>* var_set_ptr=nullptr ) { TRACE_FUNCTION; Token tok; ::std::vector<MacroExpansionEnt> ret; int depth = 0; while( GET_TOK(tok, lex) != close || depth > 0 ) { if( tok.type() == TOK_EOF ) { throw ParseError::Unexpected(lex, tok); } if( tok.type() == TOK_NULL ) continue ; if( tok.type() == open ) { DEBUG("depth++"); depth ++; } else if( tok.type() == close ) { DEBUG("depth--"); if(depth == 0) ERROR(lex.point_span(), E0000, "Unmatched " << Token(close) << " in macro content"); depth --; } // `$` - Macro metavars if( tok.type() == TOK_DOLLAR ) { GET_TOK(tok, lex); // `$(` if( tok.type() == TOK_PAREN_OPEN ) { ::std::map<unsigned int, bool> var_set; auto content = Parse_MacroRules_Cont(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, var_names, &var_set); // ^^ The above will eat the PAREN_CLOSE GET_TOK(tok, lex); enum eTokenType joiner = TOK_NULL; if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR ) { joiner = tok.type(); GET_TOK(tok, lex); } bool is_optional = (tok.type() == TOK_STAR); if( var_set_ptr ) { for(const auto& v : var_set) { // If `is_optional`: Loop may not be expanded, so var_not_opt=false // Else, inherit bool var_not_opt = (is_optional ? false : v.second); var_set_ptr->insert( ::std::make_pair(v.first, var_not_opt) ).first->second |= var_not_opt; } } DEBUG("joiner = " << Token(joiner) << ", content = " << content); switch(tok.type()) { case TOK_PLUS: case TOK_STAR: // TODO: Ensure that +/* match up? ret.push_back( MacroExpansionEnt({mv$(content), joiner, mv$(var_set)}) ); break; default: throw ParseError::Unexpected(lex, tok); } } //else if( tok.type() == TOK_IDENT || tok_is_rword(tok.type()) ) else if( tok.type() == TOK_IDENT || tok.type() == TOK_RWORD_TYPE || tok.type() == TOK_RWORD_PUB ) { // Look up the named parameter in the list of param names for this arm auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok); unsigned int idx = ::std::find(var_names.begin(), var_names.end(), name) - var_names.begin(); if( idx == var_names.size() ) { // TODO: `error-chain`'s quick_error macro has an arm which refers to an undefined metavar. // - Maybe emit a warning and use a marker index. WARNING(lex.point_span(), W0000, "Macro variable $" << name << " not found"); // Emit the literal $ <name> ret.push_back( MacroExpansionEnt(Token(TOK_DOLLAR)) ); ret.push_back( MacroExpansionEnt(mv$(tok)) ); continue ; } if( var_set_ptr ) { var_set_ptr->insert( ::std::make_pair(idx,true) ); } ret.push_back( MacroExpansionEnt(idx) ); } else if( tok.type() == TOK_RWORD_CRATE ) { ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) ); } else { throw ParseError::Unexpected(lex, tok); } } else { ret.push_back( MacroExpansionEnt( mv$(tok) ) ); } } return ret; }
static int _domains (ATTSET *set, SCAN *scan, int tflags) { /* --- parse attribute domains */ ATT *att; /* attribute read */ int type; /* attribute type */ int t; /* temporary buffer */ double wgt; /* buffer for attribute weight */ const char *v; /* token value */ while ((sc_token(scan) == T_ID) /* parse domain definitions */ && ((strcmp(sc_value(scan), "dom") == 0) || (strcmp(sc_value(scan), "domain") == 0))) { GET_TOK(); /* consume 'dom' */ GET_CHR('('); /* consume '(' */ t = sc_token(scan); /* check next token for a valid name */ if ((t != T_ID) && (t != T_NUM)) ERROR(E_ATTEXP); att = att_create(sc_value(scan), AT_NOM); if (!att) ERROR(E_NOMEM); /* create an attribute and */ t = as_attadd(set, att); /* add it to the attribute set */ if (t) { att_delete(att); ERROR((t > 0) ? E_DUPATT : E_NOMEM); } GET_TOK(); /* consume attribute name */ GET_CHR(')'); /* consume ')' */ GET_CHR('='); /* consume '=' */ type = -1; /* init. attribute type to 'none' */ t = sc_token(scan); /* test next token */ if (t == '{') /* if a set of values follows, */ type = tflags & AT_NOM; /* attribute is nominal */ else if (t == T_ID) { /* if an identifier follows */ v = sc_value(scan); /* get it for simpler comparisons */ if ((strcmp(v, "ZZ") == 0) || (strcmp(v, "Z") == 0) || (strcmp(v, "int") == 0) || (strcmp(v, "integer") == 0)) type = tflags & AT_INT; /* attribute is integer-valued */ else if ((strcmp(v, "IR") == 0) || (strcmp(v, "R") == 0) || (strcmp(v, "real") == 0) || (strcmp(v, "float") == 0)) type = tflags & AT_REAL;/* attribute is real-valued */ } /* (get and check attribute type) */ if (type <= 0) ERROR(E_DOMAIN); att->type = type; /* set attribute type */ if (type != AT_NOM) { /* if attribute is numeric */ GET_TOK(); /* consume type indicator */ if (type == AT_INT) { /* if attribute is integer-valued */ att->min.i = INT_MAX; /* initialize minimal */ att->max.i = -INT_MAX;} /* and maximal value */ else { /* if attribute is real-valued */ att->min.f = FLT_MAX; /* initialize minimal */ att->max.f = -FLT_MAX; /* and maximal value */ } if (sc_token(scan) == '[') { /* if a range of values is given */ GET_TOK(); /* consume '[' */ if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP); if (att_valadd(att, sc_value(scan), NULL) != 0) ERROR(E_NUMBER); /* get and check lower bound */ GET_TOK(); /* consume lower bound */ GET_CHR(','); /* consume ',' */ if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP); if (att_valadd(att, sc_value(scan), NULL) != 0) ERROR(E_NUMBER); /* get and check upper bound */ GET_TOK(); /* consume upper bound */ GET_CHR(']'); /* consume ']' */ } } else { /* if attribute is nominal */ GET_CHR('{'); /* consume '{' */ if (sc_token(scan) != '}') { while (1) { /* read a list of values */ t = sc_token(scan); /* check for a name */ if ((t != T_ID) && (t != T_NUM)) ERROR(E_VALEXP); t = att_valadd(att, sc_value(scan), NULL); if (t) ERROR((t > 0) ? E_DUPVAL : E_NOMEM); GET_TOK(); /* get and consume attribute value */ if (sc_token(scan) != ',') break; GET_TOK(); /* if at end of list, abort loop, */ } /* otherwise consume ',' */ } GET_CHR('}'); /* consume '}' */ } if (sc_token(scan) == ':'){ /* if a direction indication follows */ GET_TOK(); /* consume ',' */ if (sc_token(scan) != T_ID) ERR_STR("in"); v = sc_value(scan); /* get the direction indicator */ if (strcmp(v, "none") == 0) att->dir = DIR_NONE; else if (strcmp(v, "in") == 0) att->dir = DIR_IN; else if (strcmp(v, "out") == 0) att->dir = DIR_OUT; else if (strcmp(v, "id") == 0) att->dir = DIR_ID; else if (strcmp(v, "wgt") == 0) att->dir = DIR_WGT; else ERR_STR("in"); /* get the direction code */ GET_TOK(); /* and consume the token */ } if (sc_token(scan) == ','){ /* if a weight indication follows */ if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP); wgt = atof(sc_value(scan)); /* get the attribute weight */ if ((wgt <= NV_REAL) || (wgt > FLT_MAX)) ERROR(E_NUMBER); att->weight = (float)wgt; /* check and set attribute weight */ GET_TOK(); /* and consume the token */ } GET_CHR(';'); /* consume ';' */ } /* while ((sc_token(scan) == T_ID) .. */ return 0; /* return 'ok' */ } /* _domains() */