Skip to content

Commit fda0ab2

Browse files
committed
fbc: add support for __FB_EVAL__ wstrings
- internal change to refactor hMacro_EvalZ() - add hMacro_EvalW() - add functions to get internally escaped literal string (constant) to literal text safe to use in fbc source - add declare function symbGetConstStrAsStr( byval s as FBSYMBOL ptr ) as zstring ptr - add declare function symbGetConstStrAsWstr( byval s as FBSYMBOL ptr ) as wstring ptr
1 parent 3442063 commit fda0ab2

File tree

8 files changed

+229
-32
lines changed

8 files changed

+229
-32
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Version 1.09.0
1313
[added]
1414
- fbc: add '-z fbrt' command line option to link against libfbrt*.a instead of libfb*.a
1515
- makefile: add target for fbrt, fb runtime library written in fbc. Bulid libfbrt*.a and merge any missing object modules from libfb*.a
16+
- fbc: add support for wstrings used with __FB_EVAL__()
1617

1718
[fixed]
1819
- github #315: set parameters when calling SCREENCONTROL (was broken in fbc 1.08.0 due to new LONG/LONGINT SCREENCONTROL API's)

src/compiler/symb-const.bas

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include once "hash.bi"
1010
#include once "list.bi"
1111
#include once "ir.bi"
12+
#include once "dstr.bi"
1213

1314
'':::::
1415
function symbAddConst _
@@ -310,3 +311,84 @@ function symbCloneConst( byval sym as FBSYMBOL ptr ) as FBSYMBOL ptr
310311
function = symbAddConst( NULL, symbGetType( sym ), symbGetSubtype( sym ), _
311312
symbGetConstVal( sym ), symbGetAttrib( sym ) )
312313
end function
314+
315+
function symbGetConstStrAsStr( byval s as FBSYMBOL ptr ) as zstring ptr
316+
317+
assert( (symbGetType( s ) = FB_DATATYPE_CHAR) _
318+
or (symbGetType( s ) = FB_DATATYPE_WCHAR) )
319+
320+
static as DZSTRING res
321+
322+
DZStrAssign( res, NULL )
323+
324+
'' ASCII to ASCII
325+
if( symbGetType( s ) <> FB_DATATYPE_WCHAR ) then
326+
dim textlen as integer
327+
dim text as zstring ptr = hUnescape( symbGetVarLitText( s ), textlen )
328+
if( len(*text) <> textlen ) then
329+
DZStrConcatAssign( res, "!" + QUOTE )
330+
for i as integer = 0 to textlen - 1
331+
DZStrConcatAssign( res, $"\x" & hex( cast( ulong, (*text)[i] ), 2 ) )
332+
next
333+
else
334+
DZStrConcatAssign( res, "$" + QUOTE )
335+
DZStrConcatAssign( res, text )
336+
end if
337+
DZStrConcatAssign( res, QUOTE )
338+
339+
'' WSTRING to ASCII - always escape
340+
else
341+
dim textlen as integer
342+
dim text as wstring ptr = hUnescapeW( symbGetVarLitTextW( s ), textlen )
343+
DZStrConcatAssign( res, "!" + QUOTE )
344+
for i as integer = 0 to textlen - 1
345+
'' !!!FIXME!!! \u escaping assumptions
346+
DZStrConcatAssign( res, $"\u" & hex( cast( ulong, (*text)[i] ), 4 ) )
347+
next
348+
DZStrConcatAssign( res, QUOTE )
349+
end if
350+
351+
return res.data
352+
353+
end function
354+
355+
function symbGetConstStrAsWstr( byval s as FBSYMBOL ptr ) as wstring ptr
356+
357+
assert( (symbGetType( s ) = FB_DATATYPE_CHAR) _
358+
or (symbGetType( s ) = FB_DATATYPE_WCHAR) )
359+
360+
static as DWSTRING res
361+
362+
DWStrAssign( res, NULL )
363+
364+
'' WSTRING to WSTRING
365+
if( symbGetType( s ) = FB_DATATYPE_WCHAR ) then
366+
dim textlen as integer
367+
dim text as wstring ptr = hUnescapeW( symbGetVarLitTextW( s ), textlen )
368+
if( len(*text) <> textlen ) then
369+
DWStrConcatAssign( res, "!" + QUOTE )
370+
for i as integer = 0 to textlen - 1
371+
'' !!!FIXME!!! \u escaping assumptions
372+
DWStrConcatAssign( res, $"\u" & hex( cast( ulong, (*text)[i] ), 4 ) )
373+
next
374+
else
375+
DWStrConcatAssign( res, "$" + QUOTE )
376+
DWStrConcatAssign( res, text )
377+
end if
378+
DWStrConcatAssign( res, QUOTE )
379+
380+
'' ASCII to WSTRING? escape everything, it's easier.
381+
else
382+
dim textlen as integer
383+
dim text as zstring ptr = hUnescape( symbGetVarLitText( s ), textlen )
384+
DWStrConcatAssign( res, "!" + QUOTE )
385+
for i as integer = 0 to textlen - 1
386+
'' !!!FIXME!!! \u escaping assumptions
387+
DWStrConcatAssign( res, $"\u" & hex( cast( ulong, (*text)[i] ), 4 ) )
388+
next
389+
DWStrConcatAssign( res, QUOTE )
390+
end if
391+
392+
return res.data
393+
394+
end function

