10 January 2010

Listing: fcallparm.pb


; fcallparm.pb
IncludeFile "..\base2.pb"
IncludeFile "..\labels.pb"
IncludeFile "..\symboltable.pb"


Procedure.s VarRef(*V.SVariable)
Select *V\RefKind
Case #Ref_Global
ProcedureReturn "[v_" + *V\Name + "]"
Default
Error("Unknown variable scope kind")
EndSelect
EndProcedure

; Return the asm for accessing the value of a variable
Procedure.s VarValue(Name.s)
Protected *V.SSymbol = LookupSymbol(Name)
If *V And *V\Kind = #SKind_Variable
ProcedureReturn VarRef(*V)
Else
Error("Undeclared variable: " + Name)
EndIf
EndProcedure

Declare Expression()
Procedure FunctionParameters(*F.SFunction)
Protected ParamStackSize = *F\ParamCount*4 ; Note, it's 4 because we use longs. Doubles and quads would be 8!
Protected I
Emit2("sub ", "esp", Str(ParamStackSize)) ; Make room on the stack for the parameters
For I = 0 To *F\ParamCount-1
Expression()
Emit("mov [esp+" + Str(I*4) + "], eax")
If I <> *F\ParamCount-1 ; If the current parameter is NOT the last one
MatchWhite(',') ; Get a comma and whitespace to prepare for the next parameter
EndIf
Next
EndProcedure

Procedure FunctionCall(Name.s)
Protected *F.SFunction = LookupSymbolNoScopeResolve(Name)
If *F And *F\Kind = #SKind_Function
If *F\ParamCount > 0
FunctionParameters(*F)
EndIf
Emit("call " + *F\Ref)
Else
Error("Undeclared function: " + Name)
EndIf
EndProcedure

Procedure Value()
; value ::= <integer> | <variable> | <fcall()> | '(' <expression> ')'
Protected Name.s
If IsDigit(Look)
Emit("mov eax, " + GetInteger())
ElseIf IsAlpha(Look)
Name = GetName()
If Look = '('
Match('(')
FunctionCall(Name)
Match(')')
Else
Emit("mov eax, " + VarValue(Name))
EndIf
Else
Expected("value")
EndIf
EndProcedure

Procedure Expression()
; expression ::= <value>
Value()
EndProcedure

Procedure Assignment(Name.s)
; assignment ::= <name> = <expression>
MatchWhite('=')
Expression()
Emit2("mov ", VarValue(Name), "eax")
EndProcedure

Procedure VariableDeclaration()
; vardecl ::= var <name> as <type>
Protected Name.s
Protected TypeS.s, TypeI.i
Protected *V.SVariable

; Get name and type
Name = GetName()
If GetName() <> "as"
Expected("as")
EndIf
TypeS = GetName()

AddVariable(Name, TypeS, #Ref_Global, 0)
EndProcedure


Procedure Statement()
Protected N.s
N = GetName()
If Look = '('
Match('(')
FunctionCall(N)
Match(')')
Else
Select N
Case "var": VariableDeclaration()
Default: Assignment(N)
EndSelect
EndIf
EndProcedure

Procedure Program()
; program ::= { <assignment> }
EatWhiteNewlines()
While Look
Statement()
EatWhiteNewlines()
Wend
EndProcedure

Procedure GlobalAsmDefinition(ScopedName.s, *V.SVariable)
If *V\Kind = #SKind_Variable
If *V\RefKind = #Ref_Global
Emit("v_" + *v\Name + " dd 0")
EndIf
EndIf
EndProcedure

Procedure Footer()
Emit("")
Emit("push 0")
Emit("call _ExitProcess")
Emit("; Global variables: ")
EnumerateSymbols(@GlobalAsmDefinition())
EndProcedure

; Add a few functions to the symbol table so we can call them
*F.SFunction = AddFunction("MyFunc")
*F\Type = #TyLong
*F\ParamCount = 1
*F\ParamTypes[0] = #TyLong

*F.SFunction = AddFunction("DoCoolStuff")
*F\Type = #TyLong
*f\ParamCount = 3
*f\ParamTypes[0] = #TyLong
*f\ParamTypes[1] = #TyLong
*f\ParamTypes[2] = #TyLong


InitMulti()
Program()
Footer()
Input()