summaryrefslogtreecommitdiff
path: root/05
diff options
context:
space:
mode:
Diffstat (limited to '05')
-rw-r--r--05/constants.b1
-rw-r--r--05/idents.b20
-rw-r--r--05/main.b4
-rw-r--r--05/main.c7
-rw-r--r--05/parse.b119
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
diff --git a/05/main.b b/05/main.b
index 35733ae..f5b702a 100644
--- a/05/main.b
+++ b/05/main.b
@@ -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
diff --git a/05/main.c b/05/main.c
index fd2f3cd..7dc9a0a 100644
--- a/05/main.c
+++ b/05/main.c
@@ -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];
diff --git a/05/parse.b b/05/parse.b
index c424ee5..20970f5 100644
--- a/05/parse.b
+++ b/05/parse.b
@@ -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