diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon
index 459432dd1..2f8c225ae 100644
--- a/src/zscript/zcc-parse.lemon
+++ b/src/zscript/zcc-parse.lemon
@@ -64,6 +64,10 @@
%left DOT LPAREN LBRACKET.
%left SCOPE.
+%type declarator {ZCC_Declarator *}
+%type declarator_no_fun {ZCC_Declarator *}
+%type opt_func_body {ZCC_CompoundStmt *}
+%type function_body {ZCC_CompoundStmt *}
main ::= translation_unit. { stat->sc.ScriptMessage("Parse complete\n"); }
@@ -180,7 +184,7 @@ class_member ::= default_def.
class_member ::= const_def.
/*----- Struct Definition -----*/
-/* Structs can define variables, enums, and structs. */
+/* Structs can define variables and enums. */
%type struct_body{ZCC_TreeNode *}
%type struct_member{ZCC_TreeNode *}
@@ -205,7 +209,7 @@ struct_member(X) ::= enum_def(A). { X = A; }
/*----- Enum Definition -----*/
/* Enumerators are lists of named integers. */
-%type enum_type {EZCCIntType}
+%type enum_type {EZCCBuiltinType}
%type enum_list {ZCC_EnumNode *}
%type enumerator {ZCC_EnumNode *}
@@ -362,33 +366,67 @@ state_call(X) ::= IDENTIFIER(A) func_expr_list(B).
default_def ::= DEFAULT compound_statement.
/* Type names */
-%type int_type {EZCCIntType}
-%type type_name {PType *}
+%type int_type {EZCCBuiltinType}
+%type type_name {ZCC_BasicType *}
+%type type_name1 {EZCCBuiltinType}
+%type vector_size {EZCCBuiltinType}
-int_type(X) ::= SBYTE. { X = ZCCINT_SInt8; }
-int_type(X) ::= BYTE. { X = ZCCINT_UInt8; }
-int_type(X) ::= SHORT. { X = ZCCINT_SInt16; }
-int_type(X) ::= USHORT. { X = ZCCINT_UInt16; }
-int_type(X) ::= INT. { X = ZCCINT_SInt32; }
-int_type(X) ::= UINT. { X = ZCCINT_UInt32; }
+int_type(X) ::= SBYTE. { X = ZCC_SInt8; }
+int_type(X) ::= BYTE. { X = ZCC_UInt8; }
+int_type(X) ::= SHORT. { X = ZCC_SInt16; }
+int_type(X) ::= USHORT. { X = ZCC_UInt16; }
+int_type(X) ::= INT. { X = ZCC_SInt32; }
+int_type(X) ::= UINT. { X = ZCC_UInt32; }
-type_name(X) ::= BOOL. { /*FIXME*/ X = TypeBool; }
-type_name(X) ::= int_type(A). { X = A; }
-type_name(X) ::= FLOAT. { X = TypeFloat32; }
-type_name(X) ::= DOUBLE. { X = TypeFloat64; }
-type_name(X) ::= STRING. { X = TypeString; }
-type_name(X) ::= VECTOR vector_size(A). { X = NewVector(A); }
-type_name(X) ::= NAME. { X = TypeName; }
-type_name(X) ::= IDENTIFIER. /* User-defined type (struct, enum, or class) */
+type_name1(X) ::= BOOL. { X = ZCC_Bool; }
+type_name1(X) ::= int_type(A). { X = A; }
+type_name1(X) ::= FLOAT. { X = ZCC_FloatAuto; }
+type_name1(X) ::= DOUBLE. { X = ZCC_Float64; }
+type_name1(X) ::= STRING. { X = ZCC_String; }
+type_name1(X) ::= VECTOR vector_size(A). { X = A; }
+type_name1(X) ::= NAME. { X = ZCC_Name; }
+
+type_name(X) ::= type_name1(A).
{
- // FIXME
- X = NULL;
+ NEW_AST_NODE(BasicType, type);
+ type->Type = A;
+ type->UserType = NULL;
+ X = type;
+}
+type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) */
+{
+ NEW_AST_NODE(BasicType, type);
+ NEW_AST_NODE(ZCC_Identifier, id);
+ type->Type = ZCC_UserType;
+ type->UserType = id;
+ id->Id = A;
+ X = type;
+}
+type_name(X) ::= LBRACKET dottable_id(A) RBRACKET.
+{
+ NEW_AST_NODE(BasicType, type);
+ type->Type = ZCC_UserType;
+ type->UserType = A;
+ X = type;
}
-%type vector_size {unsigned int}
-
-vector_size ::= .
-vector_size(X) ::= LT INTCONST(A) GT. { X = A.Int; }
+/* Vectors can be 2, 3, or 4 entries long. Default is a 3D vector.
+ * (Well, actually, I'm not sure if 4D ones are going to happen
+ * straight away.)
+ */
+vector_size(X) ::= . { X = ZCC_Vector3; }
+vector_size(X) ::= LT INTCONST(A) GT.
+{
+ if (A.Int >= 2 && A.Int <= 4)
+ {
+ X = ZCC_Vector2 + A.Int - 2;
+ }
+ else
+ {
+ X = ZCC_Vector3;
+ stat->sc.ScriptMessage("Invalid vector size %d\n", A.Int);
+ }
+}
/* Type names can also be used as identifiers in contexts where type names
* are not normally allowed. */
@@ -401,15 +439,32 @@ vector_size(X) ::= LT INTCONST(A) GT. { X = A.Int; }
%type type_list {ZCC_Type *}
%type type_list_or_void {ZCC_Type *}
%type type_or_array {ZCC_Type *}
-%type class_restrictor {PClass *}
+%type class_restrictor {ZCC_Identifier *}
%type array_size{ZCC_Expression *}
-aggregate_type ::= MAP LT type_or_array COMMA type_or_array GT. /* Hash table */
-aggregate_type ::= ARRAY LT type_or_array GT. /* TArray */
-aggregate_type ::= CLASS class_restrictor. /* class */
+aggregate_type(X) ::= MAP LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash table */
+{
+ NEW_AST_NODE(ZCC_MapType,map);
+ map->KeyType = A;
+ map->ValueType = B;
+ X = map;
+}
-class_restrictor ::= .
-class_restrictor ::= LT IDENTIFIER GT.
+aggregate_type(X) ::= ARRAY LT type_or_array(A) GT. /* TArray */
+{
+ NEW_AST_NODE(ZCC_DynArrayType,arr);
+ map->ElementType = A;
+ X = map;
+}
+
+aggregate_type(X) ::= CLASS class_restrictor(A). /* class */
+{
+ NEW_AST_NODE(ZCC_ClassType,cls);
+ cls->Restriction = A;
+ X = cls;
+}
+class_restrictor(X) ::= . { X = NULL; }
+class_restrictor(X) ::= LT dottable_id(A) GT. { X = A; }
type(X) ::= type_name(A). { X = A; A->ArraySize = NULL; }
type(X) ::= aggregate_type(A). { X = A; A->ArraySize = NULL; }
@@ -451,17 +506,99 @@ array_size(X) ::= array_size(A) LBRACKET opt_expr(B) RBRACKET.
X = A;
}
-declarator ::= decl_flags type_list_or_void variables_or_function. /* Multiple type names are only valid for functions. */
-declarator_no_fun ::= decl_flags type variable_list.
+%include
+{
+ struct VarOrFun
+ {
+ ZCC_VarName *VarNames;
+ ZCC_FuncParamDecl *FuncParams;
+ ENamedName FuncName;
+ int FuncFlags;
+ };
+}
+%type variables_or_function {VarOrFun}
-variables_or_function ::= IDENTIFIER LPAREN func_params RPAREN func_const opt_func_body. /* Function */
-variables_or_function ::= variable_list SEMICOLON.
+/* Multiple type names are only valid for functions. */
+declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C).
+{
+ if (C.FuncParams == NULL && C.VarNames == NULL)
+ { // An error. A message was already printed.
+ X = NULL;
+ }
+ else if (C.FuncParams != NULL)
+ { // A function
+ NEW_AST_NODE(FuncDeclarator, decl);
+ decl->Type = B;
+ decl->Params = C.FuncParams;
+ decl->Name = C.FuncName;
+ decl->Flags = A | C.FuncFlags;
+ X = decl;
+ }
+ else if (B != NULL && B->Sibling == NULL)
+ { // A variable
+ NEW_AST_NODE(VarDeclarator, decl);
+ decl->Type = B;
+ decl->Names = C.VarNames;
+ decl->Flags = A;
+ X = decl;
+ }
+ else
+ { // An invalid
+ if (B == NULL)
+ {
+ sc.ScriptMessage("Variables may not be of type void.\n");
+ }
+ else
+ {
+ sc.ScriptMessage("Variables may be of only one type.\n");
+ }
+ X = NULL;
+ }
+}
+declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C).
+{
+ NEW_AST_NODE(VarDeclarator, decl);
+ decl->Type = B;
+ decl->Names = C;
+ decl->Flags = A;
+ X = decl;
+}
+
+// Need to split it up like this to avoid parsing conflicts.
+variables_or_function(X) ::= IDENTIFIER(A) LPAREN func_params(B) RPAREN func_const(C) opt_func_body(D). /* Function */
+{
+ VarOrFun fun;
+
+ fun.VarNames = NULL;
+ fun.FuncParams = B;
+ fun.FuncFlags = C;
+ fun.FuncName = A.Name();
+ fun.FuncBody = D;
+ X = fun;
+}
+variables_or_function(X) ::= variable_list(A) SEMICOLON.
+{
+ VarOrFun var;
+
+ var.VarNames = A;
+ var.FuncParams = NULL;
+ var.FuncFlags = 0;
+ var.FuncName = NAME_None;
+ var.FuncBody = NULL;
+ X = var;
+}
variables_or_function ::= error SEMICOLON.
+{
+ VarOrFun bad;
+ bad.VarNames = NULL;
+ bad.FuncParams = NULL;
+ bad.FuncFlags = 0;
+ bad.FuncName = NAME_None;
+ bad.Func_Body = NULL;
+ X = bad;
+}
/*----- Variable Names -----*/
-// They get the array size, because that makes it look more like C.
-// I might still change my mind and stick array sizes with the rest
-// of the type like C#.
%type variable_name{ZCC_VarName *}
%type variable_list{ZCC_VarName *}
@@ -499,8 +636,8 @@ decl_flags(X) ::= decl_flags(A) DEPRECATED. { X = A | ZCC_Deprecated; }
func_const ::= .
func_const ::= CONST.
-opt_func_body ::= SEMICOLON.
-opt_func_body ::= function_body.
+opt_func_body(X) ::= SEMICOLON. { X = NULL; }
+opt_func_body(X) ::= function_body(A). { X = A; }
%type func_params {ZCC_FuncParamDecl *}
%type func_param_list {ZCC_FuncParamDecl *}
diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h
index f14261c28..c36c9127e 100644
--- a/src/zscript/zcc_parser.h
+++ b/src/zscript/zcc_parser.h
@@ -93,15 +93,26 @@ enum EZCCTreeNodeType
AST_ConstantDef,
};
-enum EZCCIntType
+enum EZCCBuiltinType
{
- ZCCINT_SInt8,
- ZCCINT_UInt8,
- ZCCINT_SInt16,
- ZCCINT_UInt16,
- ZCCINT_SInt32,
- ZCCINT_UInt32,
- ZCCINT_Auto, // for enums, autoselect appropriately sized int
+ ZCC_SInt8,
+ ZCC_UInt8,
+ ZCC_SInt16,
+ ZCC_UInt16,
+ ZCC_SInt32,
+ ZCC_UInt32,
+ ZCC_IntAuto, // for enums, autoselect appropriately sized int
+
+ ZCC_Bool,
+ ZCC_Float32,
+ ZCC_Float64,
+ ZCC_FloatAuto, // 32-bit in structs/classes, 64-bit everywhere else
+ ZCC_String,
+ ZCC_Vector2,
+ ZCC_Vector3,
+ ZCC_Vector4,
+ ZCC_Name,
+ ZCC_UserType,
};
enum EZCCExprType
@@ -293,8 +304,8 @@ struct ZCC_Type : ZCC_TreeNode
struct ZCC_BasicType : ZCC_Type
{
- PType *Type;
- ENamedName TypeName;
+ EZCCBuiltinType Type;
+ ZCC_Identifier *UserType;
};
struct ZCC_MapType : ZCC_Type
@@ -310,7 +321,24 @@ struct ZCC_DynArrayType : ZCC_Type
struct ZCC_ClassType : ZCC_Type
{
- ENamedName Restriction;
+ ZCC_Identifier *Restriction;
+};
+
+// A variable in a class or struct.
+struct ZCC_VarDeclarator : ZCC_TreeNode
+{
+ ZCC_Type *Type;
+ ZCC_VarName *Names;
+ int Flags;
+};
+
+// A function in a class.
+struct ZCC_FuncDeclarator : ZCC_TreeNode
+{
+ ZCC_Type *Type;
+ ZCC_FuncParamDecl *Params;
+ ENamedName Name;
+ int Flags;
};
struct ZCC_ExprID : ZCC_Expression