enums almost working
This commit is contained in:
parent
150fbb9dd8
commit
049bd1440d
5 changed files with 142 additions and 9 deletions
|
@ -201,6 +201,7 @@
|
||||||
; array of n t's: TYPE_ARRAY {n as 8 bytes} t
|
; 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}
|
; 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}
|
; 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_VOID 1
|
||||||
#define TYPE_CHAR 3
|
#define TYPE_CHAR 3
|
||||||
#define TYPE_UNSIGNED_CHAR 4
|
#define TYPE_UNSIGNED_CHAR 4
|
||||||
|
|
20
05/idents.b
20
05/idents.b
|
@ -1,5 +1,4 @@
|
||||||
; an "identifier list" is a list of identifiers and 64-bit values associated with them
|
; 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.
|
|
||||||
|
|
||||||
function ident_list_create
|
function ident_list_create
|
||||||
argument nbytes
|
argument nbytes
|
||||||
|
@ -35,6 +34,23 @@ function ident_list_lookup
|
||||||
if b == 0 goto ilist_lookup_loop
|
if b == 0 goto ilist_lookup_loop
|
||||||
return *8list ; UNALIGNED
|
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
|
function ident_list_print
|
||||||
argument list
|
argument list
|
||||||
:ilist_print_loop
|
:ilist_print_loop
|
||||||
|
|
|
@ -28,7 +28,8 @@ global types
|
||||||
global types_bytes_used
|
global types_bytes_used
|
||||||
; ident list of type IDs
|
; ident list of type IDs
|
||||||
global typedefs
|
global typedefs
|
||||||
|
; ident list of enum values
|
||||||
|
global enumerators
|
||||||
|
|
||||||
#include util.b
|
#include util.b
|
||||||
#include idents.b
|
#include idents.b
|
||||||
|
@ -145,6 +146,7 @@ function main
|
||||||
fill_in_powers_of_10()
|
fill_in_powers_of_10()
|
||||||
|
|
||||||
typedefs = ident_list_create(100000)
|
typedefs = ident_list_create(100000)
|
||||||
|
enumerators = ident_list_create(400000)
|
||||||
|
|
||||||
dat_banned_objmacros = 255
|
dat_banned_objmacros = 255
|
||||||
dat_banned_fmacros = 255
|
dat_banned_fmacros = 255
|
||||||
|
|
|
@ -4,3 +4,10 @@
|
||||||
} (*x)(void);
|
} (*x)(void);
|
||||||
*/
|
*/
|
||||||
typedef int Foo[(char)((unsigned char)0xff + (unsigned char)0xf02)];
|
typedef int Foo[(char)((unsigned char)0xff + (unsigned char)0xf02)];
|
||||||
|
typedef enum {
|
||||||
|
HELLO,
|
||||||
|
THERE,
|
||||||
|
TEST = 1-3,
|
||||||
|
EEE
|
||||||
|
} y;
|
||||||
|
typedef int Bar[EEE];
|
||||||
|
|
119
05/parse.b
119
05/parse.b
|
@ -164,6 +164,7 @@ function parse_type_to
|
||||||
local prefix_end
|
local prefix_end
|
||||||
local suffix
|
local suffix
|
||||||
local suffix_end
|
local suffix_end
|
||||||
|
local expr
|
||||||
|
|
||||||
token = *8p_token
|
token = *8p_token
|
||||||
prefix = token
|
prefix = token
|
||||||
|
@ -297,7 +298,7 @@ function parse_type_to
|
||||||
types = malloc(4000)
|
types = malloc(4000)
|
||||||
types_init(types, &types_bytes_used)
|
types_init(types, &types_bytes_used)
|
||||||
|
|
||||||
local expr
|
|
||||||
expr = malloc(4000)
|
expr = malloc(4000)
|
||||||
*1out = TYPE_ARRAY
|
*1out = TYPE_ARRAY
|
||||||
out += 1
|
out += 1
|
||||||
|
@ -305,8 +306,8 @@ function parse_type_to
|
||||||
token_skip_to_matching_rsquare(&p)
|
token_skip_to_matching_rsquare(&p)
|
||||||
suffix += 16 ; skip [
|
suffix += 16 ; skip [
|
||||||
parse_expression(suffix, p, expr)
|
parse_expression(suffix, p, expr)
|
||||||
print_expression(expr)
|
;print_expression(expr)
|
||||||
putc(10)
|
;putc(10)
|
||||||
evaluate_constant_expression(*8p_token, expr, &n)
|
evaluate_constant_expression(*8p_token, expr, &n)
|
||||||
if n < 0 goto bad_array_size
|
if n < 0 goto bad_array_size
|
||||||
*8out = n
|
*8out = n
|
||||||
|
@ -458,7 +459,91 @@ function parse_type_to
|
||||||
:base_type_union
|
:base_type_union
|
||||||
byte 0xcc ; @TODO
|
byte 0xcc ; @TODO
|
||||||
:base_type_enum
|
: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
|
:base_type_float
|
||||||
*1out = TYPE_FLOAT
|
*1out = TYPE_FLOAT
|
||||||
out += 1
|
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_CHAR goto expression_integer ; character constants are basically the same as integer constants
|
||||||
if c == TOKEN_CONSTANT_FLOAT goto expression_float
|
if c == TOKEN_CONSTANT_FLOAT goto expression_float
|
||||||
if c == TOKEN_STRING_LITERAL goto expression_string_literal
|
if c == TOKEN_STRING_LITERAL goto expression_string_literal
|
||||||
|
if c == TOKEN_IDENTIFIER goto expression_identifier
|
||||||
goto unrecognized_expression
|
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
|
:expression_integer
|
||||||
*1out = EXPRESSION_CONSTANT_INT
|
*1out = EXPRESSION_CONSTANT_INT
|
||||||
p = in + 8
|
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
|
; @NONSTANDARD: doesn't handle floats, but really why would you use floats in an array size
|
||||||
; e.g. SomeType x[(int)3.3];
|
; e.g. SomeType x[(int)3.3];
|
||||||
; this is also used for #if evaluation
|
; 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)
|
; NOTE: this returns the end of the expression, not the value (which is stored in *8p_value)
|
||||||
function evaluate_constant_expression
|
function evaluate_constant_expression
|
||||||
argument token
|
argument token
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue