Quake C

Blitz3D Forums/Blitz3D Userlibs/Quake C

Yasha(Posted 2009) [#1]
DO NOT USE THIS CODE!!! IT DOES NOT WORK!!! It's here for historical reasons only.

---

EDIT4: I think I'll fork the projects actually - see if I can finish Noodle completely and then come back to this and build it to more closely imitate a QuakeLike, just for fun.

EDIT3: GC is functional (it's a tracing GC based on HotSpot, so cyclic references ought not to be a problem), but there is no tenured storage yet (so very limited).

EDIT2: New version is not quite ready for release, but you can download the incomplete version and keep an eye on the progress here. It'll be out as soon as the GC (yes, a GC) is done usable. Now includes object-oriented features - methods, inheritance and polymorphism!

EDIT: This doesn't really work as-is. Rather than fix it (it's borderline impossible to fix this coding disaster), I'm rewriting it from scratch, which will take a little longer but allow a few extra features (OK, OK, custom types and dynamic arrays are going in) as well as getting rid of that pesky GPL. The code remains here if you want to examine it anyway, but be warned that there are so many typos and holes that you could throw a brick through this and not see a difference.

---

Quake C is a lightweight scripting language with C-like syntax, developed by ID to write scripts for the original Quake engine. I thought it might be fun to use it as a scripting solution for Blitz projects - here is the result so far. Please note that this is not extensively tested - I haven't tested arrays at all - and not necessarily complete. I am not yet sure about its speed compared to other options (in my only test, it was faster than GameScript, but that was most likely non-representative).

First - language specification: http://www.gamers.org/dEngine/quake/spec/quake-spec34/qc-menu.htm (only the first page is really relevant due to the changes)

This implementation has a few differences, however. Firstly, most obviously, Progs.dat is no longer relevant, so unless you especially want to compile to a file named that, the compiler simply outputs separate compiled scripts named scriptname.qcx (get used to recognising GameScript ideas). Source therefore needs to have a "main()" function and won't work without it.
Secondly, "states" or "frame functions" are also absent, again being only relevant to the Quake engine, and the same goes for $-macros and the "field" data type. Thirdly, I have added simple preprocessor directives (#include, #define, #ifdef, #endif - #define is a simple copy and paste though, not a proper macro) and the ability to define simple arrays (after the fashion of Blitz arrays, they can be local and must be of constant size. You can use #defined constants for this, but not QuakeC constants). Since the interpreter now uses a stack instead of hundreds of global variables, it is now possible to call functions as parameters to other functions (composition) or operators (both impossible in the original).

I have not added custom types and do not currently intend to do so. Special mention needs to go to built-in functions (even though I actually haven't changed that) because they do still need to be prototyped in the script's source (the idea being that you make your own list of builtins and hardcode complex types as your project requires). And no, the absence of integers is not an error, it is intentional. Add them if you want, but it adds complexity.

The syntax is similar enough to C that a C IDE will provide context highlighting and indentation services, but not so similar that the code will compile. I don't ask for more than that from IDEs so I don't know if other features would work.

Finally, before we get to the code, the reason this isn't going straight into the code archives to be ignored in the right place is because the Quake code was released under the GPL - keep reading! - and therefore the compiler, which is almost entirely straight copied from the original source, falls under the same licence. The interpreter I made without reference to the Quake source - it's obviously similar, because it reads the output of the compiler, but it is my own work (working in a significantly different way from the original) and therefore can be released to the public domain. In the unlikely event anyone uses this, you can use the interpreter in your projects, but do not put the compiler in your main source or the GPL will infect that as well. Distribute the compiler as a separate exe (and source, of course) and you will be safe from the GPL.

The alert reader will notice some conventions (packing loaded scripts into "threads", compiling to extension+"x", etc.) are borrowed from GameScript. Conventions and stylistic ideas are all I borrowed - I have no idea how GameScript works because I don't have the patience to read through it (that's why I made my own alternative), so any non-stylistic similarities are coincidental, or at least unintentional.

1. The compiler


2. Its header


3. The interpreter


4. The interpreter's header
[codebox]

;Blitz3D QuakeC Interpreter
;==========================

;Header
;------

Const MAX_VARS=1000 ;
Const MAX_FUNCS=100 ;;
Const MAX_OPS=10000 ;;; These are constants because the values are held in Blitz arrays. Feel free to increase them if necessary
Const STACKSIZE=100 ;;
Const LOCALSIZE=500 ;
Const MAX_PARMS=8
Const STACKID=-1
Const NULLVAR=-2

Type Thread
Field runstate ;0=ready, 1=running, 2=done
Field vcount ;Number of variables and constants
Field fcount ;Number of functions
Field scount ;Number of instructions
Field v.vdef[MAX_VARS] ;List of variables and constants
Field f.fdef[MAX_FUNCS] ;List of functions
Field s.sdef[MAX_OPS] ;List of instructions
Field main.fdef ;Function main()
Field insptr ;Current instruction
Field cscope.fdef ;Current scope
Field stack.vdef[STACKSIZE],stkptr
Field localstack.vdef[LOCALSIZE],locptr
Field junkptr ;Address of "junk value" to dump unwanted results
End Type

Type fdef ;Function definition
Field ID
Field name$
Field code ;offset of first statement
Field rtype ;Return type
Field builtin ;0 for scripted function, or number for a native function
Field num_parms ;Number of parameters (-1=variable)
Field fvar,lvar ;First and last variables local to function (including parameters) by ID
Field parm_name$[MAX_PARMS-1]
Field parm_type[MAX_PARMS-1]
Field parm.vdef[MAX_PARMS-1] ;Store the ID rather than the vdef itself
End Type

Type vdef ;Variable definition
Field name$
Field scope
Field vtype
Field array ;True if this is an array header
Field f#,s$,e ;Value (float, string, handle)
Field vx.vdef,vy.vdef,vz.vdef ;Vector field pointers (float variables)
;Add fields for other types as required
End Type

Type sdef ;Instruction
; Field ID
Field op,a,b,c
End Type

;Type constants
Const ev_VOID=1, ev_STRING=2, ev_FLOAT=3, ev_VECTOR=4, ev_ENTITY=5, ev_FUNCTION=6

;Opcode constants
Const OP_DONE = 0
Const OP_MUL_F = 1
Const OP_MUL_V = 2
Const OP_MUL_FV = 3
Const OP_MUL_VF = 4
Const OP_DIV_F = 5
Const OP_ADD_F = 6
Const OP_ADD_V = 7
Const OP_SUB_F = 8
Const OP_SUB_V = 9
Const OP_CONC_S = 10
Const OP_EQ_F = 11
Const OP_EQ_V = 12
Const OP_EQ_S = 13
Const OP_EQ_E = 14
Const OP_NE_F = 15
Const OP_NE_V = 16
Const OP_NE_S = 17
Const OP_NE_E = 18
Const OP_LE = 19
Const OP_GE = 20
Const OP_LT = 21
Const OP_GT = 22
Const OP_STORE_F = 23
Const OP_STORE_V = 24
Const OP_STORE_S = 25
Const OP_STORE_ENT = 26
Const OP_RETURN = 27
Const OP_NOT_F = 28
Const OP_NOT_V = 29
Const OP_NOT_S = 30
Const OP_NOT_ENT = 31
Const OP_IF = 32
Const OP_IFNOT = 33
Const OP_CALL = 34
Const OP_GOTO = 35
Const OP_AND = 36
Const OP_OR = 37
Const OP_BITAND = 38
Const OP_BITOR = 39
Const OP_ARRAY = 40
;Const OP_CLEARSTACK = 41

;Built-in function IDs Built-in functions MUST be prototyped in the script.

Const BF_RINT =1 ;Here for example's sake. Maths functions like these could equally well just be opcodes
Const BF_FLOOR =2
Const BF_CEIL =3
Const BF_ABS =4
Const BF_RND =5
Const BF_FTOS =6
Const BF_VYAW =7
Const BF_VNORM =8
Const BF_VLEN =9
Const BF_VTO


puki(Posted 2009) [#2]
This looks exciting.


Yasha(Posted 2009) [#3]
.

(EDIT: As above, whole thing is being rewritten because this version has too many bugs to fix, the biggest one being the GPL. By all means play with it, but don't expect it to work as advertised. The "new version" will actually have a different name, featureset and syntax, due to the fact that trying to force the QuakeC peg into the Blitz3D hole is the root of far too much messing about. The only similarity is the use of three address code, because it's awesome.)