Hi guys,
i am very dissatisfied with the macro handling in case of error.
The debugger only shows the code line of the macro call. It would be more helpful if the error was displayed directly in the affected macro.
With nested macros that go into depth, one is totally helpless in debugging.
Besides, it disturbs my programming aesthetics enormously, if I have to place macros at positions in the code, where I don't want them at all (somewhere in the code, but BEFORE (ineffective 1-pass compiler) the first use).
Exactly the same way you could do without "Declare" if you had a simple 2-pass compiler.
Macro-Errorhandling
Re: Macro-Errorhandling
After the macros are expanded the compiler and especially the debugger don't have the slightest idea they ever existed.
Calling a two pass compiler "simple" is highly subjective. True the declares are a PITA sometimes (unless they are defining a public interface as in the case of modules) but being a single pass compiler it's half of the reasons why the PC compiler is so fast, and to me that's at the top of the list of its selling points.Exactly the same way you could do without "Declare" if you had a simple 2-pass compiler.
"Have you tried turning it off and on again ?"
A little PureBasic review
A little PureBasic review
Re: Macro-Errorhandling
Beside the two-pass compiler question, I also would like to have a better error handling of macros. In case of an error within the macro I find out where it was called, but finding the exact faulty line is a bit of work.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Re: Macro-Errorhandling
I thought about a PB tool to let the compiler help us, here is what I came-up with.
Please read remarks also, it's more an idea instead of a finished product.
Example:
Please read remarks also, it's more an idea instead of a finished product.
Code: Select all
;/--------------------------------
;| Tool to help debugging Macro errors
;|
;| (c)HeX0R 2023
;|
;|
;| PB Tool Settings:
;| Commandline: Path + Filename of tool
;| Arguments: "%TEMPFILE" "%COMPILEFILE"
;| Working Directory:
;| Name: as you like
;| Trigger Event: Before Compile/Run
;| Wait until tool quits: [x]
;| Run Hidden: [ ]
;| Hide Editor: [x]
;|
;| Usage
;| The tool doesn't do anything, as long as it doesn't find the following comment somewhere at the top of the current source code
;| ;expandmacros
;|
;| When it finds that, it will interrupt compilation process and:
;| 1.) creates one large source code containing all includes and macros expanded
;| 2.) Open-up the external PB debugger to debug that huge source code
;| 3.) It will then show, where errors really happened
;|
;| Some bad things:
;| 1.) When the external debugger is finished, PB will go on with its own compilation and debugging process.
;| There doesn't seem to be any possibility to interrupt that (thought about ending with an End -1 or something, but that doesn't work)
;| 2.) Since the Macros are expanded within the source codes, you might have difficulties to recognize to which Macro the code really belongs
;| Would be cool, when the compiler would add the Macro name as comment, when using /PREPROCESS
;|
;| ToDo:
;| 1.) change extensions to support also other OS then Windows
;| 2.) error handling from compiler
;/--------------------------------
Procedure main()
Protected FileOut$, FileIn$, Compiler$, Line$, Commands$, Project$, tmpOut$, tmpExe$, Debugger$
Protected ExpandMacros, PID, Start
FileIn$ = ProgramParameter(0)
FileOut$ = ProgramParameter(1)
tmpExe$ = GetTemporaryDirectory() + "zzz_PB_Output.exe"
Compiler$ = GetEnvironmentVariable("PB_TOOL_Compiler")
Debugger$ = GetPathPart(Compiler$) + "PBDebugger.exe"
If FileIn$ And Compiler$
If ReadFile(0, FileIn$, #PB_UTF8)
ReadStringFormat(0)
While Eof(0) = 0
Line$ = ReadString(0)
If FindString(Line$, ";expandmacros", 1, #PB_String_NoCase) = 1
ExpandMacros = #True
ElseIf ExpandMacros
If FindString(Line$, "; IDE Options = PureBasic", 1, #PB_String_NoCase) = 1
Start = #True
ElseIf Start
If FindString(Line$, "; Optimizer", 1, #PB_String_NoCase) = 1
Commands$ + " /OPTIMIZER"
EndIf
If FindString(Line$, "; EnableThread", 1, #PB_String_NoCase) = 1
Commands$ + " /THREAD"
EndIf
If FindString(Line$, "; EnableXP", 1, #PB_String_NoCase) = 1
Commands$ + " /XP"
EndIf
If FindString(Line$, "; EnableAdmin", 1, #PB_String_NoCase) = 1
Commands$ + " /ADMINISTRATOR"
EndIf
If FindString(Line$, "; DPIAware", 1, #PB_String_NoCase) = 1
Commands$ + " /DPIAWARE"
EndIf
If FindString(Line$, "; EnableOnError", 1, #PB_String_NoCase) = 1
Commands$ + " /LINENUMBERING"
EndIf
If FindString(Line$, "; SubSystem", 1, #PB_String_NoCase) = 1
Commands$ + " /SUBSYSTEM " + #DQUOTE$ + Trim(StringField(Line$, 2, "=")) + #DQUOTE$
EndIf
If FindString(Line$, "; EnableCompileCount", 1, #PB_String_NoCase) = 1
Commands$ + " /CONSTANT " + #DQUOTE$ + "PB_Editor_CompileCount=" + Trim(StringField(Line$, 2, "=")) + #DQUOTE$
EndIf
If FindString(Line$, "; EnableBuildCount", 1, #PB_String_NoCase) = 1
Commands$ + " /CONSTANT " + #DQUOTE$ + "PB_Editor_BuildCount=" + Trim(StringField(Line$, 2, "=")) + #DQUOTE$
EndIf
If FindString(Line$, "; EnableExeConstant", 1, #PB_String_NoCase) = 1
Commands$ + " /CONSTANT " + #DQUOTE$ + "PB_Editor_CreateExecutable=0" + #DQUOTE$
EndIf
If FindString(Line$, "; Constant =", 1, #PB_String_NoCase) = 1
Commands$ + " /CONSTANT " + #DQUOTE$ + Trim(RemoveString(StringField(Line$, 2, "="), "#")) + "=" + Trim(StringField(Line$, 3, "=")) + #DQUOTE$
EndIf
EndIf
EndIf
Wend
CloseFile(0)
EndIf
EndIf
If ExpandMacros
tmpOut$ = GetPathPart(FileOut$) + "zzz_" + GetFilePart(FileOut$)
Commands$ + " /DEBUGGER"
;First step, make one huge PB file, containing all includes and macros expanded in the code
PID = RunProgram(Compiler$, #DQUOTE$ + FileIn$ + #DQUOTE$ + Commands$ + " /PREPROCESS " + #DQUOTE$ + tmpOut$ + #DQUOTE$, "", #PB_Program_Read | #PB_Program_Hide | #PB_Program_Open)
If PID
While ProgramRunning(PID)
If AvailableProgramOutput(PID)
Result$ + ReadProgramString(PID) + #LF$
EndIf
Delay(5)
Wend
CloseProgram(PID)
Result$ + #CRLF$ + "----" + #CRLF$
;Scond step, compile this source
PID = RunProgram(Compiler$, #DQUOTE$ + tmpOut$ + #DQUOTE$ + Commands$ + " /OUTPUT " + #DQUOTE$ + tmpExe$ + #DQUOTE$, "", #PB_Program_Read | #PB_Program_Hide | #PB_Program_Open)
If PID
While ProgramRunning(PID)
If AvailableProgramOutput(PID)
Result$ + ReadProgramString(PID) + #LF$
EndIf
Delay(5)
Wend
CloseProgram(PID)
EndIf
Result$ + #CRLF$ + "----" + #CRLF$
;third step, call external Debugger
RunProgram(Debugger$, #DQUOTE$ + tmpExe$ + #DQUOTE$, "", #PB_Program_Wait)
EndIf
;MessageRequester("Info", Result$)
;[optional]
;remove the files we've created
EndIf
EndProcedure
main()
Example:
Code: Select all
; expandmacros remove the space between ; and expandmacros to see the difference
Macro test(a, b)
c = a + b
d = c * 2
e = d / b
EndMacro
Procedure MakeError(a, b)
test(a, b)
EndProcedure
OpenConsole("Test")
PrintN("Press enter to create bug")
Input()
MakeError(1, 0)
{Home}.:|:.{Dialog Design0R}.:|:.{Codes}.:|:.{Downloads}.:|:.{History Viewer Online}
Re: Macro-Errorhandling
This post by Freak explains why a two-pass compiler is not going to happen -> viewtopic.php?p=307825#p307825