Skip to content

Commit

Permalink
Add compound literals
Browse files Browse the repository at this point in the history
Syntax:

struct TestT { int a; };
( TestT ) { 123 };
( TestT[] ) { { 123 }, { 321 } };
( static TestT[] ) { { 123 }, { 321 } };
( int[] ) "abc";
  • Loading branch information
positively-charged committed Dec 27, 2016
1 parent 26e4e16 commit e550599
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 108 deletions.
12 changes: 12 additions & 0 deletions src/codegen/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ static void visit_conversion( struct codegen* codegen, struct result* result,
static void visit_null( struct codegen* codegen, struct result* result );
static void visit_paren( struct codegen* codegen, struct result* result,
struct paren* paren );
static void visit_compound_literal( struct codegen* codegen,
struct result* result, struct compound_literal* literal );
static void push_indexed( struct codegen* codegen, int storage, int index );
static void push_element( struct codegen* codegen, int storage, int index );
static void inc_dimtrack( struct codegen* codegen );
Expand Down Expand Up @@ -1988,6 +1990,10 @@ void visit_primary( struct codegen* codegen, struct result* result,
visit_paren( codegen, result,
( struct paren* ) node );
break;
case NODE_COMPOUNDLITERAL:
visit_compound_literal( codegen, result,
( struct compound_literal* ) node );
break;
default:
UNREACHABLE()
}
Expand Down Expand Up @@ -2897,6 +2903,12 @@ void visit_paren( struct codegen* codegen, struct result* result,
visit_operand( codegen, result, paren->inside );
}

void visit_compound_literal( struct codegen* codegen, struct result* result,
struct compound_literal* literal ) {
c_visit_var( codegen, literal->var );
visit_var( codegen, result, literal->var );
}

void push_indexed( struct codegen* codegen, int storage, int index ) {
int code = PCD_PUSHSCRIPTVAR;
switch ( storage ) {
Expand Down
155 changes: 145 additions & 10 deletions src/parse/dec.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ static void init_ref_reading( struct ref_reading* reading );
static void read_ref( struct parse* parse, struct ref_reading* reading );
static void read_struct_ref( struct parse* parse,
struct ref_reading* reading );
static bool is_array_ref( struct parse* parse );
static void read_ref_storage( struct parse* parse,
struct ref_reading* reading );
static void read_array_ref( struct parse* parse, struct ref_reading* reading );
Expand Down Expand Up @@ -260,6 +261,7 @@ void p_init_dec( struct dec* dec ) {
dec->semicolon_absent = false;
dec->external = false;
dec->force_local_scope = false;
dec->anon = false;
}

void p_read_dec( struct parse* parse, struct dec* dec ) {
Expand Down Expand Up @@ -909,15 +911,22 @@ void read_ref( struct parse* parse, struct ref_reading* reading ) {
}
// Read array and function references.
while ( parse->tk == TK_BRACKET_L || parse->tk == TK_FUNCTION ) {
switch ( parse->tk ) {
case TK_BRACKET_L:
read_array_ref( parse, reading );
break;
case TK_FUNCTION:
read_ref_func( parse, reading );
break;
default:
UNREACHABLE()
if ( parse->tk == TK_BRACKET_L ) {
if ( is_array_ref( parse ) ) {
read_array_ref( parse, reading );
}
else {
break;
}
}
else {
switch ( parse->tk ) {
case TK_FUNCTION:
read_ref_func( parse, reading );
break;
default:
UNREACHABLE()
}
}
if ( parse->tk == TK_BIT_AND ) {
p_read_tk( parse );
Expand Down Expand Up @@ -964,6 +973,34 @@ void read_struct_ref( struct parse* parse, struct ref_reading* reading ) {
p_read_tk( parse );
}

bool is_array_ref( struct parse* parse ) {
struct parsertk_iter iter;
p_init_parsertk_iter( parse, &iter );
p_next_tk( parse, &iter );
if ( parse->tk == TK_BRACKET_L && iter.token->type == TK_BRACKET_R ) {
p_next_tk( parse, &iter );
while ( true ) {
if ( iter.token->type == TK_BRACKET_L ) {
p_next_tk( parse, &iter );
if ( iter.token->type == TK_BRACKET_R ) {
p_next_tk( parse, &iter );
}
else {
return false;
}
}
else {
break;
}
}
if ( iter.token->type == TK_BIT_AND ||
iter.token->type == TK_QUESTION_MARK ) {
return true;
}
}
return false;
}

void read_array_ref( struct parse* parse, struct ref_reading* reading ) {
struct pos pos = parse->tk_pos;
int count = 0;
Expand Down Expand Up @@ -1451,7 +1488,10 @@ void add_var( struct parse* parse, struct dec* dec ) {
}
}
else if ( dec->area == DEC_LOCAL || dec->area == DEC_FOR ) {
list_append( dec->vars, var );
var->hidden = dec->static_qual;
if ( dec->vars ) {
list_append( dec->vars, var );
}
if ( dec->static_qual ) {
var->hidden = true;
list_append( &parse->lib->vars, var );
Expand Down Expand Up @@ -1491,6 +1531,7 @@ struct var* alloc_var( struct dec* dec ) {
( dec->static_qual || dec->area == DEC_TOP ) ? true : false;
var->force_local_scope = dec->force_local_scope;
var->external = dec->external;
var->anon = dec->anon;
return var;
}

Expand Down Expand Up @@ -1625,6 +1666,100 @@ void read_foreach_var( struct parse* parse, struct dec* dec ) {
read_name( parse, dec );
}

bool p_is_paren_type( struct parse* parse ) {
if ( parse->tk == TK_PAREN_L ) {
switch ( p_peek( parse ) ) {
case TK_RAW:
case TK_INT:
case TK_FIXED:
case TK_BOOL:
case TK_STR:
case TK_ENUM:
case TK_STRUCT:
case TK_TYPENAME:
case TK_VOID:
case TK_STATIC:
return true;
default:
break;
}
}
return false;
}

void p_init_paren_reading( struct parse* parse,
struct paren_reading* reading ) {
reading->var = NULL;
t_init_pos_id( &reading->cast.pos, ALTERN_FILENAME_COMPILER );
reading->cast.spec = SPEC_NONE;
}

void p_read_paren_type( struct parse* parse, struct paren_reading* reading ) {
p_test_tk( parse, TK_PAREN_L );
struct dec dec;
p_init_dec( &dec );
dec.pos = parse->tk_pos;
dec.name = parse->task->blank_name;
dec.name_pos = parse->tk_pos;
dec.object = DECOBJ_VAR;
dec.private_visibility = true;
dec.anon = true;
if ( parse->local_vars ) {
dec.area = DEC_LOCAL;
}
else {
dec.area = DEC_TOP;
}
p_read_tk( parse );
// Qualifier, for compound literals.
if ( parse->tk == TK_STATIC ) {
read_qual( parse, &dec );
}
// Specifier.
struct spec_reading spec;
init_spec_reading( &spec, AREA_VAR );
read_spec( parse, &spec );
dec.type_pos = spec.pos;
dec.spec = spec.type;
dec.path = spec.path;
// Reference.
struct ref_reading ref;
init_ref_reading( &ref );
read_ref( parse, &ref );
dec.ref = ref.head;
// Dimension, for array literals. If a reference type is specified, then
// force it to be a part of an array literal, since a reference type is not
// used in a cast or a structure variable literal.
if ( parse->tk == TK_BRACKET_L || dec.ref ) {
p_test_tk( parse, TK_BRACKET_L );
read_dim( parse, &dec );
}
p_test_tk( parse, TK_PAREN_R );
p_read_tk( parse );
// Compound literal.
if ( dec.static_qual || dec.dim || parse->tk == TK_BRACE_L ) {
// Inializer.
dec.initz.pos = parse->tk_pos;
dec.initz.specified = true;
// String-based initializer, for array literals.
if ( dec.dim && parse->tk == TK_LIT_STRING ) {
read_single_init( parse, &dec );
}
else {
read_multi_init( parse, &dec, NULL );
}
// Variable.
test_var( parse, &dec );
add_var( parse, &dec );
reading->var = dec.var;
}
// Cast.
else {
reading->cast.pos = dec.pos;
reading->cast.spec = dec.spec;
}
}

void read_func( struct parse* parse, struct dec* dec ) {
read_name( parse, dec );
struct func* func = t_alloc_func();
Expand Down
117 changes: 44 additions & 73 deletions src/parse/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ static void read_prefix( struct parse* parse, struct expr_reading* reading );
static void read_unary( struct parse* parse, struct expr_reading* reading );
static void read_inc( struct parse* parse, struct expr_reading* reading );
static struct inc* alloc_inc( struct pos pos, bool dec );
static bool is_cast( struct parse* parse );
static void read_cast( struct parse* parse, struct expr_reading* reading );
static void read_primary( struct parse* parse, struct expr_reading* reading );
static void read_fixed_literal( struct parse* parse,
struct expr_reading* reading );
Expand Down Expand Up @@ -72,6 +70,10 @@ static void read_strcpy_call( struct parse* parse,
struct strcpy_reading* reading );
static void read_memcpy( struct parse* parse, struct expr_reading* reading );
static void read_paren( struct parse* parse, struct expr_reading* reading );
static void read_compound_literal( struct parse* parse,
struct expr_reading* reading, struct paren_reading* paren );
static void read_cast( struct parse* parse, struct expr_reading* reading,
struct paren_reading* paren );
static void read_anon_func( struct parse* parse,
struct expr_reading* reading );
static void read_paren_expr( struct parse* parse,
Expand Down Expand Up @@ -431,13 +433,7 @@ void read_prefix( struct parse* parse, struct expr_reading* reading ) {
}
break;
default:
if ( is_cast( parse ) ) {
read_cast( parse, reading );
return;
}
else {
prefix = parse->tk;
}
prefix = parse->tk;
}
// Read prefix operation.
switch ( prefix ) {
Expand Down Expand Up @@ -502,63 +498,6 @@ struct inc* alloc_inc( struct pos pos, bool dec ) {
return inc;
}

bool is_cast( struct parse* parse ) {
if ( parse->tk == TK_PAREN_L ) {
switch ( p_peek( parse ) ) {
case TK_RAW:
case TK_INT:
case TK_FIXED:
case TK_BOOL:
case TK_STR:
return ( p_peek_2nd( parse ) != TK_PAREN_L );
default:
break;
}
}
return false;
}

// TODO: Read type information from dec.c.
void read_cast( struct parse* parse, struct expr_reading* reading ) {
struct pos pos = parse->tk_pos;
p_test_tk( parse, TK_PAREN_L );
p_read_tk( parse );
int spec = SPEC_NONE;
switch ( parse->tk ) {
case TK_RAW:
spec = SPEC_RAW;
p_read_tk( parse );
break;
case TK_INT:
spec = SPEC_INT;
p_read_tk( parse );
break;
case TK_FIXED:
spec = SPEC_FIXED;
p_read_tk( parse );
break;
case TK_BOOL:
spec = SPEC_BOOL;
p_read_tk( parse );
break;
case TK_STR:
spec = SPEC_STR;
p_read_tk( parse );
break;
default:
UNREACHABLE();
}
p_test_tk( parse, TK_PAREN_R );
p_read_tk( parse );
read_prefix( parse, reading );
struct cast* cast = mem_alloc( sizeof( *cast ) );
cast->node.type = NODE_CAST;
cast->operand = reading->node;
cast->pos = pos;
cast->spec = spec;
reading->node = &cast->node;
}

void read_primary( struct parse* parse, struct expr_reading* reading ) {
// Determine which primary to read.
enum tk primary = TK_NONE;
Expand Down Expand Up @@ -1315,14 +1254,46 @@ void read_memcpy( struct parse* parse, struct expr_reading* reading ) {
}

void read_paren( struct parse* parse, struct expr_reading* reading ) {
switch ( p_peek( parse ) ) {
case TK_BRACE_L:
case TK_FUNCTION:
read_anon_func( parse, reading );
break;
default:
read_paren_expr( parse, reading );
if ( p_is_paren_type( parse ) ) {
struct paren_reading paren;
p_init_paren_reading( parse, &paren );
p_read_paren_type( parse, &paren );
if ( paren.var ) {
read_compound_literal( parse, reading, &paren );
}
else {
read_cast( parse, reading, &paren );
}
}
else {
switch ( p_peek( parse ) ) {
case TK_BRACE_L:
case TK_FUNCTION:
read_anon_func( parse, reading );
break;
default:
read_paren_expr( parse, reading );
}
}
}

void read_compound_literal( struct parse* parse, struct expr_reading* reading,
struct paren_reading* paren ) {
struct compound_literal* literal = mem_alloc( sizeof( *literal ) );
literal->node.type = NODE_COMPOUNDLITERAL;
literal->var = paren->var;
reading->node = &literal->node;
}

void read_cast( struct parse* parse, struct expr_reading* reading,
struct paren_reading* paren ) {
read_prefix( parse, reading );
struct cast* cast = mem_alloc( sizeof( *cast ) );
cast->node.type = NODE_CAST;
cast->operand = reading->node;
cast->pos = paren->cast.pos;
cast->spec = paren->cast.spec;
reading->node = &cast->node;
}

void read_anon_func( struct parse* parse, struct expr_reading* reading ) {
Expand Down
Loading

0 comments on commit e550599

Please sign in to comment.