#define equivalent

BlitzMax Forums/BlitzMax Programming/#define equivalent

_JIM(Posted 2009) [#1]
Comming from a C/C++ environment, I miss the #define directive.

I know there's "?Win32", "?Debug", "?Threaded" and so on... but is there any way to define my own?

What I'd like to do is stick "?[something]" around my code and have a single define switch from my editor to the game itself. This way I make sure that any updates to the engine are instantly visible in both the editor and game.

There is a way to do this... if I split the editor and game code entirely and keep some core code in includes. But that is really hacky, especially when I have something like:

Type MyType
   Method New()
      ?Editor
         myTreeView.AddTreeViewNode(myInstanceName)
      ?
      'fill in the fields values, etc.
   EndMethod
EndType


Is there any way to define my own precompiler constants?
If not (very likely) how would you go about doing this?


Brucey(Posted 2009) [#2]
If not (very likely) how would you go about doing this?

You'd need to write your own pre-compiler, which processes your .bmx files and creates a "processed" version of the source which you could then pass to the standard build process.

Not sure if it's been mentioned around here, but I think someone made a pre-processor on the German forum.


_JIM(Posted 2009) [#3]
Hm... sound like a good idea.

I'll give this a try and post my results :)


TaskMaster(Posted 2009) [#4]
This gets complicated when it comes to debugging. The debugger will be giving line numbers that correspond to the file that was sent to the compiler, but if you edit the version that came out of your pre-compiler, the changes don't make it in to the original source.

I am not saying it can't be done, but it will take a lot of work.


joncom2000(Posted 2009) [#5]
According to this thread http://www.blitzbasic.com/Community/posts.php?topic=41598#467399 from several years ago you can sort of conditional compile if you use a const as the test in an if statement. I dont know if it still works but might be worth trying.

a #define #if #endif request has been made afew times but not happened it seems.


BlitzSupport(Posted 2009) [#6]
I've occasionally wished for a ?Custom thing too!


_JIM(Posted 2009) [#7]
Consts won't work. In my above example, there's no "myTreeView" declared inside the "game".

The debugging issue is interesting. However, I can temporarily output some sources and use those to do the debugging. After that, move on to fixing stuff in the original code.

However, I am not too concerned about this as I rarely use the debugger for stepping through the program in bmax. I use it often in C++, but since the bmax debugger is vastly inferior, I just stick to "DebugLog", "DrawText" and "Notify" to do the debugging :)


_Skully(Posted 2009) [#8]
If someone adds a pre-processor to the IDE that would do it...

Thats like regions... the IDE could add folding to those as well


Arowx(Posted 2009) [#9]
Could you not just write a simple app to Rem and 'Rem any lines within a ?<Custom> block, as a one click 'pre-compile' process?

Or does the IDE have hooks for pre/post compile processing?


TaskMaster(Posted 2009) [#10]
That's a good idea Merx. Then the debugging would line up...

But another nice feature to have in a pre-compiler would be a macro/inline type functionality, which you could not do with Rem statements. Though you could do it with includes.


_JIM(Posted 2009) [#11]
That's a very nice idea, Merx. There might be issues if you have a "Rem..EndRem" inside a "?Custom..?", but those can be easily eliminated (replaced with anything else but not erased completely because they'll mess up line numbers).

I'm quite eager to try this... must find time!


TaskMaster(Posted 2009) [#12]
You don't have to Rem - End Rem them. Just put an apostrophe in front of the lines in the ?Custom block. Then the line numbers don't change, and there is no way there can be a conflict with other rem statements.


joncom2000(Posted 2009) [#13]
That kind of defeats the purpose if you have to manually comment out each line, if we could use are own ?define it saves time and is the point ;)


_JIM(Posted 2009) [#14]
@joncom2000

That's what TaskMaster was talking about: AUTOMAGICALLY put an apostrophe in front of every line.


TaskMaster(Posted 2009) [#15]
Yes, you could have a preprocessor that looked through your source file and commented out the user defines that got defined away.

You could even make the user defines a special comment that only the preprocessor would recognize, so they didn't mess up anything else.

Like:

'define MyTest

And

'?MyTest

Then just run through the source files. Remember the 'define lines you find. If you see a '? directive and haven't found a define for it, then put apostrophes in front of all the lines.

Would be fairly easy and unobtrusive.

I wonder if Blide is capable of allowing a preprocessor. Maybe using the BLide SDK...


_JIM(Posted 2009) [#16]
Well, if you convert boredom at work into a productive period of time, you get this:

SuperStrict

Global compiler_args:String = " "
Global compiled_file:String
Global compiler_path:String = "C:\Program Files\BlitzMax\bin\bmk"

Global temp_files:TList = New TList

Type Definition
	Global DefList:TList = New TList
	
	Field n:String	'name
	Field v:String	'value
	
	Method New()
		DefList.AddLast(Self)
	End Method
	
	Function Find:Definition(n:String)
		For Local d:Definition = EachIn DefList
			If (d.n = n)
				Return d
			End If
		Next
	End Function
End Type

Local arg:String
AppArgs[0] = ""
For arg = EachIn AppArgs
	Local ext:String
	If arg.Length > 4
		ext = Right(arg, 4)
		If Lower(ext) = ".bmx"
			ProcessFile(arg)
			compiled_file = arg
		Else
			compiler_args:+arg + " "
		End If
	Else
		compiler_args:+arg + " "
	End If
Next

system_(compiler_path + " " + compiler_args + " " + Replace(AppDir, "/", "\") + "\" + compiled_file + "_out.bmx")

Function ProcessFile(f:String)
	If (FileType(f) <> 1)
		Notify ("Cannot find file: " + f, True)
	End If
	
	temp_files.AddLast(f + "_out.bmx")
	
	Local fs:TStream = ReadFile(f)
	Local fo:TStream = WriteFile(f + "_out.bmx")
	While Not Eof(fs)
		Process(fs, fo, f)
	Wend
	CloseFile(fs)
	CloseFile(fo)
End Function

Function Process(s:TStream, os:TStream, crtfile:String = "")
	Local processed_line:String
	Local out_line:String
	Local indent:String
	
	While Not Eof(s)
		indent = ReadLine(s)
		processed_line = Trim(indent)
		indent = Replace(indent, processed_line, "")
		out_line = processed_line
		Select True
			Case (Lower(Left(processed_line, 8)) = "'#define")
				Local def:String[]
				def = processed_line.Split(" ")
				
				Local d:Definition = New Definition
				d.n = def[1]
				If (def.Length > 2)
					d.v = def[2]
				End If
				WriteLine(os, indent + out_line)
			Case (Lower(Left(processed_line, 7)) = "'#ifdef")
				Local cond:String[]
				cond = processed_line.Split(" ")
				
				Local d:Definition = Definition.Find(cond[1])
				If (d <> Null)
					WriteLine(os, indent + out_line)
					Process(s, os)
				Else
					WriteLine(os, out_line)
					While (Not (Lower(Left(processed_line, 7)) = "'#endif"))
						processed_line = ReadLine(s)
						out_line = "'" + processed_line
						WriteLine(os, out_line)
					Wend
				End If
			Case (Lower(Left(processed_line, 7)) = "include")
				Local inc:String[]
				inc = processed_line.Split(" ")
				
				inc[1] = Replace(inc[1], "~q", "")
				
				ProcessFile(ExtractDir(crtfile) + inc[1])
				WriteLine(os, "Include ~q" + inc[1] + "_out.bmx~q")
			Default
				WriteLine(os, indent + out_line)
		End Select
	Wend
EndFunction

For Local fl:String = EachIn temp_files
	DeleteFile(fl)
Next

End



The basics are there. The code's a bit messy but does the job for now.

Features:

- supports definitions through: '#define
- supports checking definitions through '#ifdef .. '#endif
- supports included files
- supports nested checks

One thing that I didn't test yet (but will do when I get home):

set the compiler path to "bmk_old", rename bmk.exe, then compile this preprocessor as bmk.exe. It should be working as it passes the arguments right through.

EDIT: This doesn't work yet.

It's fairly simple atm... feel free to bring modifications and improvements before I do :)

EDIT2: It's driving me crazy not being able to place this between BLIde and bmk.exe.

Anyone happen to have the preprocessor mentioned here: http://www.blitzbasic.com/Community/posts.php?topic=56393#627200 ?


AndyGFX(Posted 2009) [#17]
I don't understand why this isn't implemented in BLIde ;) This compiler directives are very useful.


degac(Posted 2009) [#18]
I made (long time ago) a similar thing: as I dont' like wasting my time typing something like
Local window:tgadget,btn_add:tgadget,btn_remove:tgadget,btn_close:tgadget

(note the :tgadget repeated 4 times...)
I would like something like
Local window,btn_add,btn_remove,btn_close as Tgadget

(Tgadget is typed 1 time)
So I wrote an application that 'read' and 'translated' the source code (I dont' remember where it is now...) like the one of _Jim (without Include support): the only problem is that my 'source code' (the one with the AS keyword) was/is not compatible with standard Blitzmax code...I can't use the 'hack' of the REM (') solution.

To come back on topic, I would like some 'directive' support from Bmax (or standard IDE).


_JIM(Posted 2009) [#19]
Well, I managed to plug this in bmk.exe :)

Still testing and fixing as its not fully working yet. It compiles my application just fine (including defines support) but it doesn't compile bmk itself.