src/compiler/symb-define.bas

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ private function hMacro_EvalZ( byval arg as zstring ptr ) as string
240240

241241
'' the expression should have already been handled in hLoadMacro|hLoadMacroW
242242
'' so, if we do get here, just pass the argument back as-is
243+
'' !!!TODO!!! - DZSTRING can be replaced by STRING
243244
dim as DZSTRING res
244245
DZStrAssign( res, NULL )
245246

@@ -284,41 +285,12 @@ private function hMacro_EvalZ( byval arg as zstring ptr ) as string
284285
errmsg = FB_ERRMSG_SYNTAXERROR
285286
end if
286287
elseif( astIsConstant( expr ) ) then
287-
'' !!!TODO!!! refactor in to procedures
288-
if( symbGetType( expr->sym ) <> FB_DATATYPE_WCHAR ) then
289-
dim textlen as integer
290-
dim text as zstring ptr = hUnescape( symbGetVarLitText( expr->sym ), textlen )
291-
if( len(*text) <> textlen ) then
292-
dim tmp as string
293-
for i as integer = 1 to textlen
294-
tmp &= $"\x" & hex( asc( *text, i ), 2 )
295-
next
296-
DZStrConcatAssign( res, "!" + QUOTE )
297-
DZStrConcatAssign( res, strptr(tmp) )
298-
DZStrConcatAssign( res, QUOTE )
299-
else
300-
DZStrConcatAssign( res, "$" + QUOTE )
301-
DZStrConcatAssign( res, text )
302-
DZStrConcatAssign( res, QUOTE )
303-
end if
304-
else
305-
'' WSTRING to ASCII? always escape.
306-
dim textlen as integer
307-
dim text as wstring ptr = hUnescapeW( symbGetVarLitTextW( expr->sym ), textlen )
308-
dim tmp as string
309-
for i as integer = 0 to textlen - 1
310-
tmp &= $"\u" & hex( cast( ulong, text[i] ), 4 )
311-
next
312-
'' Careful - wstring literal pasted into an ascii lexer stream
313-
DZStrConcatAssign( res, "!" + QUOTE )
314-
DZStrConcatAssign( res, strptr(tmp) )
315-
DZStrConcatAssign( res, QUOTE )
316-
end if
317-
288+
DZStrAssign( res, symbGetConstStrAsStr( expr->sym ) )
318289
'' any tokens still in the buffer? cExpression() should have used them all
319290
if( lexGetToken( ) <> FB_TK_EOL ) then
320291
errmsg = FB_ERRMSG_SYNTAXERROR
321292
end if
293+
astDelTree( expr )
322294
else
323295
astDelTree( expr )
324296
errmsg = FB_ERRMSG_EXPECTEDCONST
@@ -344,6 +316,88 @@ private function hMacro_EvalZ( byval arg as zstring ptr ) as string
344316

345317
end function
346318

