+
+void print_pp_token_kind(FILE *f, int token_kind)
+{
+ if (token_kind == TP_EOF) {
+ fputs("end of file", f);
+ return;
+ }
+ if (token_kind == TP_ERROR) {
+ fputs("error", f);
+ return;
+ }
+
+ int token_symbols_len = TP_LAST_TOKEN;
+ if (token_kind < 0 || token_kind >= token_symbols_len) {
+ fputs("invalid token", f);
+ return;
+ }
+
+ const symbol_t *symbol = pp_token_symbols[token_kind];
+ if (symbol != NULL) {
+ fputs(symbol->string, f);
+ } else {
+ if(token_kind >= 0 && token_kind < 256) {
+ fputc(token_kind, f);
+ return;
+ }
+ fputs("unknown token", f);
+ }
+}
+
+void print_pp_token(FILE *f, const token_t *token)
+{
+ switch((preprocessor_token_kind_t) token->kind) {
+ case TP_IDENTIFIER:
+ fprintf(f, "identifier '%s'", token->identifier.symbol->string);
+ break;
+ case TP_NUMBER:
+ fprintf(f, "number '%s'", token->number.number.begin);
+ break;
+ case TP_STRING_LITERAL:
+ fprintf(f, "string \"%s\"", token->string.string.begin);
+ break;
+ default:
+ print_pp_token_kind(f, (preprocessor_token_kind_t) token->kind);
+ break;
+ }
+}
+
+bool tokens_would_paste(preprocessor_token_kind_t token1,
+ preprocessor_token_kind_t token2)
+{
+ char c = token2 < 256 ? (char) token2 : pp_token_symbols[token2]->string[0];
+
+ switch (token1) {
+ case '>': return c == '>' || c == '=';
+ case '<': return c == '<' || c == '=' || c == '%' || c == ':';
+ case '+': return c == '+' || c == '=';
+ case '-': return c == '-' || c == '>';
+ case '/': return c == '/' || c == '=' || c == '*';
+ case '%': return c == ':' || c == '=' || c == '>';
+ case '&': return c == '&' || c == '=';
+ case '|': return c == '|' || c == '=';
+ case ':': return c == ':' || c == '>';
+ case '*': return c == '*' || c == '=';
+ case '.': return c == '.' || c == '%' || token2 == TP_NUMBER;
+ case '#': return c == '#' || c == '%';
+ case TP_GREATERGREATER: return c == '=';
+ case TP_LESSLESS: return c == '=';
+ case '^': return c == '=';
+ case '!': return c == '=';
+ case TP_IDENTIFIER:
+ return token2 == TP_IDENTIFIER || token2 == TP_NUMBER ||
+ token2 == TP_CHARACTER_CONSTANT ||
+ token2 == TP_WIDE_CHARACTER_CONSTANT ||
+ token2 == TP_WIDE_STRING_LITERAL ||
+ token2 == TP_STRING_LITERAL; /* L */
+ case TP_NUMBER:
+ return token2 == TP_NUMBER || token2 == TP_IDENTIFIER ||
+ token2 == '.' || token2 == '+' || token2 == '-';
+ default:
+ return false;
+ }
+}