BlitzScript3D

Blitz3D Forums/Blitz3D Programming/BlitzScript3D

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

I would do select..case conditions and conditional loops basically the same as I did if..then conditions: the "TOKEN_IF" case takes care of the entire if..then..else..endif" and all it's statements just like Mark Sibley's example. Here's my if..then..else..endif code (single or multi line):

	Case TOKEN_IF
		GSC_ParseExpression()
		If GSC_TokenType <> TOKEN_THEN Then
			GSC_AddError("Expected "+Chr(34)+"Then"+Chr(34))
			GSC_SkipLine(): GSC_NextToken()
			Return
		End If
		LabelElse = GSC_UniqueLabel()
		WriteLine GSC_OutputFile, "    jz    _" + LabelElse
		
		GSC_NextToken()
		If GSC_TokenType = TOKEN_TERMINATOR Then
			;Multi-line IF statement
			Repeat
				GSC_ParseStatement()
				If GSC_Done Then
					GSC_AddError("Expected "+Chr(34)+"Else"+Chr(34)+" or "+Chr(34)+"EndIf"+Chr(34))
					Return
				End If
			Until GSC_TokenType = TOKEN_ELSE Or GSC_TokenType = TOKEN_ENDIF
			If GSC_TokenType = TOKEN_ELSE
				LabelEndif = GSC_UniqueLabel()
				WriteLine GSC_OutputFile, "    jmp   _" + LabelEndif
				WriteLine GSC_OutputFile, "_" + LabelElse + ":"
				GSC_NextToken()
				If GSC_TokenType = TOKEN_IF Then GSC_AddWarning("Ambiguous coding style (may cause unexpected errors - see language manual)")
				Repeat
					GSC_ParseStatement()
					If GSC_Done Then
						GSC_AddError("Expected "+Chr(34)+"EndIf"+Chr(34))
						Return
					End If
				Until GSC_TokenType = TOKEN_ENDIF
				WriteLine GSC_OutputFile, "_" + LabelEndif + ":"
				GSC_NextToken()
			Else ;EndIf
				WriteLine GSC_OutputFile, "_" + LabelElse + ":"
				GSC_NextToken()
			EndIf
		Else
			;Single-line IF statement
			GSC_ParseStatement(False)
			If GSC_TokenType = TOKEN_ELSE
				LabelEndif = GSC_UniqueLabel()
				WriteLine GSC_OutputFile, "    jmp   _" + LabelEndif
				WriteLine GSC_OutputFile, "_" + LabelElse + ":"
				GSC_NextToken()
				GSC_ParseStatement()
				WriteLine GSC_OutputFile, "_" + LabelEndif + ":"
			Else
				WriteLine GSC_OutputFile, "_" + LabelElse + ":"
			EndIf
		End If
		
	Case TOKEN_ELSE, TOKEN_ENDIF
		GSC_AddError("Keyword is out of place (there are no open "+Chr(34)+"If"+Chr(34)+" statements)")
		GSC_NextToken()
		Return

Note: As you can see, GSC_NextToken() does not return anything! Instead of returning the token type, I find it cleaner and more logical to store the token and token type in global variables (GSC_Token, GSC_TokenType).

I haven't gotten to overloadable functions yet, but I don't think I'll have much trouble with the overloading part; just search all functions for the best match. For the actual function part I'm not sure - probably just as simple as a call stack and "scoping" variables properly.

To impliment custom types I had to "invent" a few special opcodes. These opcodes move a type field to/from another variable/eax/ecx:

mfc  a, b
  Moves the contents of the ecx."b" (type ecx, field "b") into "a"

mfa  a, b
  Moves the contents of the eax."b" (type eax, field "b") into "a" (same as mfc except uses eax instead of ecx)

xfc  a, b
  Moves the contents of "b" into ecx."a" (type ecx, field "a")

xfa  a, b
  Moves the contents of "b" into eax."a" (type eax, field "a") (same as xfc except uses eax instead of ecx)


Then the compiler can use these to compile code like this:
Type Car 
  Field a:Int, b:Float
EndType

Local test:Car, tmp:Float

test = New Car

test.a = 23

tmp = test.a * 10

Delete test


Into this:

;test = New Car
    new   eax,{car}
    mov   [test], eax
;test.a = 23
    mov   eax,23
    mov   ecx, [test]
    xfc   <a>, eax
;tmp = test.a * 10
    mov   eax,[test]
    mfa   eax,<a>
    push  eax
    mov   eax,10
    pop   ecx
    mul   eax,ecx
    mov   [tmp], eax
    mov   eax,[test]
;Delete test
    del   eax

    end