Skip to content

Commit

Permalink
Implement the new '(any[, ...])' syntax for bydesc parameters too
Browse files Browse the repository at this point in the history
  • Loading branch information
dkl committed Apr 11, 2014
1 parent 8fb075e commit 831f0c3
Show file tree
Hide file tree
Showing 44 changed files with 646 additions and 202 deletions.
3 changes: 2 additions & 1 deletion changelog.txt
Expand Up @@ -10,14 +10,15 @@ Version 0.91.0:
- DOS rtlib no longer uses setlocale(), as FB-dos doesn't support Unicode anyways, and thus the setlocale() reference here only served to unnecessarily increase .exe size.
- #if expressions allow quirk function names to be used as literals again, so for example <#IF TYPEOF(x) = STRING> works again, instead of complaining about missing arguments in a call to the String() function.
- For dynamic arrays where the dimension count is known at the point of the declaration, fbc will now allocate array descriptors with room for only the amount of required dimensions. Descriptors with room for all of FB_MAXARRAYDIMS will only be used for dynamic arrays declared with '()' (unknown dimension count) now.
- The C++-compatible name mangling for procedures with BYDESC parameters has been adjusted to match the implementation of BYDESC parameters, and to support the new '(any[, ...])' syntax.

[added]
- 64bit support (-arch x86_64) based on -gen gcc: INTEGER/POINTER = 64bit, LONG = 32bit DWORD. Compiler #define: __FB_64BIT__
- -arch 32|64 options to support easy switching between 32bit and 64bit, by selecting a default arch that supports 32/64 bits respectively.
- ARM support (-arch armv6|armv7-a|aarch64) based on -gen gcc. Compiler #define: __FB_ARM__
- fbc -v now prints out the target system and architecture
- BYVAL AS STRING is now working properly: it now has BYVAL semantics and no longer behaves like BYREF AS ZSTRING. Modifications made by the callee are not visible to the caller, as for other BYVAL parameters. (BYVAL AS STRING is implemented by copying the string argument into a temporary STRING, whose descriptor is then passed BYREF to the procedure)
- New syntax for declaring dynamic arrays with certain amount of dimensions (but no initial bounds): DIM array(ANY) AS INTEGER (1 dimension), DIM array(ANY, ANY) AS INTEGER (2 dimensions), etc. This allows the compiler to allocate smaller array descriptors which is especially useful for dynamic array fields.
- New syntax for declaring dynamic arrays with certain amount of dimensions (but no initial bounds): DIM array(ANY) AS INTEGER (1 dimension), DIM array(ANY, ANY) AS INTEGER (2 dimensions), etc. This allows for better compile-time checking of dynamic array parameters, and also allows the compiler to allocate smaller array descriptors which is especially useful for dynamic array fields.
- Dynamic array fields are now supported in UDTs (for example: array(ANY) AS INTEGER). Similar rules as for dynamic string fields apply: Just the array descriptor is included in the UDT, not the actual array data. The UDT will become a class, and is given an implicit constructor and destructor to initialize the array descriptor, or free the data it contains. This code will also automatically be added to user-defined constructors/destructors.
- REDIM now also accepts expressions to access dynamic arrays, instead of just plain identifiers, which is needed to redim dynamic array fields, or dynamic arrays that are static member variables. For example: REDIM (this.array)(0 to 1)
- Improved multiplication/division/modulus to bitwise shift/and optimizations to handle operations with 64bit and unsigned right hand operand better
Expand Down
71 changes: 59 additions & 12 deletions src/compiler/ast-node-arg.bas
Expand Up @@ -341,7 +341,37 @@ private sub hCheckByrefParam _
hBuildByrefArg( param, n, arg )
end sub

'':::::
private function hCheckBydescDimensions _
( _
byval param as FBSYMBOL ptr, _
byval arg as FBSYMBOL ptr _
) as integer

