Skip to content

Commit 84b307f

Browse files
committed
Add const qualifier support
The implementation allows shecc to parse and handle const qualifiers in C code, improving type safety and C standard compliance.
1 parent 3a8d1b3 commit 84b307f

File tree

5 files changed

+47
-15
lines changed

5 files changed

+47
-15
lines changed

src/defs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ typedef enum {
179179
T_break,
180180
T_default,
181181
T_continue,
182+
T_const, /* const qualifier */
182183
/* C pre-processor directives */
183184
T_cppd_include,
184185
T_cppd_define,
@@ -353,7 +354,8 @@ struct var {
353354
int ptr_level;
354355
bool is_func;
355356
bool is_global;
356-
bool address_taken; /* true if variable address was taken (&var) */
357+
bool is_const_qualified; /* true if variable has const qualifier */
358+
bool address_taken; /* true if variable address was taken (&var) */
357359
int array_size;
358360
int array_dim1, array_dim2; /* first/second dimension size for 2D arrays */
359361
int offset; /* offset from stack or frame, index 0 is reserved */

src/elf.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
int elf_symbol_index;
1515

16-
void elf_write_str(strbuf_t *elf_array, char *vals)
16+
void elf_write_str(strbuf_t *elf_array, const char *vals)
1717
{
1818
/*
1919
* Note that strbuf_puts() does not push the null character.
@@ -348,7 +348,7 @@ void elf_align(void)
348348
elf_write_byte(elf_strtab, 0);
349349
}
350350

351-
void elf_add_symbol(char *symbol, int pc)
351+
void elf_add_symbol(const char *symbol, int pc)
352352
{
353353
/* Check for null pointers to prevent crashes */
354354
if (!symbol || !elf_symtab || !elf_strtab) {
@@ -366,7 +366,7 @@ void elf_add_symbol(char *symbol, int pc)
366366
elf_symbol_index++;
367367
}
368368

369-
void elf_generate(char *outfile)
369+
void elf_generate(const char *outfile)
370370
{
371371
elf_align();
372372
elf_generate_header();

src/globals.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1159,7 +1159,7 @@ bool strbuf_putc(strbuf_t *src, char value)
11591159
return true;
11601160
}
11611161

1162-
bool strbuf_puts(strbuf_t *src, char *value)
1162+
bool strbuf_puts(strbuf_t *src, const char *value)
11631163
{
11641164
int len = strlen(value);
11651165

src/lexer.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
/* Hash table constants */
1414
#define NUM_DIRECTIVES 11
15-
#define NUM_KEYWORDS 16
15+
#define NUM_KEYWORDS 17
1616

1717
/* Token mapping structure for elegant initialization */
1818
typedef struct {
@@ -86,6 +86,7 @@ void lex_init_keywords()
8686
{"default", T_default},
8787
{"continue", T_continue},
8888
{"union", T_union},
89+
{"const", T_const},
8990
};
9091

9192
/* hashmap insertion */
@@ -787,13 +788,15 @@ token_t lex_token_impl(bool aliasing)
787788
keyword = T_case;
788789
break;
789790

790-
case 5: /* 5-letter keywords: while, break, union */
791+
case 5: /* 5-letter keywords: while, break, union, const */
791792
if (token_str[0] == 'w' && !memcmp(token_str, "while", 5))
792793
keyword = T_while;
793794
else if (token_str[0] == 'b' && !memcmp(token_str, "break", 5))
794795
keyword = T_break;
795796
else if (token_str[0] == 'u' && !memcmp(token_str, "union", 5))
796797
keyword = T_union;
798+
else if (token_str[0] == 'c' && !memcmp(token_str, "const", 5))
799+
keyword = T_const;
797800
break;
798801

799802
case 6: /* 6-letter keywords: return, struct, switch, sizeof */

src/parser.c

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ var_t *opstack_pop(void)
130130

131131
void read_expr(block_t *parent, basic_block_t **bb);
132132

133-
int write_symbol(char *data)
133+
int write_symbol(const char *data)
134134
{
135135
int start_len = elf_data->size;
136136
elf_write_str(elf_data, data);
@@ -1325,8 +1325,15 @@ void read_parameter_list_decl(func_t *func, bool anon)
13251325
lex_accept(T_comma);
13261326
}
13271327

1328-
while (lex_peek(T_identifier, NULL) == 1) {
1329-
read_full_var_decl(&func->param_defs[vn++], anon, true);
1328+
while (lex_peek(T_identifier, NULL) == 1 || lex_peek(T_const, NULL)) {
1329+
/* Check for const qualifier */
1330+
bool is_const = false;
1331+
if (lex_accept(T_const))
1332+
is_const = true;
1333+
1334+
read_full_var_decl(&func->param_defs[vn], anon, true);
1335+
func->param_defs[vn].is_const_qualified = is_const;
1336+
vn++;
13301337
lex_accept(T_comma);
13311338
}
13321339
func->num_params = vn;
@@ -3808,6 +3815,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
38083815
type_t *type;
38093816
var_t *vd, *rs1, *rs2, *var;
38103817
opcode_t prefix_op = OP_generic;
3818+
bool is_const = false;
38113819

38123820
if (!bb)
38133821
printf("Warning: unreachable code detected\n");
@@ -4127,6 +4135,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
41274135
type = find_type(token, find_type_flag);
41284136
if (type) {
41294137
var = require_typed_var(parent, type);
4138+
var->is_const_qualified = is_const;
41304139
read_partial_var_decl(var, NULL);
41314140
add_insn(parent, bb, OP_allocat, var, NULL, NULL, 0, NULL);
41324141
add_symbol(bb, var);
@@ -4332,14 +4341,22 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
43324341
error("Unknown struct/union type");
43334342
}
43344343

4344+
/* Handle const qualifier for local variable declarations */
4345+
if (lex_accept(T_const)) {
4346+
is_const = true;
4347+
/* After const, we expect a type */
4348+
if (!lex_peek(T_identifier, token))
4349+
error("Expected type after const");
4350+
}
4351+
43354352
/* statement with prefix */
4336-
if (lex_accept(T_increment))
4353+
if (!is_const && lex_accept(T_increment))
43374354
prefix_op = OP_add;
4338-
else if (lex_accept(T_decrement))
4355+
else if (!is_const && lex_accept(T_decrement))
43394356
prefix_op = OP_sub;
43404357
/* must be an identifier or asterisk (for pointer dereference) */
43414358
bool has_asterisk = lex_peek(T_asterisk, NULL);
4342-
if (!lex_peek(T_identifier, token) && !has_asterisk)
4359+
if (!is_const && !lex_peek(T_identifier, token) && !has_asterisk)
43434360
error("Unexpected token");
43444361

43454362
/* handle macro parameter substitution for statements */
@@ -4411,6 +4428,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
44114428

44124429
if (type) {
44134430
var = require_typed_var(parent, type);
4431+
var->is_const_qualified = is_const;
44144432
read_full_var_decl(var, false, false);
44154433
add_insn(parent, bb, OP_allocat, var, NULL, NULL, 0, NULL);
44164434
add_symbol(bb, var);
@@ -4729,10 +4747,11 @@ void read_func_body(func_t *func)
47294747
}
47304748

47314749
/* if first token is type */
4732-
void read_global_decl(block_t *block)
4750+
void read_global_decl(block_t *block, bool is_const)
47334751
{
47344752
var_t *var = require_var(block);
47354753
var->is_global = true;
4754+
var->is_const_qualified = is_const;
47364755

47374756
/* new function, or variables under parent */
47384757
read_full_var_decl(var, false, false);
@@ -4818,6 +4837,7 @@ void initialize_struct_field(var_t *nv, var_t *v, int offset)
48184837
nv->ptr_level = 0;
48194838
nv->is_func = false;
48204839
nv->is_global = false;
4840+
nv->is_const_qualified = false;
48214841
nv->array_size = 0;
48224842
nv->offset = offset;
48234843
nv->init_val = 0;
@@ -4832,6 +4852,11 @@ void read_global_statement(void)
48324852
{
48334853
char token[MAX_ID_LEN];
48344854
block_t *block = GLOBAL_BLOCK; /* global block */
4855+
bool is_const = false;
4856+
4857+
/* Handle const qualifier */
4858+
if (lex_accept(T_const))
4859+
is_const = true;
48354860

48364861
if (lex_accept(T_struct)) {
48374862
int i = 0, size = 0;
@@ -4847,6 +4872,7 @@ void read_global_statement(void)
48474872
/* one or more declarators */
48484873
var_t *var = require_typed_var(block, decl_type);
48494874
var->is_global = true; /* Global struct variable */
4875+
var->is_const_qualified = is_const;
48504876
read_partial_var_decl(var, NULL);
48514877
add_insn(block, GLOBAL_FUNC->bbs, OP_allocat, var, NULL, NULL, 0,
48524878
NULL);
@@ -5144,7 +5170,7 @@ void read_global_statement(void)
51445170
lex_expect(T_semicolon);
51455171
}
51465172
} else if (lex_peek(T_identifier, NULL)) {
5147-
read_global_decl(block);
5173+
read_global_decl(block, is_const);
51485174
} else
51495175
error("Syntax error in global statement");
51505176
}
@@ -5155,6 +5181,7 @@ void parse_internal(void)
51555181
GLOBAL_FUNC = add_func("", true);
51565182
GLOBAL_FUNC->stack_size = 4;
51575183
GLOBAL_FUNC->bbs = arena_calloc(BB_ARENA, 1, sizeof(basic_block_t));
5184+
GLOBAL_FUNC->bbs->belong_to = GLOBAL_FUNC; /* Prevent nullptr deref in RA */
51585185

51595186
/* built-in types */
51605187
TY_void = add_named_type("void");

0 commit comments

Comments
 (0)