diff options
-rw-r--r-- | 05/constants.b | 1 | ||||
-rw-r--r-- | 05/idents.b | 20 | ||||
-rw-r--r-- | 05/main.b | 4 | ||||
-rw-r--r-- | 05/main.c | 7 | ||||
-rw-r--r-- | 05/parse.b | 119 |
5 files changed, 142 insertions, 9 deletions
diff --git a/05/constants.b b/05/constants.b index a9f7774..9c20fdc 100644 --- a/05/constants.b +++ b/05/constants.b @@ -201,6 +201,7 @@ ; array of n t's: TYPE_ARRAY {n as 8 bytes} t ; struct/union: TYPE_STRUCT/TYPE_UNION {0 for incomplete types/4-byte pointer to struct/union} ; function: TYPE_FUNCTION {arg1 type} {arg2 type} ... {argn type} 0 {return type} +; note that enum types are just treated as ints. #define TYPE_VOID 1 #define TYPE_CHAR 3 #define TYPE_UNSIGNED_CHAR 4 diff --git a/05/idents.b b/05/idents.b index 1606b95..3f9d309 100644 --- a/05/idents.b +++ b/05/idents.b @@ -1,5 +1,4 @@ -; an "identifier list" is a list of identifiers and 64-bit values associated with them -; the values should be non-zero because 0 is returned for undefined identifiers. +; an "identifier list" is a list of identifiers and 64-bit values associated with them. function ident_list_create argument nbytes @@ -35,6 +34,23 @@ function ident_list_lookup if b == 0 goto ilist_lookup_loop return *8list ; UNALIGNED +; if identifier in list, sets *pvalue to its value (if pvalue is not null) and returns 1 +; otherwise, returns 0 +function ident_list_lookup_check + argument list + argument ident + argument pvalue + local b + :ilist_lookcheck_loop + if *1list == 255 goto return_0 + b = str_equals(list, ident) + list = memchr(list, 0) + list += 1 + if b == 0 goto ilist_lookcheck_loop + if pvalue == 0 goto return_1 + *8pvalue = *8list + return 1 + function ident_list_print argument list :ilist_print_loop @@ -28,7 +28,8 @@ global types global types_bytes_used ; ident list of type IDs global typedefs - +; ident list of enum values +global enumerators #include util.b #include idents.b @@ -145,6 +146,7 @@ function main fill_in_powers_of_10() typedefs = ident_list_create(100000) + enumerators = ident_list_create(400000) dat_banned_objmacros = 255 dat_banned_fmacros = 255 @@ -4,3 +4,10 @@ } (*x)(void); */ typedef int Foo[(char)((unsigned char)0xff + (unsigned char)0xf02)]; +typedef enum { + HELLO, + THERE, + TEST = 1-3, + EEE +} y; +typedef int Bar[EEE]; @@ -164,6 +164,7 @@ function parse_type_to local prefix_end local suffix local suffix_end + local expr token = *8p_token prefix = token @@ -297,7 +298,7 @@ function parse_type_to types = malloc(4000) types_init(types, &types_bytes_used) - local expr + expr = malloc(4000) *1out = TYPE_ARRAY out += 1 @@ -305,8 +306,8 @@ function parse_type_to token_skip_to_matching_rsquare(&p) suffix += 16 ; skip [ parse_expression(suffix, p, expr) - print_expression(expr) - putc(10) + ;print_expression(expr) + ;putc(10) evaluate_constant_expression(*8p_token, expr, &n) if n < 0 goto bad_array_size *8out = n @@ -458,7 +459,91 @@ function parse_type_to :base_type_union byte 0xcc ; @TODO :base_type_enum - byte 0xcc ; @TODO + local q + + *1out = TYPE_INT ; treat any enum as int + out += 1 + types_bytes_used = out - types + + p = prefix + 16 + if *1p == SYMBOL_LBRACE goto enum_definition + if *1p != TOKEN_IDENTIFIER goto bad_type ; e.g. enum int x; + p += 16 + if *1p == SYMBOL_LBRACE goto enum_definition + goto base_type_done ; just using an enum type, not defining it. + :enum_definition + local name + local value + value = -1 ; consider initial previous value as -1, because -1 + 1 = 0 + p += 16 ; skip opening { + :enum_defn_loop + if *1p == SYMBOL_RBRACE goto enum_defn_loop_end + if *1p != TOKEN_IDENTIFIER goto bad_enum_definition + p += 8 + name = *8p + p += 8 + if *1p == SYMBOL_COMMA goto enum_defn_no_equals + if *1p == SYMBOL_RBRACE goto enum_defn_no_equals + if *1p != SYMBOL_EQ goto bad_enum_definition ; e.g. enum { X ! }; + ; value provided, e.g. X = 5, + p += 16 + depth = 0 ; parenthesis depth + q = p + ; find matching comma -- yes, a comma can appear in an enumerator expression, e.g. + ; enum { X = sizeof(struct{int x, y;}) }; + ; or enum { X = (enum {A,B})3 }; + + ; find associated comma or right-brace + :enum_comma_loop + if depth > 0 goto enum_comma_deep + if *1q == SYMBOL_COMMA goto enum_comma_loop_end + if *1q == SYMBOL_RBRACE goto enum_comma_loop_end + :enum_comma_deep + if *1q == TOKEN_EOF goto bad_type + c = *1q + q += 16 + if c == SYMBOL_LPAREN goto enum_comma_incdepth + if c == SYMBOL_RPAREN goto enum_comma_decdepth + goto enum_comma_loop + :enum_comma_incdepth + depth += 1 + goto enum_comma_loop + :enum_comma_decdepth + depth -= 1 + goto enum_comma_loop + :enum_comma_loop_end + expr = malloc(4000) + parse_expression(p, q, expr) + evaluate_constant_expression(p, expr, &value) + free(expr) + if value < -0x80000000 goto bad_enumerator + if value > 0x7fffffff goto bad_enumerator + ident_list_add(enumerators, name, value) + p = q + if *1p == SYMBOL_RBRACE goto enum_defn_loop_end + p += 16 ; skip , + goto enum_defn_loop + :bad_enumerator + token_error(p, .str_bad_enumerator) + :str_bad_enumerator + string Enumerators too large for int. + byte 0 + :enum_defn_no_equals + ; no value provided, e.g. X, + ; the value of this enumerator is one more than the value of the last one + value += 1 + ident_list_add(enumerators, name, value) + if *1p == SYMBOL_RBRACE goto enum_defn_loop_end + p += 16 ; skip , + goto enum_defn_loop + :enum_defn_loop_end + out = types + types_bytes_used ; fix stuff in case there were any types in the enumerator expressions + goto base_type_done + :bad_enum_definition + token_error(*8p_token, .str_bad_enum_defn) + :str_bad_enum_defn + string Bad enum definition. + byte 0 :base_type_float *1out = TYPE_FLOAT out += 1 @@ -989,8 +1074,30 @@ function parse_expression if c == TOKEN_CONSTANT_CHAR goto expression_integer ; character constants are basically the same as integer constants if c == TOKEN_CONSTANT_FLOAT goto expression_float if c == TOKEN_STRING_LITERAL goto expression_string_literal + if c == TOKEN_IDENTIFIER goto expression_identifier goto unrecognized_expression - + + :expression_identifier + in += 8 + a = *8in + in += 8 + ; check if it's an enumerator + c = ident_list_lookup_check(enumerators, a, &n) + if c == 0 goto not_enumerator + ; it is an enumerator + *1out = EXPRESSION_CONSTANT_INT + out += 4 + *4out = TYPE_INT + out += 4 + *8out = n + out += 16 + return out + :not_enumerator + in -= 16 + token_error(in, .str_undeclared_variable) + :str_undeclared_variable + string Undeclared variable. + byte 0 :expression_integer *1out = EXPRESSION_CONSTANT_INT p = in + 8 @@ -1113,7 +1220,7 @@ function type_sizeof ; @NONSTANDARD: doesn't handle floats, but really why would you use floats in an array size ; e.g. SomeType x[(int)3.3]; ; this is also used for #if evaluation -; tokens is used for error messages (e.g. if this "constant" expression is *x or something) +; token is used for error messages (e.g. if this "constant" expression is *x or something) ; NOTE: this returns the end of the expression, not the value (which is stored in *8p_value) function evaluate_constant_expression argument token |