319+
private function hMacro_EvalW( byval arg as wstring ptr ) as wstring ptr
320+
321+
'' the expression should have already been handled in hLoadMacro|hLoadMacroW
322+
'' so, if we do get here, just pass the argument back as-is
323+
'' !!!TODO!!! - We must use DWSTRING since we don't have a built-in var-len wstring
324+
'' but, if we did have a var-len wstring, we should use it instead
325+
326+
static as DWSTRING res
327+
DWStrAssign( res, NULL )
328+
329+
if( arg ) then
330+
331+
'' create a lightweight context push for the lexer
332+
'' like an include file, but no named include file
333+
'' - text to expand is to be loaded in LEX.CTX->DEFTEXT[W]
334+
'' - use the parser to build an AST for the literal result
335+
336+
lexPushCtx()
337+
lexInit( FALSE, TRUE )
338+
339+
'' prevent cExpression from writing to .pp.bas file
340+
lex.ctx->reclevel += 1
341+
342+
DWstrAssign( lex.ctx->deftextw, *arg )
343+
lex.ctx->defptrw = lex.ctx->deftextw.data
344+
lex.ctx->deflen += len( *arg )
345+
346+
'' Add an end of expression marker so that the parser
347+
'' doesn't read past the end of the expression text
348+
'' by appending an LFCHAR to the end of the expression
349+
'' It would be better to use the explicit EOF character,
350+
'' but we can't appened an extra NUL character to a zstring
351+
352+
DWstrConcatAssign( lex.ctx->deftextw, LFCHAR )
353+
lex.ctx->defptrw = lex.ctx->deftextw.data
354+
lex.ctx->deflen += len( LFCHAR )
355+
356+
dim expr as ASTNODE ptr = cExpression( )
357+
var errmsg = FB_ERRMSG_OK
358+
359+
if( expr <> NULL ) then
360+
expr = astOptimizeTree( expr )
361+
362+
if( astIsCONST( expr ) ) then
363+
DWStrAssign( res, astConstFlushToWstr( expr ) )
364+
365+
'' any tokens still in the buffer? cExpression() should have used them all
366+
if( lexGetToken( ) <> FB_TK_EOL ) then
367+
errmsg = FB_ERRMSG_SYNTAXERROR
368+
end if
369+
elseif( astIsConstant( expr ) ) then
370+
DWStrAssign( res, symbGetConstStrAsWstr( expr->sym ) )
371+
'' any tokens still in the buffer? cExpression() should have used them all
372+
if( lexGetToken( ) <> FB_TK_EOL ) then
373+
errmsg = FB_ERRMSG_SYNTAXERROR
374+
end if
375+
astDelTree( expr )
376+
else
377+
astDelTree( expr )
378+
errmsg = FB_ERRMSG_EXPECTEDCONST
379+
DWStrAssign( res, !"\u0000" )
380+
end if
381+
else
382+
errmsg = FB_ERRMSG_SYNTAXERROR
383+
end if
384+
385+
lex.ctx->reclevel -= 1
386+
387+
lexPopCtx()
388+
389+
if( errmsg <> FB_ERRMSG_OK ) then
390+
errReportEx( errmsg, *arg )
391+
'' error recovery: skip until next line (in the buffer)
392+
hSkipUntil( FB_TK_EOL, TRUE )
393+
end if
394+
395+
end if
396+
397+
function = res.data
398+
399+
end function
400+
347401
private function hDefUniqueIdPush_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string
348402

349403
'' __FB_UNIQUEID_PUSH__( STACKID )
@@ -768,6 +822,21 @@ private function hDefEvalZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as i
768822

769823
end function
770824

825+
private function hDefEvalW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as wstring ptr
826+
827+
'' __FB_EVAL__( arg )
828+
829+
'' the expression should have already been handled in hLoadMacro|hLoadMacroW
830+
'' so, if we do get here, just pass the argument back as-is
831+
832+
var arg = hMacro_getArgW( argtb, 0 )
833+
static as DWSTRING res
834+
DWstrAssign( res, hMacro_EvalW( arg ) )
835+
836+
function = res.data
837+
838+
end function
839+
771840

772841
'' Intrinsic #defines which are always defined
773842
dim shared defTb(0 to ...) as SYMBDEF => _
@@ -833,7 +902,7 @@ dim shared macroTb(0 to ...) as SYMBMACRO => _
833902
(@"__FB_JOIN__" , 0 , @hDefJoinZ_cb , @hDefJoinW_cb , 2, { (@"L"), (@"R") } ), _
834903
(@"__FB_QUOTE__" , 0 , @hDefQuoteZ_cb , @hDefQuoteW_cb , 1, { (@"ARG") } ), _
835904
(@"__FB_UNQUOTE__" , 0 , @hDefUnquoteZ_cb , @hDefUnquoteW_cb , 1, { (@"ARG") } ), _
836-
(@"__FB_EVAL__" , 0 , @hDefEvalZ_cb , NULL , 1, { (@"ARG") } ) _
905+
(@"__FB_EVAL__" , 0 , @hDefEvalZ_cb , @hDefEvalW_cb , 1, { (@"ARG") } ) _
837906
}
838907

