/* Returns nonzero if a space should be inserted to avoid an accidental token paste for output. For simplicity, it is conservative, and occasionally advises a space where one is not needed, e.g. "." and ".2". */ int cpp_avoid_paste (cpp_reader *pfile, const cpp_token *token1, const cpp_token *token2) { enum cpp_ttype a = token1->type, b = token2->type; cppchar_t c; if (token1->flags & NAMED_OP) a = CPP_NAME; if (token2->flags & NAMED_OP) b = CPP_NAME; c = EOF; if (token2->flags & DIGRAPH) c = digraph_spellings[(int) b - (int) CPP_FIRST_DIGRAPH][0]; else if (token_spellings[b].category == SPELL_OPERATOR) c = token_spellings[b].name[0]; /* Quickly get everything that can paste with an '='. */ if ((int) a <= (int) CPP_LAST_EQ && c == '=') return 1; switch (a) { case CPP_GREATER: return c == '>' || c == '?'; case CPP_LESS: return c == '<' || c == '?' || c == '%' || c == ':'; case CPP_PLUS: return c == '+'; case CPP_MINUS: return c == '-' || c == '>'; case CPP_DIV: return c == '/' || c == '*'; /* Comments. */ case CPP_MOD: return c == ':' || c == '>'; case CPP_AND: return c == '&'; case CPP_OR: return c == '|'; case CPP_COLON: return c == ':' || c == '>'; case CPP_DEREF: return c == '*'; case CPP_DOT: return c == '.' || c == '%' || b == CPP_NUMBER; case CPP_HASH: return c == '#' || c == '%'; /* Digraph form. */ case CPP_NAME: return ((b == CPP_NUMBER && name_p (pfile, &token2->val.str)) || b == CPP_NAME || b == CPP_CHAR || b == CPP_STRING); /* L */ case CPP_NUMBER: return (b == CPP_NUMBER || b == CPP_NAME || c == '.' || c == '+' || c == '-'); /* UCNs */ case CPP_OTHER: return ((token1->val.str.text[0] == '\\' && b == CPP_NAME) || (CPP_OPTION (pfile, objc) && token1->val.str.text[0] == '@' && (b == CPP_NAME || b == CPP_STRING))); default: break; } return 0; }
static void logo_Lexer_advance(logo_Lexer *self) { #define opv(_name, _value) do { self->token = (logo_Token) { .type = logo_Token_ ## _name, .value = _value, .start = start, .end = logo_Stream_position(self->stream) }; return; } while (0) #define op(_name) opv(_name, NULL) long start = logo_Stream_position(self->stream); int c = logo_Stream_next(self->stream); bool whitespace = false; trim: if (whitespace_p(c) || ((self->list_level || self->in_proc) && newline_p(c))) { start = logo_Stream_position(self->stream); c = logo_Stream_next(self->stream); whitespace = true; goto trim; } if (c == '#') { if (logo_Stream_next(self->stream) == '!') { do { c = logo_Stream_next(self->stream); } while (!newline_p(c) && c != logo_Stream_END); start = logo_Stream_position(self->stream) - 1; goto trim; } logo_Stream_skip(self->stream, -1); } if (c == ';' && self->list_level == 0) { do { c = logo_Stream_next(self->stream); } while (!newline_p(c) && c != logo_Stream_END); start = logo_Stream_position(self->stream) - 1; goto trim; } switch (c) { case logo_Stream_END: op(END); case '[': ++self->list_level; op(LBRACKET); case ']': if (self->list_level > 0) --self->list_level; op(RBRACKET); } if (newline_p(c)) { do { c = logo_Stream_next(self->stream); } while (newline_p(c)); logo_Stream_skip(self->stream, -1); op(NEWLINE); } if (self->list_level || self->in_proc) { size_t size = 0; do { ++size; c = logo_Stream_next(self->stream); } while (lword_p(c)); logo_Stream_skip(self->stream, -size - 1); char *s = malloc(size + 1), *p; for (p = s; p < s + size; ++p) { *p = logo_Stream_next(self->stream); } *p = 0; if (self->in_proc && strcmp(s, "end") == 0) { free(s); op(PROCEND); } opv(WORD, s); } switch (c) { case '(': op(LPAREN); case ')': op(RPAREN); case ':': op(COLON); case '?': op(QUESTION); case '+': op(ADD); case '-': if (whitespace && !whitespace_p(logo_Stream_peek(self->stream))) { op(INVERSE); } op(SUB); case '*': op(MUL); case '/': op(DIV); case '=': op(EQUAL); case '>': if (logo_Stream_peek(self->stream) == '=') { logo_Stream_next(self->stream); op(GTE); } op(GT); case '<': if (logo_Stream_peek(self->stream) == '=') { logo_Stream_next(self->stream); op(LTE); } if (logo_Stream_peek(self->stream) == '>') { logo_Stream_next(self->stream); op(NOTEQUAL); } op(LT); } if (c == '"') { size_t size = 0; c = logo_Stream_next(self->stream); while (word_p(c)) { ++size; c = logo_Stream_next(self->stream); } logo_Stream_skip(self->stream, -size - 1); char *s = malloc(size + 1), *p; for (p = s; p < s + size; ++p) { *p = logo_Stream_next(self->stream); } *p = 0; opv(WORD, s); } if (digit_p(c)) { size_t size = 0; #define next do { ++size; c = logo_Stream_next(self->stream); } while (0) do { do next; while (digit_p(c)); if (c == '.') { next; if (!digit_p(c)) break; do next; while (digit_p(c)); } if (c == 'e' || c == 'E') { next; if (c == '+' || c == '-') next; if (!digit_p(c)) break; do next; while (digit_p(c)); } if (name_p(c)) break; logo_Stream_skip(self->stream, -size - 1); char *s = malloc(size + 1), *p; for (p = s; p < s + size; ++p) { *p = logo_Stream_next(self->stream); } *p = 0; opv(NUMBER, s); } while (false); #undef next logo_Stream_skip(self->stream, -size - 1); c = logo_Stream_next(self->stream); } if (name_p(c)) { size_t size = 0; do { ++size; c = logo_Stream_next(self->stream); } while (name_p(c)); logo_Stream_skip(self->stream, -size - 1); char *s = malloc(size), *p; for (p = s; p < s + size; ++p) { *p = logo_Stream_next(self->stream); } *p = 0; opv(NAME, s); } #undef op }