assert( param->class = FB_SYMBCLASS_PARAM )
assert( symbIsVar( arg ) or symbIsField( arg ) )

if( param->param.bydescdimensions <> symbGetArrayDimensions( arg ) ) then
'' 1. BYDESC param itself has unknown dimensions? (then it can't affect the arg array anyways)
if( param->param.bydescdimensions = -1 ) then
'' Note: Can't update the BYDESC param from unknown to known dimensions,
'' because that would break rtlib functions like lbound(): they couldn't
'' accept any arrays anymore within the same module.
'''param->param.bydescdimensions = symbGetArrayDimensions( arg )

'' 2. Arg array has unknown dimensions, while BYDESC param has known dimensions?
elseif( symbGetArrayDimensions( arg ) = -1 ) then
'' Then the arg array can be updated to the BYDESC param's known dimensions.
symbCheckDynamicArrayDimensions( arg, param->param.bydescdimensions )

'' 3. Both have known dimensions, but they're different, i.e. incompatible
else
exit function
end if
end if

function = TRUE
end function

private function hCheckByDescParam _
( _
byval parent as ASTNODE ptr, _
Expand All @@ -354,6 +384,7 @@ private function hCheckByDescParam _
dim as FBSYMBOL ptr s = any, desc = any

arg_dtype = astGetDatatype( n->l )
function = FALSE

'' is arg a pointer?
if( n->arg.mode = FB_PARAMMODE_BYVAL ) then
Expand All @@ -362,17 +393,15 @@ private function hCheckByDescParam _

s = astGetSymbol( n->l )
if( s = NULL ) then
errReport( FB_ERRMSG_PARAMTYPEMISMATCHAT )
return FALSE
exit function
end if

'' same type? (don't check if it's a rtl proc, or a forward call)
sym_dtype = symbGetType( param )
if( (parent->call.isrtl = FALSE) and (sym_dtype <> FB_DATATYPE_VOID) ) then
if( (typeGetClass( arg_dtype ) <> typeGetClass( sym_dtype )) or _
(typeGetSize( arg_dtype ) <> typeGetSize( sym_dtype )) ) then
errReport( FB_ERRMSG_PARAMTYPEMISMATCHAT )
return FALSE
(typeGetSize( arg_dtype ) <> typeGetSize( sym_dtype )) ) then
exit function
end if
end if

Expand All @@ -381,9 +410,13 @@ private function hCheckByDescParam _

'' BYDESC param passed to BYDESC param?
if( symbIsParamByDesc( s ) ) then
if( hCheckBydescDimensions( param, s ) = FALSE ) then
exit function
end if

'' it's a pointer, but it will be seen as anything else
'' (ie: "array() as string"), so, remap the type
astSetType( n->l, typeAddrOf( FB_DATATYPE_STRUCT ), symb.fbarray(-1) )
astSetType( n->l, typeAddrOf( FB_DATATYPE_STRUCT ), symb.fbarray(symbGetArrayDimensions( s )) )
return TRUE
end if

Expand All @@ -392,6 +425,10 @@ private function hCheckByDescParam _
'' ellipsis)
desc = symbGetArrayDescriptor( s )
if( desc ) then
if( hCheckBydescDimensions( param, s ) = FALSE ) then
exit function
end if

astDelTree( n->l )
n->l = astNewADDROF( astNewVAR( desc ) )
return TRUE
Expand All @@ -401,6 +438,10 @@ private function hCheckByDescParam _
assert( symbIsField( s ) )

if( symbIsDynamic( s ) ) then
if( hCheckBydescDimensions( param, s ) = FALSE ) then
exit function
end if

'' Dynamic array fields: If an access to the fake array field is given,
'' how to build the access to descriptor? The FIELD node may be optimized
'' already, and there probably is no way to tell the UDT access expression
Expand All @@ -417,15 +458,16 @@ private function hCheckByDescParam _
return TRUE

elseif( symbGetArrayDimensions( s ) > 0 ) then
if( hCheckBydescDimensions( param, s ) = FALSE ) then
exit function
end if

'' Static array field: Create a temp array descriptor
desc = hAllocTmpArrayDesc( s, n->l, desc_tree )
n->l = astNewLINK( astNewADDROF( astNewVAR( desc ) ), desc_tree )
return TRUE
end if
end if

errReport( FB_ERRMSG_PARAMTYPEMISMATCHAT )
function = FALSE
end function

'':::::
Expand Down Expand Up @@ -741,7 +783,7 @@ private function hCheckParam _
) as integer

dim as ASTNODE ptr arg = any
dim as integer param_dtype = any, arg_dtype
dim as integer param_dtype = any, arg_dtype = any

function = FALSE

Expand All @@ -757,7 +799,12 @@ private function hCheckParam _
select case symbGetParamMode( param )
'' by descriptor?
case FB_PARAMMODE_BYDESC
return hCheckByDescParam( parent, param, n )
if( hCheckByDescParam( parent, param, n ) = FALSE ) then
errReport( FB_ERRMSG_PARAMTYPEMISMATCHAT )
exit function
end if

return TRUE

'' vararg?
case FB_PARAMMODE_VARARG
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/edbg_stab.bas
Expand Up @@ -689,7 +689,7 @@ private function hDeclDynArray( byval sym as FBSYMBOL ptr ) as string static
dim as FBSYMBOL ptr fld = any, desctype = any

if( symbIsParamByDesc( sym ) ) then
desctype = symb.fbarray(-1)
desctype = symb.fbarray(symbGetArrayDimensions( sym ))
else
desctype = symbGetSubtype( symbGetArrayDescriptor( sym ) )
end if
Expand Down
10 changes: 5 additions & 5 deletions src/compiler/fb-main.bas
Expand Up @@ -32,15 +32,15 @@ private sub hBuildDllMainWin32( )

'' instance
symbAddProcParam( proc, "__FB_DLLINSTANCE__", typeAddrOf( FB_DATATYPE_VOID ), NULL, _
FB_PARAMMODE_BYVAL, 0 )
0, FB_PARAMMODE_BYVAL, 0 )

'' reason
param = symbAddProcParam( proc, "__FB_DLLREASON__", FB_DATATYPE_UINT, NULL, _
FB_PARAMMODE_BYVAL, 0 )
0, FB_PARAMMODE_BYVAL, 0 )

'' reserved
symbAddProcParam( proc, "__FB_DLLRESERVED__", typeAddrOf( FB_DATATYPE_VOID ), NULL, _
FB_PARAMMODE_BYVAL, 0 )
0, FB_PARAMMODE_BYVAL, 0 )

'' function DllMain stdcall( byval instance as any ptr, byval reason as uinteger, _
'' byval reserved as any ptr ) as integer
Expand Down Expand Up @@ -94,11 +94,11 @@ private sub hMainBegin( )

'' byval argc as long
symbAddProcParam( proc, "__FB_ARGC__", FB_DATATYPE_LONG, NULL, _
FB_PARAMMODE_BYVAL, 0 )
0, FB_PARAMMODE_BYVAL, 0 )

'' byval argv as zstring ptr ptr
symbAddProcParam( proc, "__FB_ARGV__", typeMultAddrOf( FB_DATATYPE_CHAR, 2 ), NULL, _
FB_PARAMMODE_BYVAL, 0 )
0, FB_PARAMMODE_BYVAL, 0 )

'' if it's a dll, the main() function should be private
var attrib = FB_SYMBATTRIB_PUBLIC
Expand Down
40 changes: 31 additions & 9 deletions src/compiler/parser-decl-proc-params.bas
Expand Up @@ -192,7 +192,7 @@ private function hMockParam _
dtype = FB_DATATYPE_INTEGER
end if

function = symbAddProcParam( proc, NULL, dtype, NULL, pmode, 0 )
function = symbAddProcParam( proc, NULL, dtype, NULL, iif( pmode = FB_PARAMMODE_BYDESC, -1, 0 ), pmode, 0 )
end function

'':::::
Expand All @@ -209,11 +209,14 @@ private function hParamDecl _
static as integer reclevel = 0
dim as zstring ptr id = any
dim as ASTNODE ptr optexpr = any
dim as integer dtype = any, mode = any
dim as integer attrib = any
dim as integer readid = any, dotpos = any, doskip = any, dontinit = any, use_default = any
dim as integer dtype = any, mode = any, attrib = any, dimensions = any
dim as integer readid = any, dotpos = any, doskip = any, dontinit = any
dim as integer use_default = any, have_bounds = any
dim as FBSYMBOL ptr subtype = any, param = any

'' unused, so overwriting during recursion doesn't matter
static as ASTNODE ptr exprTB(0 to FB_MAXARRAYDIMS-1, 0 to 1)

function = NULL

attrib = 0
Expand Down Expand Up @@ -246,7 +249,7 @@ private function hParamDecl _
end if

return symbAddProcParam( proc, NULL, FB_DATATYPE_INVALID, NULL, _
FB_PARAMMODE_VARARG, 0 )
0, FB_PARAMMODE_VARARG, 0 )

'' syntax error..
else
Expand Down Expand Up @@ -333,15 +336,34 @@ private function hParamDecl _
dtype = FB_DATATYPE_INVALID
end if

dimensions = 0
have_bounds = FALSE

'' '()' array parentheses, '('?
if( lexGetToken( ) = CHAR_LPRNT ) then
lexSkipToken( )
'' Must be followed by ')', and BYVAL/BYREF cannot be used
'' (array() parameters always implicitly are BYDESC)
if( (mode <> INVALID) or (hMatch( CHAR_RPRNT ) = FALSE) ) then

'' BYVAL/BYREF cannot be used; array() parameters always
'' implicitly are BYDESC
if( mode <> INVALID ) then
hParamError( proc, id )
end if
mode = FB_PARAMMODE_BYDESC

'' '()'?
if( lexGetToken( ) = CHAR_RPRNT ) then
dimensions = -1
else
cArrayDecl( dimensions, have_bounds, exprTB() )
if( have_bounds ) then
hParamError( proc, id )
end if
end if

'' ')'
if( hMatch( CHAR_RPRNT ) = FALSE ) then
errReport( FB_ERRMSG_EXPECTEDRPRNT )
end if
end if

use_default = FALSE
Expand Down Expand Up @@ -461,7 +483,7 @@ private function hParamDecl _

'' Add new param
param = symbAddProcParam( proc, iif( isproto, cptr( zstring ptr, NULL ), id ), _
dtype, subtype, mode, attrib )
dtype, subtype, dimensions, mode, attrib )
if( param = NULL ) then
exit function
end if
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/parser-decl-var.bas
Expand Up @@ -384,7 +384,7 @@ private function hAddVar _
end if

if( is_declared ) then
if( symbIsDynamic( sym ) ) then
if( symbGetIsDynamic( sym ) ) then
symbCheckDynamicArrayDimensions( sym, dimensions )
end if
else
Expand Down
6 changes: 2 additions & 4 deletions src/compiler/parser-expr-variable.bas
Expand Up @@ -837,9 +837,7 @@ private function cDynamicArrayIndex _
'' No longer needed, all places using it should have cloned
astDelTree( descexpr )

if( symbIsDynamic( sym ) ) then
symbCheckDynamicArrayDimensions( sym, dimension + 1 )
end if
symbCheckDynamicArrayDimensions( sym, dimension + 1 )

function = expr
end function
Expand Down Expand Up @@ -990,7 +988,7 @@ function cVariableEx overload _
if( symbIsParamBydesc( sym ) ) then
'' Build a VAR access with the BYDESC param's real dtype
descexpr = astNewVAR( sym )
astSetType( descexpr, typeAddrOf( FB_DATATYPE_STRUCT ), symb.fbarray(-1) )
astSetType( descexpr, typeAddrOf( FB_DATATYPE_STRUCT ), symb.fbarray(symbGetArrayDimensions( sym )) )

'' And DEREF to get to the descriptor
descexpr = astNewDEREF( descexpr )
Expand Down
19 changes: 14 additions & 5 deletions src/compiler/parser-proc.bas
Expand Up @@ -188,7 +188,7 @@ private function hCheckPrototype _
exit function
end if

'' check each arg
'' check each param
for i = 1 to params
dim as integer dtype = symbGetFullType( proto_param )

Expand All @@ -211,12 +211,21 @@ private function hCheckPrototype _
end if
end if

'' and mode
if( param->param.mode <> symbGetParamMode( proto_param ) ) then
'' and mode
if( param->param.mode <> proto_param->param.mode ) then
hParamError( proc, i )
'' no error recovery: ditto
exit function
end if
exit function
end if

'' Different BYDESC dimensions?
'' (even if one is unknown, both should be unknown)
if( param->param.mode = FB_PARAMMODE_BYDESC ) then
if( param->param.bydescdimensions <> proto_param->param.bydescdimensions ) then
hParamError( proc, i )
exit function
end if
end if

'' check names and change to the new one if needed
if( param->param.mode <> FB_PARAMMODE_VARARG ) then
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/parser-proccall.bas
Expand Up @@ -1107,7 +1107,7 @@ function hForwardCall( ) as integer
dtype = FB_DATATYPE_STRING
end select

if( symbAddProcParam( proc, NULL, dtype, NULL, mode, 0 ) = NULL ) then
if( symbAddProcParam( proc, NULL, dtype, NULL, iif( mode = FB_PARAMMODE_BYDESC, -1, 0 ), mode, 0 ) = NULL ) then
exit do
end if

Expand Down
4 changes: 2 additions & 2 deletions src/compiler/rtl.bas
Expand Up @@ -188,7 +188,7 @@ sub rtlAddIntrinsicProcs( byval procdef as const FB_RTL_PROCDEF ptr )
inner_attrib = 0
end if

param = symbAddProcParam( inner_proc, NULL, .dtype, NULL, .mode, inner_attrib )
param = symbAddProcParam( inner_proc, NULL, .dtype, NULL, iif( .mode = FB_PARAMMODE_BYDESC, -1, 0 ), .mode, inner_attrib )
symbMakeParamOptional( inner_proc, param, inner_param_optval )
end with
next
Expand Down Expand Up @@ -228,7 +228,7 @@ sub rtlAddIntrinsicProcs( byval procdef as const FB_RTL_PROCDEF ptr )
dtype = typeAddrOf( FB_DATATYPE_VOID )
end if

param = symbAddProcParam( proc, NULL, dtype, subtype, .mode, attrib )
param = symbAddProcParam( proc, NULL, dtype, subtype, iif( .mode = FB_PARAMMODE_BYDESC, -1, 0 ), .mode, attrib )

if( .check_const ) then
symbSetIsRTLConst( param )
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/symb-comp.bas
Expand Up @@ -58,7 +58,7 @@ private function hDeclareProc _
if( add_rhs ) then
assert( symbIsStruct( udt ) )
symbAddProcParam( proc, "__FB_RHS__", FB_DATATYPE_STRUCT, udt, _
FB_PARAMMODE_BYREF, FB_SYMBATTRIB_NONE )
0, FB_PARAMMODE_BYREF, FB_SYMBATTRIB_NONE )
end if

attrib or= FB_SYMBATTRIB_METHOD
Expand Down

0 comments on commit 831f0c3

Please sign in to comment.