+static
+void eat_whitespace()
+{
+ while(1) {
+ switch(c) {
+ case ' ':
+ case '\t':
+ next_char();
+ break;
+
+ case '\r':
+ case '\n':
+ return;
+
+ case '\\':
+ next_char();
+ if(c == '\n') {
+ next_char();
+ source_position.linenr++;
+ break;
+ }
+
+ put_back(c);
+ c = '\\';
+ return;
+
+ SKIP_TRIGRAPHS(,
+ return;
+ )
+
+ case '/':
+ next_char();
+ while(1) {
+ switch(c) {
+ case '*':
+ next_char();
+ skip_multiline_comment();
+ eat_whitespace();
+ return;
+ case '/':
+ next_char();
+ skip_line_comment();
+ eat_whitespace();
+ return;
+
+ SKIP_TRIGRAPHS(
+ put_back('?');
+ ,
+ c = '/';
+ return;
+ )
+
+ case '\\':
+ next_char();
+ EAT_NEWLINE(break;)
+ /* fallthrough */
+ default:
+ return;
+ }
+ }
+ break;
+
+ default:
+ return;
+ }
+ }
+}
+
+static
+void lexer_next_preprocessing_token(token_t *token)
+{
+ while(1) {
+ switch(c) {
+ case ' ':
+ case '\t':
+ next_char();
+ break;
+
+ MATCH_NEWLINE(
+ eat_whitespace();
+ if(c == '#') {
+ next_char();
+ parse_preprocessor_directive(token);
+ return;
+ }
+ token->type = '\n';
+ return;
+ )
+
+ SYMBOL_CHARS
+ parse_symbol(token);
+ return;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ parse_number(token);
+ return;
+
+ case '"':
+ parse_string_literal(token);
+ return;
+
+ case '\'':
+ parse_character_constant(token);
+ return;
+
+ case '\\':
+ next_char();
+ if(c == '\n') {
+ next_char();
+ source_position.linenr++;
+ break;
+ } else {
+ parse_error("unexpected '\\' found");
+ token->type = T_ERROR;
+ }
+ return;
+