struct obstack ast_obstack;
static int indent;
+static int case_indent;
bool print_implicit_casts = false;
bool print_parenthesis = false;
void print_indent(void)
{
for (int i = 0; i < indent; ++i)
- print_string("\t");
-}
-
-static void print_symbol(const symbol_t *symbol)
-{
- print_string(symbol->string);
+ print_char('\t');
}
static void print_stringrep(const string_t *string)
static unsigned get_expression_precedence(expression_kind_t kind)
{
static const unsigned prec[] = {
- [EXPR_UNKNOWN] = PREC_PRIMARY,
- [EXPR_INVALID] = PREC_PRIMARY,
[EXPR_REFERENCE] = PREC_PRIMARY,
[EXPR_REFERENCE_ENUM_VALUE] = PREC_PRIMARY,
[EXPR_LITERAL_INTEGER] = PREC_PRIMARY,
[EXPR_UNARY_PREFIX_INCREMENT] = PREC_UNARY,
[EXPR_UNARY_PREFIX_DECREMENT] = PREC_UNARY,
[EXPR_UNARY_CAST] = PREC_UNARY,
- [EXPR_UNARY_CAST_IMPLICIT] = PREC_UNARY,
[EXPR_UNARY_ASSUME] = PREC_PRIMARY,
[EXPR_UNARY_DELETE] = PREC_UNARY,
[EXPR_UNARY_DELETE_ARRAY] = PREC_UNARY,
for (const char *c = string->begin; c != end; ++c) {
const char tc = *c;
if (tc == border) {
- print_string("\\");
+ print_char('\\');
}
switch (tc) {
case '\\': print_string("\\\\"); break;
case EXPR_LITERAL_INTEGER_OCTAL:
case EXPR_LITERAL_FLOATINGPOINT:
print_stringrep(&literal->value);
- if (literal->suffix != NULL)
- print_symbol(literal->suffix);
+ if (literal->suffix.size > 0)
+ print_stringrep(&literal->suffix);
return;
case EXPR_LITERAL_WIDE_CHARACTER:
print_char('L');
static void print_compound_literal(
const compound_literal_expression_t *expression)
{
- print_string("(");
+ print_char('(');
print_type(expression->type);
- print_string(")");
+ print_char(')');
print_initializer(expression->initializer);
}
static void print_call_expression(const call_expression_t *call)
{
print_expression_prec(call->function, PREC_POSTFIX);
- print_string("(");
+ print_char('(');
call_argument_t *argument = call->arguments;
int first = 1;
while (argument != NULL) {
argument = argument->next;
}
- print_string(")");
+ print_char(')');
}
/**
{
unsigned prec = get_expression_precedence(unexpr->base.kind);
switch (unexpr->base.kind) {
- case EXPR_UNARY_NEGATE: print_string("-"); break;
- case EXPR_UNARY_PLUS: print_string("+"); break;
- case EXPR_UNARY_NOT: print_string("!"); break;
- case EXPR_UNARY_BITWISE_NEGATE: print_string("~"); break;
+ case EXPR_UNARY_NEGATE: print_char ('-' ); break;
+ case EXPR_UNARY_PLUS: print_char ('+' ); break;
+ case EXPR_UNARY_NOT: print_char ('!' ); break;
+ case EXPR_UNARY_BITWISE_NEGATE: print_char ('~' ); break;
case EXPR_UNARY_PREFIX_INCREMENT: print_string("++"); break;
case EXPR_UNARY_PREFIX_DECREMENT: print_string("--"); break;
- case EXPR_UNARY_DEREFERENCE: print_string("*"); break;
- case EXPR_UNARY_TAKE_ADDRESS: print_string("&"); break;
+ case EXPR_UNARY_DEREFERENCE: print_char ('*' ); break;
+ case EXPR_UNARY_TAKE_ADDRESS: print_char ('&' ); break;
case EXPR_UNARY_DELETE: print_string("delete "); break;
case EXPR_UNARY_DELETE_ARRAY: print_string("delete [] "); break;
print_expression_prec(unexpr->value, prec);
print_string("--");
return;
- case EXPR_UNARY_CAST_IMPLICIT:
case EXPR_UNARY_CAST:
- print_string("(");
+ print_char('(');
print_type(unexpr->base.type);
- print_string(")");
+ print_char(')');
break;
case EXPR_UNARY_ASSUME:
print_string("__assume(");
print_assignment_expression(unexpr->value);
- print_string(")");
+ print_char(')');
return;
case EXPR_UNARY_THROW:
{
if (!expression->flipped) {
print_expression_prec(expression->array_ref, PREC_POSTFIX);
- print_string("[");
+ print_char('[');
print_expression(expression->index);
- print_string("]");
+ print_char(']');
} else {
print_expression_prec(expression->index, PREC_POSTFIX);
- print_string("[");
+ print_char('[');
print_expression(expression->array_ref);
- print_string("]");
+ print_char(']');
}
}
/* PREC_TOP: always print the '()' here, sizeof x is right but unusual */
print_expression_prec(expression->tp_expression, PREC_TOP);
} else {
- print_string("(");
+ print_char('(');
print_type(expression->type);
- print_string(")");
+ print_char(')');
}
}
{
print_string("__builtin_constant_p(");
print_assignment_expression(expression->value);
- print_string(")");
+ print_char(')');
}
/**
print_type(expression->left);
print_string(", ");
print_type(expression->right);
- print_string(")");
+ print_char(')');
}
/**
print_assignment_expression(expression->ap);
print_string(", ");
print_string(expression->parameter->base.base.symbol->string);
- print_string(")");
+ print_char(')');
}
/**
print_assignment_expression(expression->ap);
print_string(", ");
print_type(expression->base.type);
- print_string(")");
+ print_char(')');
}
/**
print_assignment_expression(expression->dst);
print_string(", ");
print_assignment_expression(expression->src);
- print_string(")");
+ print_char(')');
}
/**
static void print_select(const select_expression_t *expression)
{
print_expression_prec(expression->compound, PREC_POSTFIX);
+ /* do not print anything for anonymous struct/union selects
+ * FIXME: if the anonymous select was a '->' this will print '.'
+ */
+ if (expression->compound_entry->base.symbol == NULL)
+ return;
+
if (is_type_pointer(skip_typeref(expression->compound->base.type))) {
print_string("->");
} else {
- print_string(".");
+ print_char('.');
}
print_string(expression->compound_entry->base.symbol->string);
}
{
print_string("__builtin_classify_type(");
print_assignment_expression(expr->type_expression);
- print_string(")");
+ print_char(')');
}
/**
{
for ( ; designator != NULL; designator = designator->next) {
if (designator->symbol == NULL) {
- print_string("[");
+ print_char('[');
print_expression(designator->array_index);
- print_string("]");
+ print_char(']');
} else {
- print_string(".");
+ print_char('.');
print_string(designator->symbol->string);
}
}
{
print_string("__builtin_offsetof(");
print_type(expression->type);
- print_string(",");
+ print_char(',');
print_designator(expression->designator);
- print_string(")");
+ print_char(')');
}
/**
*/
static void print_statement_expression(const statement_expression_t *expression)
{
- print_string("(");
+ print_char('(');
print_statement(expression->statement);
- print_string(")");
+ print_char(')');
}
/**
*/
static void print_expression_prec(const expression_t *expression, unsigned top_prec)
{
- if (expression->kind == EXPR_UNARY_CAST_IMPLICIT && !print_implicit_casts) {
+ if (expression->kind == EXPR_UNARY_CAST
+ && expression->base.implicit && !print_implicit_casts) {
expression = expression->unary.value;
}
top_prec > get_expression_precedence(expression->base.kind);
if (parenthesized)
- print_string("(");
+ print_char('(');
switch (expression->kind) {
- case EXPR_UNKNOWN:
- case EXPR_INVALID:
- print_string("$invalid expression$");
+ case EXPR_ERROR:
+ print_string("$error$");
break;
case EXPR_WIDE_STRING_LITERAL:
case EXPR_STRING_LITERAL:
case EXPR_STATEMENT:
print_statement_expression(&expression->statement);
break;
+ }
+ if (parenthesized)
+ print_char(')');
+}
+
+static void print_indented_statement(statement_t const *const stmt)
+{
+ switch (stmt->kind) {
+ case STATEMENT_LABEL:
+ break;
+
+ case STATEMENT_CASE_LABEL:
+ for (int i = 0; i != case_indent; ++i)
+ print_char('\t');
+ break;
-#if 0
default:
- /* TODO */
- print_format("some expression of type %d", (int)expression->kind);
+ print_indent();
break;
-#endif
}
- if (parenthesized)
- print_string(")");
+ print_statement(stmt);
}
/**
statement_t *statement = block->statements;
while (statement != NULL) {
- if (statement->base.kind == STATEMENT_CASE_LABEL)
- --indent;
- if (statement->kind != STATEMENT_LABEL)
- print_indent();
- print_statement(statement);
+ print_indented_statement(statement);
+ print_char('\n');
statement = statement->base.next;
}
--indent;
print_indent();
- print_string(block->stmt_expr ? "}" : "}\n");
+ print_char('}');
}
/**
if (val != NULL) {
print_string("return ");
print_expression(val);
- print_string(";\n");
+ print_char(';');
} else {
- print_string("return;\n");
+ print_string("return;");
}
}
static void print_expression_statement(const expression_statement_t *statement)
{
print_expression(statement->expression);
- print_string(";\n");
+ print_char(';');
}
/**
{
print_string("goto ");
if (statement->expression != NULL) {
- print_string("*");
+ print_char('*');
print_expression(statement->expression);
} else {
print_string(statement->label->base.symbol->string);
}
- print_string(";\n");
+ print_char(';');
}
/**
static void print_label_statement(const label_statement_t *statement)
{
print_format("%s:\n", statement->label->base.symbol->string);
- print_indent();
- print_statement(statement->statement);
+ print_indented_statement(statement->statement);
+}
+
+static void print_inner_statement(statement_t const *const stmt)
+{
+ if (stmt->kind == STATEMENT_COMPOUND) {
+ print_char(' ');
+ print_compound_statement(&stmt->compound);
+ } else {
+ print_char('\n');
+ ++indent;
+ print_indented_statement(stmt);
+ --indent;
+ }
+}
+
+static void print_after_inner_statement(statement_t const *const stmt)
+{
+ if (stmt->kind == STATEMENT_COMPOUND) {
+ print_char(' ');
+ } else {
+ print_char('\n');
+ print_indent();
+ }
}
/**
{
print_string("if (");
print_expression(statement->condition);
- print_string(") ");
- print_statement(statement->true_statement);
-
- if (statement->false_statement != NULL) {
- print_indent();
- print_string("else ");
- print_statement(statement->false_statement);
+ print_char(')');
+ print_inner_statement(statement->true_statement);
+
+ statement_t const *const f = statement->false_statement;
+ if (f) {
+ print_after_inner_statement(statement->true_statement);
+ print_string("else");
+ if (f->kind == STATEMENT_IF) {
+ print_char(' ');
+ print_if_statement(&f->ifs);
+ } else {
+ print_inner_statement(f);
+ }
}
}
*/
static void print_switch_statement(const switch_statement_t *statement)
{
+ int const old_case_indent = case_indent;
+ case_indent = indent;
+
print_string("switch (");
print_expression(statement->expression);
- print_string(") ");
- print_statement(statement->body);
+ print_char(')');
+ print_inner_statement(statement->body);
+
+ case_indent = old_case_indent;
}
/**
}
print_string(":\n");
}
- ++indent;
- if (statement->statement != NULL) {
- if (statement->statement->base.kind == STATEMENT_CASE_LABEL) {
- --indent;
- }
- print_indent();
- print_statement(statement->statement);
- }
+ print_indented_statement(statement->statement);
}
static void print_typedef(const entity_t *entity)
{
print_string("typedef ");
print_type_ext(entity->typedefe.type, entity->base.symbol, NULL);
- print_string(";");
+ print_char(';');
}
/**
bool first = true;
entity_t *entity = statement->declarations_begin;
if (entity == NULL) {
- print_string("/* empty declaration statement */\n");
+ print_string("/* empty declaration statement */");
return;
}
continue;
if (!first) {
+ print_char('\n');
print_indent();
} else {
first = false;
}
print_entity(entity);
- print_string("\n");
}
}
{
print_string("while (");
print_expression(statement->condition);
- print_string(") ");
- print_statement(statement->body);
+ print_char(')');
+ print_inner_statement(statement->body);
}
/**
*/
static void print_do_while_statement(const do_while_statement_t *statement)
{
- print_string("do ");
- print_statement(statement->body);
- print_indent();
+ print_string("do");
+ print_inner_statement(statement->body);
+ print_after_inner_statement(statement->body);
print_string("while (");
print_expression(statement->condition);
- print_string(");\n");
+ print_string(");");
}
/**
print_string("for (");
if (statement->initialisation != NULL) {
print_expression(statement->initialisation);
- print_string(";");
+ print_char(';');
} else {
entity_t const *entity = statement->scope.entities;
for (; entity != NULL; entity = entity->base.next) {
}
}
if (statement->condition != NULL) {
- print_string(" ");
+ print_char(' ');
print_expression(statement->condition);
}
- print_string(";");
+ print_char(';');
if (statement->step != NULL) {
- print_string(" ");
+ print_char(' ');
print_expression(statement->step);
}
- print_string(") ");
- print_statement(statement->body);
+ print_char(')');
+ print_inner_statement(statement->body);
}
/**
print_quoted_string(&argument->constraints, '"', 1);
print_string(" (");
print_expression(argument->expression);
- print_string(")");
+ print_char(')');
}
}
if (statement->is_volatile) {
print_string("volatile ");
}
- print_string("(");
+ print_char('(');
print_quoted_string(&statement->asm_text, '"', 1);
if (statement->outputs == NULL &&
statement->inputs == NULL &&
print_asm_clobbers(statement->clobbers);
end_of_print_asm_statement:
- print_string(");\n");
+ print_string(");");
}
/**
*/
static void print_ms_try_statement(const ms_try_statement_t *statement)
{
- print_string("__try ");
- print_statement(statement->try_statement);
- print_indent();
+ print_string("__try");
+ print_inner_statement(statement->try_statement);
+ print_after_inner_statement(statement->try_statement);
if (statement->except_expression != NULL) {
print_string("__except(");
print_expression(statement->except_expression);
- print_string(") ");
+ print_char(')');
} else {
- print_string("__finally ");
+ print_string("__finally");
}
- print_statement(statement->final_statement);
+ print_inner_statement(statement->final_statement);
}
/**
static void print_leave_statement(const leave_statement_t *statement)
{
(void)statement;
- print_string("__leave;\n");
+ print_string("__leave;");
}
/**
{
switch (statement->kind) {
case STATEMENT_EMPTY:
- print_string(";\n");
+ print_char(';');
break;
case STATEMENT_COMPOUND:
print_compound_statement(&statement->compound);
print_goto_statement(&statement->gotos);
break;
case STATEMENT_CONTINUE:
- print_string("continue;\n");
+ print_string("continue;");
break;
case STATEMENT_BREAK:
- print_string("break;\n");
+ print_string("break;");
break;
case STATEMENT_IF:
print_if_statement(&statement->ifs);
case STATEMENT_LEAVE:
print_leave_statement(&statement->leave);
break;
- case STATEMENT_INVALID:
- print_string("$invalid statement$\n");
+ case STATEMENT_ERROR:
+ print_string("$error statement$");
break;
}
}
}
if (variable->put_property_sym != NULL)
print_format("%sput=%s", comma, variable->put_property_sym->string);
- print_string(")");
+ print_char(')');
}
}
}
for ( ; entity != NULL; entity = entity->base.next) {
print_indent();
print_entity(entity);
- print_string("\n");
+ print_char('\n');
}
}
print_string("namespace ");
if (namespace->base.symbol != NULL) {
print_string(namespace->base.symbol->string);
- print_string(" ");
+ print_char(' ');
}
print_string("{\n");
&entity->function.parameters);
if (entity->function.statement != NULL) {
- print_string("\n");
- print_indent();
- print_statement(entity->function.statement);
+ print_char('\n');
+ print_indented_statement(entity->function.statement);
+ print_char('\n');
return;
}
break;
}
break;
+ case ENTITY_COMPOUND_MEMBER:
+ print_type_ext(declaration->type, declaration->base.symbol, NULL);
+ if (entity->compound_member.bitfield) {
+ print_format(" : %u", entity->compound_member.bit_size);
+ }
+ break;
+
default:
print_type_ext(declaration->type, declaration->base.symbol, NULL);
break;
}
- print_string(";");
+ print_char(';');
}
/**
print_compound:
print_string(entity->base.symbol->string);
if (entity->compound.complete) {
- print_string(" ");
+ print_char(' ');
print_compound_definition(&entity->compound);
}
- print_string(";");
+ print_char(';');
return;
case ENTITY_ENUM:
print_string("enum ");
print_string(entity->base.symbol->string);
- print_string(" ");
+ print_char(' ');
print_enum_definition(&entity->enume);
- print_string(";");
+ print_char(';');
return;
case ENTITY_NAMESPACE:
print_namespace(&entity->namespacee);
case ENTITY_LOCAL_LABEL:
print_string("__label__ ");
print_string(entity->base.symbol->string);
- print_string(";");
+ print_char(';');
return;
case ENTITY_LABEL:
case ENTITY_ENUM_VALUE:
panic("print_entity used on unexpected entity type");
- case ENTITY_INVALID:
- break;
}
panic("Invalid entity type encountered");
}
print_indent();
print_entity(entity);
- print_string("\n");
+ print_char('\n');
}
}
return EXPR_CLASS_CONSTANT;
case INITIALIZER_VALUE:
- return is_constant_expression(initializer->value.value);
+ return is_linker_constant(initializer->value.value);
case INITIALIZER_LIST: {
expression_classification_t all = EXPR_CLASS_CONSTANT;
panic("invalid initializer kind found");
}
-static expression_classification_t is_object_with_linker_constant_address(const expression_t *expression)
+/**
+ * Checks if an expression references an object with a constant/known location
+ * to the linker. Example:
+ * - "x", "*&x" with x being a global variable. The value of x need not be
+ * constant but the address of x is.
+ * - "a.b.c" when a has a constant/known location to the linker
+ */
+static expression_classification_t is_object_with_linker_constant_address(
+ const expression_t *expression)
{
switch (expression->kind) {
case EXPR_UNARY_DEREFERENCE:
- return is_address_constant(expression->unary.value);
+ return is_linker_constant(expression->unary.value);
case EXPR_SELECT: {
type_t *base_type = skip_typeref(expression->select.compound->base.type);
if (is_type_pointer(base_type)) {
/* it's a -> */
- return is_address_constant(expression->select.compound);
+ return is_linker_constant(expression->select.compound);
} else {
return is_object_with_linker_constant_address(expression->select.compound);
}
}
case EXPR_ARRAY_ACCESS: {
- expression_classification_t const ref = is_address_constant(expression->array_access.array_ref);
+ expression_classification_t const ref = is_linker_constant(expression->array_access.array_ref);
expression_classification_t const idx = is_constant_expression(expression->array_access.index);
return ref < idx ? ref : idx;
}
return EXPR_CLASS_VARIABLE;
}
- case EXPR_INVALID:
+ case EXPR_ERROR:
return EXPR_CLASS_ERROR;
default:
}
}
-expression_classification_t is_address_constant(const expression_t *expression)
+expression_classification_t is_linker_constant(const expression_t *expression)
{
switch (expression->kind) {
case EXPR_STRING_LITERAL:
case EXPR_LABEL_ADDRESS:
return EXPR_CLASS_CONSTANT;
+ case EXPR_COMPOUND_LITERAL:
+ return is_constant_initializer(expression->compound_literal.initializer);
+
case EXPR_UNARY_TAKE_ADDRESS:
return is_object_with_linker_constant_address(expression->unary.value);
= revert_automatic_type_conversion(expression->unary.value);
/* dereferencing a function is a NOP */
if (is_type_function(real_type)) {
- return is_address_constant(expression->unary.value);
+ return is_linker_constant(expression->unary.value);
}
/* FALLTHROUGH */
}
if (!is_type_pointer(dest) && (
dest->kind != TYPE_ATOMIC ||
!(get_atomic_type_flags(dest->atomic.akind) & ATOMIC_TYPE_FLAG_INTEGER) ||
- get_atomic_type_size(dest->atomic.akind) < get_atomic_type_size(get_intptr_kind())
+ get_atomic_type_size(dest->atomic.akind) < get_type_size(type_void_ptr)
))
- return EXPR_CLASS_VARIABLE;
+ return is_constant_expression(expression);
- expression_classification_t const expr = is_constant_expression(expression->unary.value);
- expression_classification_t const addr = is_address_constant(expression->unary.value);
- return expr > addr ? expr : addr;
+ return is_linker_constant(expression->unary.value);
}
case EXPR_BINARY_ADD:
type_t *const rtype = skip_typeref(right->base.type);
if (is_type_pointer(ltype)) {
- expression_classification_t const l = is_address_constant(left);
+ expression_classification_t const l = is_linker_constant(left);
expression_classification_t const r = is_constant_expression(right);
return l < r ? l : r;
} else if (is_type_pointer(rtype)) {
expression_classification_t const l = is_constant_expression(left);
- expression_classification_t const r = is_address_constant(right);
+ expression_classification_t const r = is_linker_constant(right);
return l < r ? l : r;
} else if (!is_type_valid(ltype) || !is_type_valid(rtype)) {
return EXPR_CLASS_ERROR;
} else {
- return EXPR_CLASS_VARIABLE;
+ return is_constant_expression(expression);
}
}
skip_typeref(revert_automatic_type_conversion(expression));
if (!is_type_array(type))
return EXPR_CLASS_VARIABLE;
- expression_classification_t const ref = is_address_constant(expression->array_access.array_ref);
- expression_classification_t const idx = is_constant_expression(expression->array_access.index);
- return ref < idx ? ref : idx;
+ return is_linker_constant(expression->array_access.array_ref);
}
case EXPR_CONDITIONAL: {
if (fold_constant_to_bool(c)) {
expression_t const *const t = expression->conditional.true_expression;
- return is_address_constant(t != NULL ? t : c);
+ return is_linker_constant(t != NULL ? t : c);
} else {
- return is_address_constant(expression->conditional.false_expression);
+ return is_linker_constant(expression->conditional.false_expression);
}
}
type_t *base_type = skip_typeref(compound->base.type);
if (is_type_pointer(base_type)) {
/* it's a -> */
- return is_address_constant(compound);
+ return is_linker_constant(compound);
} else {
return is_object_with_linker_constant_address(compound);
}
return EXPR_CLASS_VARIABLE;
}
- case EXPR_INVALID:
- return EXPR_CLASS_ERROR;
-
default:
- return EXPR_CLASS_VARIABLE;
+ return is_constant_expression(expression);
}
}
return EXPR_CLASS_VARIABLE;
switch (ref->entity->function.btk) {
- case bk_gnu_builtin_huge_val:
- case bk_gnu_builtin_huge_valf:
- case bk_gnu_builtin_huge_vall:
- case bk_gnu_builtin_inf:
- case bk_gnu_builtin_inff:
- case bk_gnu_builtin_infl:
- case bk_gnu_builtin_nan:
- case bk_gnu_builtin_nanf:
- case bk_gnu_builtin_nanl:
+ case BUILTIN_INF:
+ case BUILTIN_NAN:
return EXPR_CLASS_CONSTANT;
default:
return EXPR_CLASS_VARIABLE;
case EXPR_UNARY_DEREFERENCE:
return is_constant_pointer(expression->unary.value);
- case EXPR_INVALID:
+ case EXPR_ERROR:
return EXPR_CLASS_ERROR;
default:
case EXPR_UNARY_NOT:
return is_constant_expression(expression->unary.value);
- case EXPR_UNARY_CAST:
- case EXPR_UNARY_CAST_IMPLICIT: {
+ case EXPR_UNARY_CAST: {
type_t *const type = skip_typeref(expression->base.type);
if (is_type_scalar(type))
return is_constant_expression(expression->unary.value);
}
}
- case EXPR_INVALID:
+ case EXPR_ERROR:
return EXPR_CLASS_ERROR;
-
- case EXPR_UNKNOWN:
- break;
}
panic("invalid expression found (is constant expression)");
}