double expression(TokenStream& tokenStream) { double result = term(tokenStream); // set result to value of term Token token = tokenStream.getToken(); // get next token from tokenStream while (true) { if (token.kind == '+') { result += term(tokenStream); // evaluate term and add to result token = tokenStream.getToken(); // get next token from tokenStream } if (token.kind == '-') { result -= term(tokenStream); // evaluate term and subtract from result token = tokenStream.getToken(); // get next token from tokenStream } if (token.kind != '+' && token.kind != '-') { tokenStream.setToken(token); // reset token into token stream return result; // return result } } }
void calculate() { const char quit = 'q'; // t.kind==quit means that t is a quit Token const char print = ';'; // t.kind==print means that t is a print Token const std::string prompt = "> "; const std::string equals = "= "; // used to indicate that what follows is an evaluation TokenStream tokenStream; std::string enterToClose = "~~"; while (std::cin) try { std::cout << prompt; Token token = tokenStream.getToken(); if (token.kind == print) token = tokenStream.getToken(); // eat ';' if (token.kind == quit) break; tokenStream.setToken(token); // reset token into tokenStream std::cout << equals << expression(tokenStream) << '\n'; } catch (std::exception& e) { std::cerr << e.what() << '\n'; // write error message tokenStream.ignore(print); } }
double primary(TokenStream& tokenStream) { const char number = '8'; Token token = tokenStream.getToken(); if (token.kind == '-') return -primary(tokenStream); else if (token.kind == '+') return primary(tokenStream); else if (token.kind == number) return token.value; // return the number’s value else if (token.kind == '(') // handle ‘(‘ expression ‘)’ { double result = expression(tokenStream); // set result to value of expression token = tokenStream.getToken(); // get next token from tokenStream if (token.kind != ')') error("')' expected"); // check for error return result; // return divisor } else // check for error error("primary expected"); }
double term(TokenStream& tokenStream) { double result = primary(tokenStream); // set result to value of primary Token token = tokenStream.getToken(); // get next token from tokenStream while (true) { if (token.kind == '*') { result *= primary(tokenStream); // evaluate primary and multiply with result token = tokenStream.getToken(); // get next token from tokenStream } else if (token.kind == '/') { double divisor = primary(tokenStream); // set divisor to value of primary if (divisor == 0) error("divide by zero"); // check for error result /= divisor; // divide result by divisor token = tokenStream.getToken(); // get next token from tokenStream } else if (token.kind == '%') // modulo will only work on ints for this implementation { int numer = result; // cast result to int int denom = primary(tokenStream); // cast denom to int if (denom == 0) error("%: divide by zero"); // error check result = numer % denom; // get result token = tokenStream.getToken(); // get next token from tokenStream } else { tokenStream.setToken(token); // put token back into the Token stream return result; // return result } } }
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"); }