839908
sub symbDefineInit _

src/compiler/symb.bi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,8 @@ declare function symbReuseOrAddConst _
12521252
) as FBSYMBOL ptr
12531253

12541254
declare function symbGetConstValueAsStr( byval s as FBSYMBOL ptr ) as string
1255+
declare function symbGetConstStrAsStr( byval s as FBSYMBOL ptr ) as zstring ptr
1256+
declare function symbGetConstStrAsWstr( byval s as FBSYMBOL ptr ) as wstring ptr
12551257

12561258
declare function symbStructBegin _
12571259
( _
4.88 KB
Binary file not shown.

tests/pp/macro-eval-str.bas

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ SUITE( fbc_tests.pp.macro_eval_str )
1010
CU_ASSERT_EQUAL( "A" + !"\0" + "B", __FB_EVAL__( "A" + !"\0" + "B" ) )
1111
CU_ASSERT_EQUAL( !"\\" + "\" + !"\\", __FB_EVAL__( !"\\" + "\" + !"\\" ) )
1212

13+
CU_ASSERT_EQUAL( wstr(""), __FB_EVAL__( wstr("") ) )
14+
CU_ASSERT_EQUAL( wstr("A"), __FB_EVAL__( wstr("A") ) )
15+
CU_ASSERT_EQUAL( wstr("A") + wstr("B"), __FB_EVAL__( wstr("A") + wstr("B") ) )
16+
CU_ASSERT_EQUAL( wstr("A") + wstr(!"\0"), __FB_EVAL__( wstr("A") + wstr(!"\0") ) )
17+
CU_ASSERT_EQUAL( wstr("A") + wstr(!"\0") + wstr("B"), __FB_EVAL__( wstr("A") + wstr(!"\0") + wstr("B") ) )
18+
CU_ASSERT_EQUAL( wstr(!"\\") + wstr("\") + wstr(!"\\"), __FB_EVAL__( wstr(!"\\") + wstr("\") + wstr(!"\\") ) )
19+
1320
END_TEST
1421

1522
TEST( nulchar )

tests/string/asc-utf16le.bas

4.43 KB
Binary file not shown.

tests/string/asc.bas

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,40 @@ SUITE( fbc_tests.string_.asc_ )
6666

6767
END_TEST
6868

69+
TEST( const_wstr_ )
70+
scope
71+
const S = wstr("")
72+
CU_ASSERT_EQUAL( asc(s, 0 ), 0 )
73+
CU_ASSERT_EQUAL( asc(s, 1 ), 0 )
74+
CU_ASSERT_EQUAL( asc(s, 2 ), 0 )
75+
end scope
76+
77+
scope
78+
const S = wstr("AB")
79+
CU_ASSERT_EQUAL( asc(s, 0 ), 0 )
80+
CU_ASSERT_EQUAL( asc(s, 1 ), 65 )
81+
CU_ASSERT_EQUAL( asc(s, 2 ), 66 )
82+
CU_ASSERT_EQUAL( asc(s, 3 ), 0 )
83+
end scope
84+
85+
scope
86+
const S = wstr(!"A\000B")
87+
CU_ASSERT_EQUAL( asc(s, 0 ), 0 )
88+
CU_ASSERT_EQUAL( asc(s, 1 ), 65 )
89+
CU_ASSERT_EQUAL( asc(s, 2 ), 0 )
90+
CU_ASSERT_EQUAL( asc(s, 3 ), 66 )
91+
CU_ASSERT_EQUAL( asc(s, 4 ), 0 )
92+
end scope
93+
94+
scope
95+
const S = wstr(!"\u1111\u0000\u2222")
96+
CU_ASSERT_EQUAL( asc(s, 0 ), 0 )
97+
CU_ASSERT_EQUAL( asc(s, 1 ), &h1111 )
98+
CU_ASSERT_EQUAL( asc(s, 2 ), 0 )
99+
CU_ASSERT_EQUAL( asc(s, 3 ), &h2222 )
100+
CU_ASSERT_EQUAL( asc(s, 4 ), 0 )
101+
end scope
102+
103+
END_TEST
104+
69105
END_SUITE

0 commit comments

Comments
 (0)