Posts: 68
Threads: 11
Joined: Apr 2022
Reputation:
5
01-20-2026, 04:37 AM
Hello,
I've three little questions :
qb64pe translates its basic code (.bas) into C++ code (.cpp) witch then is compiled using GCC (or Mingw with windows).
1) what tool use qb64pe to translate the .bas code to the .cpp code (e.g. BaCon, NBCX, etc) ?
2) should I still use a specific parameter (-z) when I start qb64pe from the command line to save the .cpp translation ?
3) where (in what qb64pe sub directory) can I find the translated .ccp file to take a look at its C++ translation : i.e. hello.bas -> hello.cpp ?
TIA for your response.
Cheers.
Fifi
Before to send the arrow of truth, dip the head in a honey pot (Cheyenne saying).
Don't tell my Mom I'm on iMac with macOS, she thinks I work on PC with Windows.
Posts: 346
Threads: 45
Joined: Jun 2024
Reputation:
32
- [b]1) Translator Tool[/b]: QB64-PE does not use external tools like BaCon or BCX. It uses its [b]own internal translator[/b] built directly into the QB64-PE executable. This built-in engine parses the BASIC source and generates the equivalent C++ code before passing it to the MinGW-w64 (GCC) compiler.
- [b]2) Command Line Parameter[/b]: Yes, you can use the
[b][/b] parameter.
- Running
Code: (Select All) qb64pe -z yourfile.bas
performs the first compile pass (syntax checking and C++ code generation) without opening the IDE or creating a final executable.
- Standard compilation using
or
will also generate these files as part of the normal build process.
- [b]3) Directory for Translated Files[/b]: You can find the generated files in the
Code: (Select All) internal/temp
[b][/b] sub-directory within your main QB64-PE folder.
Code: (Select All) main.txt
[b][/b]: This file contains the actual C++ translation of your BASIC code.
Code: (Select All) qbx.cpp
[b][/b]: This is the core C++ wrapper that includes your code and the QB64 runtime libraries.
Code: (Select All) recompile.bat
[b][/b]: A batch file that contains the exact GCC command line used to compile the program.
Now, I KNOW people hate AI but please just ask Google!
Unseen
Posts: 68
Threads: 11
Joined: Apr 2022
Reputation:
5
(01-20-2026, 06:08 AM)Unseen Machine Wrote: - [b]1) Translator Tool[/b]: QB64-PE does not use external tools like BaCon or BCX. It uses its [b]own internal translator[/b] built directly into the QB64-PE executable. This built-in engine parses the BASIC source and generates the equivalent C++ code before passing it to the MinGW-w64 (GCC) compiler.
Unseen
Hi Unseen machine.
May you tell me where is the qb64pe source I can take a look at the translator part ?
Just currious.
Before to send the arrow of truth, dip the head in a honey pot (Cheyenne saying).
Don't tell my Mom I'm on iMac with macOS, she thinks I work on PC with Windows.
Posts: 3,446
Threads: 376
Joined: Apr 2022
Reputation:
345
(01-21-2026, 10:19 AM)Fifi Wrote: (01-20-2026, 06:08 AM)Unseen Machine Wrote: - [b]1) Translator Tool[/b]: QB64-PE does not use external tools like BaCon or BCX. It uses its [b]own internal translator[/b] built directly into the QB64-PE executable. This built-in engine parses the BASIC source and generates the equivalent C++ code before passing it to the MinGW-w64 (GCC) compiler.
Unseen
Hi Unseen machine.
May you tell me where is the qb64pe source I can take a look at the translator part ?
Just currious.
Qb64pe.bas
Posts: 68
Threads: 11
Joined: Apr 2022
Reputation:
5
01-21-2026, 12:27 PM
(This post was last modified: 01-21-2026, 12:32 PM by Fifi.)
(01-21-2026, 10:57 AM)SMcNeill Wrote: Qb64pe.bas Hi SMcNeill,
Yes, I do assume it's in qb64pe.bas, but there are so few comments that I don't know where to look.
BTW, I've never seen such a long source code with so few comments, and I give the developers my two thumbs up for maintaining and improving this program!
So, could you tell me the line number in qb64pe.bas where the Basic keyword translator begins?
For example, where can I find the translation of QB64PE keywords, such as "Print" or "Input," etc., into their C++ equivalents?
Is there, for instance, a conversion table listing all the QB64 keywords and their respective C++ translations?
Just out of curiosity.
Cheers.
Fifi
Before to send the arrow of truth, dip the head in a honey pot (Cheyenne saying).
Don't tell my Mom I'm on iMac with macOS, she thinks I work on PC with Windows.
Posts: 3,446
Threads: 376
Joined: Apr 2022
Reputation:
345
(01-21-2026, 12:27 PM)Fifi Wrote: (01-21-2026, 10:57 AM)SMcNeill Wrote: Qb64pe.bas Hi SMcNeill,
Yes, I do assume it's in qb64pe.bas, but there are so few comments that I don't know where to look.
BTW, I've never seen such a long source code with so few comments, and I give the developers my two thumbs up for maintaining and improving this program!
So, could you tell me the line number in qb64pe.bas where the Basic keyword translator begins?
For example, where can I find the translation of QB64PE keywords, such as "Print" or "Input," etc., into their C++ equivalents?
Is there, for instance, a conversion table listing all the QB64 keywords and their respective C++ translations?
Just out of curiosity.
Cheers.
Fifi
It's.... the whole thing. And all the subdirectories and help files all added in as well. For example, if you want PRINT, do a search for:
firstelement$ = "PRINT"
Code: (Select All) If firstelement$ = "PRINT" Then 'file print
If n > 1 Then
If getelement$(a$, 2) = "#" Then
xfileprint a$, ca$, n
If Error_Happened Then GoTo errmes
l$ = tlayout$
layoutdone = 1: If Len(layout$) Then layout$ = layout$ + sp + l$ Else layout$ = l$
GoTo finishedline
End If '#
End If 'n>1
End If '"print"
If firstelement$ = "PRINT" Or firstelement$ = "LPRINT" Then
If secondelement$ <> "USING" Then 'check to see if we need to auto-add semicolons
elementon = 2
redosemi:
For i = elementon To n - 1
nextchar$ = getelement$(a$, i + 1)
If nextchar$ <> ";" And nextchar$ <> "," And nextchar$ <> "+" And nextchar$ <> ")" Then
temp1$ = getelement$(a$, i)
beginpoint = InStr(beginpoint, temp1$, Chr$(34))
endpoint = InStr(beginpoint + 1, temp1$, Chr$(34) + ",")
If beginpoint <> 0 And endpoint <> 0 Then 'if we have both positions
'Quote without semicolon check (like PRINT "abc"123)
textlength = endpoint - beginpoint - 1
textvalue$ = Mid$(temp1$, endpoint + 2, Len(_ToStr$(textlength)))
If Val(textvalue$) = textlength Then
insertelements a$, i, ";"
insertelements ca$, i, ";"
n = n + 1
elementon = i + 2 'just an easy way to reduce redundant calls to the routine
GoTo redosemi
End If
End If
If temp1$ <> "USING" Then
If Left$(LTrim$(nextchar$), 1) = Chr$(34) Then
If temp1$ <> ";" And temp1$ <> "," And temp1$ <> "+" And temp1$ <> "(" Then
insertelements a$, i, ";"
insertelements ca$, i, ";"
n = n + 1
elementon = i + 2 'just an easy way to reduce redundant calls to the routine
GoTo redosemi
End If
End If
End If
End If
Next
End If
xprint a$, ca$, n
If Error_Happened Then GoTo errmes
l$ = tlayout$
layoutdone = 1: If Len(layout$) Then layout$ = layout$ + sp + l$ Else layout$ = l$
GoTo finishedline
End If
Then you can see that if you're dealing with a file being printed, the first IF deals with that and sends off the translation to: xfileprint a$, ca$, n
For the screen printing, that's done in the next statement and it gets handed off to xprint a$, ca$, n
If you want to look at xprint, here it is:
Code: (Select All) Sub xprint (a$, ca$, n)
u$ = _ToStr$(uniquenumber)
l$ = SCase$("Print")
If Asc(a$) = 76 Then lp = 1: lp$ = "l": l$ = SCase$("LPrint"): WriteBufLine MainTxtBuf, "tab_LPRINT=1;": SetDependency DEPENDENCY_PRINTER '"L"
'PRINT USING?
If n >= 2 Then
If getelement(a$, 2) = "USING" Then
'get format string
i = 3
pujump:
l$ = l$ + sp + SCase$("Using")
e$ = "": b = 0: puformat$ = ""
For i = i To n
a2$ = getelement(ca$, i)
If a2$ = "(" Then b = b + 1
If a2$ = ")" Then b = b - 1
If b = 0 Then
If a2$ = "," Then Give_Error "Expected PRINT USING formatstring ; ...": Exit Sub
If a2$ = ";" Then
e$ = fixoperationorder$(e$)
If Error_Happened Then Exit Sub
l$ = l$ + sp + tlayout$ + sp2 + ";"
e$ = evaluate(e$, typ)
If Error_Happened Then Exit Sub
If (typ And ISREFERENCE) Then e$ = refer(e$, typ, 0)
If Error_Happened Then Exit Sub
If (typ And ISSTRING) = 0 Then Give_Error "Expected PRINT USING formatstring ; ...": Exit Sub
puformat$ = e$
Exit For
End If ';
End If 'b
If Len(e$) Then e$ = e$ + sp + a2$ Else e$ = a2$
Next
If puformat$ = "" Then Give_Error "Expected PRINT USING formatstring ; ...": Exit Sub
If i = n Then Give_Error "Expected PRINT USING formatstring ; ...": Exit Sub
'create build string
If TQBSset = 0 Then
WriteBufLine MainTxtBuf, "tqbs=qbs_new(0,0);"
Else
WriteBufLine MainTxtBuf, "qbs_set(tqbs,qbs_new_txt_len(" + Chr$(34) + Chr$(34) + ",0));"
End If
'set format start/index variable
WriteBufLine MainTxtBuf, "tmp_long=0;" 'scan format from beginning
'create string to hold format in for multiple references
puf$ = "print_using_format" + u$
If subfunc = "" Then
WriteBufLine DataTxtBuf, "static qbs *" + puf$ + ";"
Else
WriteBufLine DataTxtBuf, "qbs *" + puf$ + ";"
End If
WriteBufLine MainTxtBuf, puf$ + "=qbs_new(0,0); qbs_set(" + puf$ + "," + puformat$ + ");"
WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip_pu" + u$ + ";"
'print expressions
b = 0
e$ = ""
last = 0
For i = i + 1 To n
a2$ = getelement(ca$, i)
If a2$ = "(" Then b = b + 1
If a2$ = ")" Then b = b - 1
If b = 0 Then
If a2$ = ";" Or a2$ = "," Then
printulast:
e$ = fixoperationorder$(e$)
If Error_Happened Then Exit Sub
If last Then l$ = l$ + sp + tlayout$ Else l$ = l$ + sp + tlayout$ + sp2 + a2$
e$ = evaluate(e$, typ)
If Error_Happened Then Exit Sub
If (typ And ISREFERENCE) Then e$ = refer(e$, typ, 0)
If Error_Happened Then Exit Sub
If typ And ISSTRING Then
If Left$(e$, 9) = "func_tab(" Or Left$(e$, 9) = "func_spc(" Then
'TAB/SPC exception
'note: position in format-string must be maintained
'-print any string up until now
WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(tqbs,0);"
'-print e$
WriteBufLine MainTxtBuf, "qbs_set(tqbs," + e$ + ");"
WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip_pu" + u$ + ";"
If lp Then WriteBufLine MainTxtBuf, "lprint_makefit(tqbs);" Else WriteBufLine MainTxtBuf, "makefit(tqbs);"
WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(tqbs,0);"
'-set length of tqbs to 0
WriteBufLine MainTxtBuf, "tqbs->len=0;"
Else
'regular string
WriteBufLine MainTxtBuf, "tmp_long=print_using(" + puf$ + ",tmp_long,tqbs," + e$ + ");"
End If
Else 'not a string
If typ And ISFLOAT Then
If (typ And 511) = 32 Then WriteBufLine MainTxtBuf, "tmp_long=print_using_single(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
If (typ And 511) = 64 Then WriteBufLine MainTxtBuf, "tmp_long=print_using_double(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
If (typ And 511) > 64 Then WriteBufLine MainTxtBuf, "tmp_long=print_using_float(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
Else
If ((typ And 511) = 64) And (typ And ISUNSIGNED) <> 0 Then
WriteBufLine MainTxtBuf, "tmp_long=print_using_uinteger64(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
Else
WriteBufLine MainTxtBuf, "tmp_long=print_using_integer64(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
End If
End If
End If 'string/not string
WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip_pu" + u$ + ";"
e$ = ""
If last Then Exit For
GoTo printunext
End If
End If
If Len(e$) Then e$ = e$ + sp + a2$ Else e$ = a2$
printunext:
Next
If e$ <> "" Then a2$ = "": last = 1: GoTo printulast
WriteBufLine MainTxtBuf, "skip_pu" + u$ + ":"
'check for errors
WriteBufLine MainTxtBuf, "if (is_error_pending()){"
WriteBufLine MainTxtBuf, "g_tmp_long=new_error; new_error=0; qbs_" + lp$ + "print(tqbs,0); new_error=g_tmp_long;"
WriteBufLine MainTxtBuf, "}else{"
If a2$ = "," Or a2$ = ";" Then nl = 0 Else nl = 1 'note: a2$ is set to the last element of a$
WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(tqbs," + _ToStr$(nl) + ");"
WriteBufLine MainTxtBuf, "}"
WriteBufLine MainTxtBuf, "qbs_free(tqbs);"
WriteBufLine MainTxtBuf, "qbs_free(" + puf$ + ");"
WriteBufLine MainTxtBuf, "skip" + u$ + ":"
WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
If lp Then WriteBufLine MainTxtBuf, "tab_LPRINT=0;"
tlayout$ = l$
Exit Sub
End If
End If
'end of print using code
b = 0
e$ = ""
last = 0
WriteBufLine MainTxtBuf, "tqbs=qbs_new(0,0);" 'initialize the temp string
TQBSset = -1 'set the temporary flag so we don't create a temp string twice, in case USING comes after something
For i = 2 To n
a2$ = getelement(ca$, i)
If a2$ = "(" Then b = b + 1
If a2$ = ")" Then b = b - 1
If b = 0 Then
If a2$ = ";" Or a2$ = "," Or UCase$(a2$) = "USING" Then
printlast:
If UCase$(a2$) = "USING" Then
If e$ <> "" Then gotopu = 1 Else i = i + 1: GoTo pujump
End If
If Len(e$) Then
ebak$ = e$
pnrtnum = 0
printnumber:
e$ = fixoperationorder$(e$)
If Error_Happened Then Exit Sub
If pnrtnum = 0 Then
If last Then l$ = l$ + sp + tlayout$ Else l$ = l$ + sp + tlayout$ + sp2 + a2$
End If
e$ = evaluate(e$, typ)
If Error_Happened Then Exit Sub
If (typ And ISSTRING) = 0 Then
'not a string expression!
e$ = "STR$" + sp + "(" + sp + ebak$ + sp + ")" + sp + "+" + sp + Chr$(34) + " " + Chr$(34)
pnrtnum = 1
GoTo printnumber
End If
If (typ And ISREFERENCE) Then e$ = refer(e$, typ, 0)
If Error_Happened Then Exit Sub
WriteBufLine MainTxtBuf, "qbs_set(tqbs," + e$ + ");"
WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
If lp Then WriteBufLine MainTxtBuf, "lprint_makefit(tqbs);" Else WriteBufLine MainTxtBuf, "makefit(tqbs);"
WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(tqbs,0);"
Else
If a2$ = "," Then l$ = l$ + sp + a2$
If a2$ = ";" Then
If Right$(l$, 1) <> ";" Then l$ = l$ + sp + a2$ 'concat ;; to ;
End If
End If 'len(e$)
If a2$ = "," Then WriteBufLine MainTxtBuf, "tab();"
e$ = ""
If gotopu Then i = i + 1: GoTo pujump
If last Then
WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(nothingstring,1);" 'go to new line
Exit For
End If
GoTo printnext
End If 'a2$
End If 'b=0
If Len(e$) Then e$ = e$ + sp + a2$ Else e$ = a2$
printnext:
Next
If Len(e$) Then a2$ = "": last = 1: GoTo printlast
If n = 1 Then WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(nothingstring,1);"
WriteBufLine MainTxtBuf, "skip" + u$ + ":"
WriteBufLine MainTxtBuf, "qbs_free(tqbs);"
WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
If lp Then WriteBufLine MainTxtBuf, "tab_LPRINT=0;"
tlayout$ = l$
End Sub
As you can see, it does a ton of WriteBufLine calls -- those are where the translation is taking place and it's writing to the translation buffer, which it only saves to disk before actually compiling to reduce wear and tear on any SSD drives.
If you look in subs_functions.bas, you'll see where a lot of the commands that can be almost directly processed are located. These are all handled via QB64PE's own internal language/syntax, which takes a bit to learn and sort out.
Code: (Select All) clearid
id.n = "Sin"
id.subfunc = 1
id.callname = "std::sin"
id.args = 1
id.arg = MKL$(FLOATTYPE - ISPOINTER)
id.ret = FLOATTYPE - ISPOINTER
id.hr_syntax = "SIN(radian_angle!)"
regid
clearid
id.n = "Cos"
id.subfunc = 1
id.callname = "std::cos"
id.args = 1
id.arg = MKL$(FLOATTYPE - ISPOINTER)
id.ret = FLOATTYPE - ISPOINTER
id.hr_syntax = "COS(radian_angle!)"
regid
clearid
id.n = "Tan"
id.subfunc = 1
id.callname = "std::tan"
id.args = 1
id.arg = MKL$(FLOATTYPE - ISPOINTER)
id.ret = FLOATTYPE - ISPOINTER
id.hr_syntax = "TAN(radian_angle!)"
regid
clearid
id.n = "Atn"
id.subfunc = 1
id.callname = "std::atan"
id.args = 1
id.arg = MKL$(FLOATTYPE - ISPOINTER)
id.ret = FLOATTYPE - ISPOINTER
id.hr_syntax = "ATN(tangent!)"
regid
id.n is the QB64 keyword name.
id.subfunc tells us if it's a SUB or FUNCTION and whether to expect a return value or not.
id.callname is the C-translated name which you'll find in libqb.cpp or one of the subfolders there.
id.args is the number of parameters which we're going to pass
id.arg is the type of parameters we're passing
id.ret is the type of value we're getting back
id.hr_syntax is the help row syntax which shows up as you're typing to help you remember what the command's syntax is quickly.
regid then registers that command for processing.
So you type ATN(.1), it gets translated to std:atan(1).
So not only are you looking in qb64pe.bas, but also in libqb.cpp and all the subfolders attached to it, to process your single line translation.
It's the whole thing, scattered in 50 different areas, and all working together to process each command independently.
Posts: 68
Threads: 11
Joined: Apr 2022
Reputation:
5
(01-21-2026, 01:11 PM)SMcNeill Wrote: It's.... the whole thing. And all the subdirectories and help files all added in as well.
So not only are you looking in qb64pe.bas, but also in libqb.cpp and all the subfolders attached to it, to process your single line translation.
It's the whole thing, scattered in 50 different areas, and all working together to process each command independently. Thank you for this detailed explanation.
I now understand how difficult it is to maintain and improve qb64pe, as well as to find and motivate new developers.
Once again, a big thank you to the developers!
Cheers.
Fifi
Before to send the arrow of truth, dip the head in a honey pot (Cheyenne saying).
Don't tell my Mom I'm on iMac with macOS, she thinks I work on PC with Windows.
|