+ symbol_t *symbol = pp_token.identifier.symbol;
+ if (symbol->pp_ID == TP_STDC) {
+ stdc_pragma_kind_t kind = STDC_UNKNOWN;
+ /* a STDC pragma */
+ if (c_mode & _C99) {
+ next_pp_token();
+
+ switch (pp_token.identifier.symbol->pp_ID) {
+ case TP_FP_CONTRACT:
+ kind = STDC_FP_CONTRACT;
+ break;
+ case TP_FENV_ACCESS:
+ kind = STDC_FENV_ACCESS;
+ break;
+ case TP_CX_LIMITED_RANGE:
+ kind = STDC_CX_LIMITED_RANGE;
+ break;
+ default:
+ break;
+ }
+ if (kind != STDC_UNKNOWN) {
+ stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
+ next_pp_token();
+ switch (pp_token.identifier.symbol->pp_ID) {
+ case TP_ON:
+ value = STDC_VALUE_ON;
+ break;
+ case TP_OFF:
+ value = STDC_VALUE_OFF;
+ break;
+ case TP_DEFAULT:
+ value = STDC_VALUE_DEFAULT;
+ break;
+ default:
+ break;
+ }
+ if (value != STDC_VALUE_UNKNOWN) {
+ unknown_pragma = false;
+ } else {
+ errorf(&pp_token.base.source_position,
+ "bad STDC pragma argument");
+ }
+ }
+ }
+ } else {
+ unknown_pragma = true;
+ }
+ eat_until_newline();
+ if (unknown_pragma) {
+ warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.source_position,
+ "encountered unknown #pragma");
+ }
+}
+
+/**
+ * Parse a preprocessor non-null directive.
+ */
+static void parse_preprocessor_identifier(void)
+{
+ assert(pp_token.kind == T_IDENTIFIER);
+ symbol_t *symbol = pp_token.identifier.symbol;
+
+ switch (symbol->pp_ID) {
+ case TP_line:
+ next_pp_token();
+ parse_line_directive();
+ break;
+ case TP_pragma:
+ parse_pragma();
+ break;
+ case TP_error:
+ /* TODO; output the rest of the line */
+ parse_error("#error directive");
+ break;
+ }
+}
+
+/**
+ * Parse a preprocessor directive.
+ */
+static void parse_preprocessor_directive(void)
+{
+ next_pp_token();
+
+ switch (pp_token.kind) {
+ case T_IDENTIFIER:
+ parse_preprocessor_identifier();
+ break;
+ case T_INTEGER:
+ parse_line_directive();
+ break;
+ case '\n':
+ /* NULL directive, see §6.10.7 */
+ break;
+ default:
+ parse_error("invalid preprocessor directive");
+ eat_until_newline();
+ break;