2
0
Эх сурвалжийг харах

Added loop label support.

woollybah 11 жил өмнө
parent
commit
b87f0ae5b0
6 өөрчлөгдсөн 210 нэмэгдсэн , 30 устгасан
  1. 35 0
      decl.bmx
  2. 35 1
      expr.bmx
  3. 1 1
      options.bmx
  4. 38 15
      parser.bmx
  5. 49 11
      stmt.bmx
  6. 52 2
      translator.bmx

+ 35 - 0
decl.bmx

@@ -913,6 +913,22 @@ End Rem
 		Return match
 	End Method
 	
+	Method FindLoop:TStmt(ident:String)
+
+		If TBlockDecl(scope) And TBlockDecl(scope).extra Then
+			Local loop:TLoopStmt = TLoopStmt(TBlockDecl(scope).extra)
+			If loop.loopLabel And loop.loopLabel.ident = ident Then
+				Return loop
+			End If
+		End If
+
+		If TFuncDecl(scope) Or TModuleDecl(scope)
+			Return Null
+		End If
+		
+		If scope Return scope.FindLoop( ident )
+	End Method
+	
 	Method OnSemant()
 	End Method
 	
@@ -920,6 +936,7 @@ End Type
 
 Type TBlockDecl Extends TScopeDecl
 	Field stmts:TList=New TList
+	Field extra:Object
 	
 	Method Create:TBlockDecl( scope:TScopeDecl )
 		Self.scope=scope
@@ -935,6 +952,7 @@ Type TBlockDecl Extends TScopeDecl
 		For Local stmt:TStmt=EachIn stmts
 			t.AddStmt stmt.Copy( t )
 		Next
+		t.extra = extra
 		Return t
 	End Method
 
@@ -1800,6 +1818,23 @@ End Rem
 	
 End Type
 
+Type TLoopLabelDecl Extends TDecl
+
+	Method Create:TLoopLabelDecl( ident$, attrs:Int=0 )
+		Self.ident=ident
+		Self.attrs=attrs
+		Return Self
+	End Method
+	
+	Method OnCopy:TDecl()
+		Return New TLoopLabelDecl.Create( ident,attrs )
+	End Method
+	
+	Method OnSemant()
+	End Method
+	
+End Type
+
 Const MODULE_STRICT:Int=1
 Const MODULE_SUPERSTRICT:Int=2
 Const MODULE_ACTUALMOD:Int=4

+ 35 - 1
expr.bmx

@@ -1734,7 +1734,6 @@ Type TIdentExpr Extends TExpr
 	End Method
 
 	Method SemantSet:TExpr( op$,rhs:TExpr )
-
 		_Semant
 
 		'Local scope:TScopeDecl=IdentScope()
@@ -1814,6 +1813,13 @@ Type TIdentExpr Extends TExpr
 			e.cdecl = cdecl
 			Return e
 		End If
+
+		' maybe it's a loop label?
+		Local stmt:TLoopStmt = TLoopStmt(scope.FindLoop(ident))
+		
+		If stmt Then
+			Return New TLoopLabelExpr.Create(stmt)
+		End If
 		
 		IdentErr
 	End Method
@@ -2185,3 +2191,31 @@ Type TNullExpr Extends TExpr
 	End Method
 
 End Type
+
+Type TLoopLabelExpr Extends TExpr
+
+	Field loop:TLoopStmt
+
+	Method Create:TLoopLabelExpr(loop:TLoopStmt)
+		Self.loop = loop
+		Return Self
+	End Method
+	
+	Method Copy:TExpr()
+		Return New TLoopLabelExpr.Create(loop)
+	End Method
+
+	Method Semant:TExpr()
+		Return Self
+	End Method
+
+	Method Trans$()
+		DebugStop
+	End Method
+
+	Method Eval$()
+		Return ""
+	End Method
+
+End Type
+

+ 1 - 1
options.bmx

@@ -25,7 +25,7 @@ SuperStrict
 
 Import "base.configmap.bmx"
 
-Const version:String = "0.16"
+Const version:String = "0.17"
 
 Const BUILDTYPE_APP:Int = 0
 Const BUILDTYPE_MODULE:Int = 1

+ 38 - 15
parser.bmx

@@ -30,7 +30,7 @@ Import "iparser.bmx"
 
 Global FILE_EXT$="bmx"
 
-Type TForEachinStmt Extends TStmt
+Type TForEachinStmt Extends TLoopStmt
 	Field varid$
 	Field varty:TType
 	Field varlocal:Int
@@ -39,17 +39,18 @@ Type TForEachinStmt Extends TStmt
 	
 	Field stmts:TList=New TList
 
-	Method Create:TForEachinStmt( varid$,varty:TType,varlocal:Int,expr:TExpr,block:TBlockDecl )
+	Method Create:TForEachinStmt( varid$,varty:TType,varlocal:Int,expr:TExpr,block:TBlockDecl,loopLabel:TLoopLabelDecl )
 		Self.varid=varid
 		Self.varty=varty
 		Self.varlocal=varlocal
 		Self.expr=expr
 		Self.block=block
+		Self.loopLabel=loopLabel
 		Return Self
 	End Method
 
 	Method OnCopy:TStmt( scope:TScopeDecl )
-		Return New TForEachinStmt.Create( varid,varty,varlocal,expr.Copy(),block.CopyBlock( scope ) )
+		Return New TForEachinStmt.Create( varid,varty,varlocal,expr.Copy(),block.CopyBlock( scope ),TLoopLabelDecl(loopLabel.Copy()) )
 	End Method
 
 	Method OnSemant()
@@ -120,7 +121,7 @@ Type TForEachinStmt Extends TStmt
 
 			EndIf
 
-			Local whileStmt:TWhileStmt=New TWhileStmt.Create( cmpExpr,block )
+			Local whileStmt:TWhileStmt=New TWhileStmt.Create( cmpExpr,block,Null )
 
 			block=New TBlockDecl.Create( block.scope )
 			block.AddStmt New TDeclStmt.Create( exprTmp )
@@ -167,7 +168,7 @@ Type TForEachinStmt Extends TStmt
 				block.stmts.AddFirst New TAssignStmt.Create( "=",New TIdentExpr.Create( varid ),nextObjExpr )
 			EndIf
 
-			Local whileStmt:TWhileStmt=New TWhileStmt.Create( hasNextExpr,block )
+			Local whileStmt:TWhileStmt=New TWhileStmt.Create( hasNextExpr,block,Null )
 
 			block=New TBlockDecl.Create( block.scope )
 			If tmpDecl Then
@@ -1214,7 +1215,7 @@ Type TParser
 		_block.AddStmt stmt
 	End Method
 
-	Method ParseWhileStmt()
+	Method ParseWhileStmt(loopLabel:TLoopLabelDecl = Null)
 		Parse "while"
 
 		Local expr:TExpr=ParseExpr()
@@ -1241,12 +1242,12 @@ Type TParser
 		Wend
 		PopBlock
 
-		Local stmt:TWhileStmt=New TWhileStmt.Create( expr,block )
+		Local stmt:TWhileStmt=New TWhileStmt.Create( expr,block,loopLabel )
 
 		_block.AddStmt stmt
 	End Method
 
-	Method ParseRepeatStmt()
+	Method ParseRepeatStmt(loopLabel:TLoopLabelDecl = Null)
 
 		Parse "repeat"
 
@@ -1268,12 +1269,12 @@ Type TParser
 			expr=New TConstExpr.Create( New TBoolType,"" )
 		EndIf
 
-		Local stmt:TRepeatStmt=New TRepeatStmt.Create( block,expr )
+		Local stmt:TRepeatStmt=New TRepeatStmt.Create( block,expr,loopLabel )
 
 		_block.AddStmt stmt
 	End Method
 
-	Method ParseForStmt()
+	Method ParseForStmt(loopLabel:TLoopLabelDecl = Null)
 'DebugStop
 		Parse "for"
 
@@ -1310,7 +1311,7 @@ Type TParser
 			Wend
 			PopBlock
 
-			Local stmt:TForEachinStmt=New TForEachinStmt.Create( varid,varty,varlocal,expr,block )
+			Local stmt:TForEachinStmt=New TForEachinStmt.Create( varid,varty,varlocal,expr,block,loopLabel )
 
 			_block.AddStmt stmt
 
@@ -1365,7 +1366,7 @@ Type TParser
 
 		NextToke
 
-		Local stmt:TForStmt=New TForStmt.Create( init,expr,incr,block )
+		Local stmt:TForStmt=New TForStmt.Create( init,expr,incr,block,loopLabel )
 
 		_block.AddStmt stmt
 	End Method
@@ -1379,12 +1380,16 @@ Type TParser
 
 	Method ParseExitStmt()
 		Parse "exit"
-		_block.AddStmt New TBreakStmt
+		Local expr:TExpr
+		If Not AtEos() expr=ParseExpr()
+		_block.AddStmt New TBreakStmt.Create(expr)
 	End Method
 
 	Method ParseContinueStmt()
 		Parse "continue"
-		_block.AddStmt New TContinueStmt
+		Local expr:TExpr
+		If Not AtEos() expr=ParseExpr()
+		_block.AddStmt New TContinueStmt.Create(expr)
 	End Method
 
 	Method ParseTryStmt()
@@ -1665,6 +1670,19 @@ Type TParser
 				ParseEndStmt()
 			Case "extern"
 				ParseExternBlock(_module, 0)
+			Case "#"
+				Local decl:TLoopLabelDecl = ParseLoopLabelDecl()
+				NextToke
+				Select _toke
+					Case "while"
+						ParseWhileStmt(decl)
+					Case "repeat"
+						ParseRepeatStmt(decl)
+					Case "for"
+						ParseForStmt(decl)
+					Default
+						Err "Expecting loop statement"
+				End Select
 			Default
 				Local expr:TExpr=ParsePrimaryExpr( True )
 
@@ -1847,6 +1865,12 @@ Type TParser
 			_block.AddStmt New TDeclStmt.Create( decl )
 		Until Not CParse(",")
 	End Method
+	
+	Method ParseLoopLabelDecl:TLoopLabelDecl()
+		NextToke
+		Local id:String = ParseIdent()
+		Return New TLoopLabelDecl.Create(id, 0)
+	End Method
 
 	'handle end-of-line "dot dot return"-line connector
 	'-> skips EOL tokens
@@ -2381,7 +2405,6 @@ End Rem
 
 			' try to import interface
 			Local par:TIParser = New TIParser
-
 			If par.ParseModuleImport(_module, modpath, origPath, path, , , filepath) Return
 		Else
 			If filepath.startswith("-") Then

+ 49 - 11
stmt.bmx

@@ -269,12 +269,22 @@ End Type
 
 Type TBreakStmt Extends TStmt
 
+	Field label:TExpr
+
+	Method Create:TBreakStmt( label:TExpr )
+		Self.label=label
+		Return Self
+	End Method
+
 	Method OnSemant()
 		If Not _loopnest Err "Exit statement must appear inside a loop."
+		If label Then
+			label = label.Semant()
+		End If
 	End Method
 
 	Method OnCopy:TStmt( scope:TScopeDecl )
-		Return New TBreakStmt
+		Return New TBreakStmt.Create(label.Copy())
 	End Method
 	
 	Method Trans$()
@@ -285,12 +295,22 @@ End Type
 
 Type TContinueStmt Extends TStmt
 
+	Field label:TExpr
+	
+	Method Create:TContinueStmt( label:TExpr )
+		Self.label=label
+		Return Self
+	End Method
+
 	Method OnSemant()
 		If Not _loopnest Err "Continue statement must appear inside a loop."
+		If label Then
+			label = label.Semant()
+		End If
 	End Method
 
 	Method OnCopy:TStmt( scope:TScopeDecl )
-		Return New TContinueStmt
+		Return New TContinueStmt.Create(label.Copy())
 	End Method
 	
 	Method Trans$()
@@ -326,18 +346,28 @@ Type TIfStmt Extends TStmt
 	End Method
 End Type
 
-Type TWhileStmt Extends TStmt
+Type TLoopStmt Extends TStmt
+
+	Field loopLabel:TLoopLabelDecl
+
+End Type
+
+Type TWhileStmt Extends TLoopStmt
 	Field expr:TExpr
 	Field block:TBlockDecl
 	
-	Method Create:TWhileStmt( expr:TExpr,block:TBlockDecl )
+	Method Create:TWhileStmt( expr:TExpr,block:TBlockDecl,loopLabel:TLoopLabelDecl )
 		Self.expr=expr
 		Self.block=block
+		Self.loopLabel = loopLabel
+		If loopLabel Then
+			block.extra = Self
+		End If
 		Return Self
 	End Method
 
 	Method OnCopy:TStmt( scope:TScopeDecl )
-		Return New TWhileStmt.Create( expr.Copy(),block.CopyBlock( scope ) )
+		Return New TWhileStmt.Create( expr.Copy(),block.CopyBlock( scope ),TLoopLabelDecl(loopLabel.Copy()) )
 	End Method
 	
 	Method OnSemant()
@@ -352,18 +382,22 @@ Type TWhileStmt Extends TStmt
 	End Method
 End Type
 
-Type TRepeatStmt Extends TStmt
+Type TRepeatStmt Extends TLoopStmt
 	Field block:TBlockDecl
 	Field expr:TExpr
 	
-	Method Create:TRepeatStmt( block:TBlockDecl,expr:TExpr )
+	Method Create:TRepeatStmt( block:TBlockDecl,expr:TExpr,loopLabel:TLoopLabelDecl )
 		Self.block=block
 		Self.expr=expr
+		Self.loopLabel=loopLabel
+		If loopLabel Then
+			block.extra = Self
+		End If
 		Return Self
 	End Method
 
 	Method OnCopy:TStmt( scope:TScopeDecl )
-		Return New TRepeatStmt.Create( block.CopyBlock( scope ),expr.Copy() )
+		Return New TRepeatStmt.Create( block.CopyBlock( scope ),expr.Copy(),TLoopLabelDecl(loopLabel.Copy()) )
 	End Method
 	
 	Method OnSemant()
@@ -378,22 +412,26 @@ Type TRepeatStmt Extends TStmt
 	End Method
 End Type
 
-Type TForStmt Extends TStmt
+Type TForStmt Extends TLoopStmt
 	Field init:TStmt	'assignment or local decl...
 	Field expr:TExpr
 	Field incr:TStmt	'assignment...
 	Field block:TBlockDecl
 	
-	Method Create:TForStmt( init:TStmt,expr:TExpr,incr:TStmt,block:TBlockDecl )
+	Method Create:TForStmt( init:TStmt,expr:TExpr,incr:TStmt,block:TBlockDecl,loopLabel:TLoopLabelDecl )
 		Self.init=init
 		Self.expr=expr
 		Self.incr=incr
 		Self.block=block
+		Self.loopLabel=loopLabel
+		If loopLabel Then
+			block.extra = Self
+		End If
 		Return Self
 	End Method
 
 	Method OnCopy:TStmt( scope:TScopeDecl )
-		Return New TForStmt.Create( init.Copy( scope ),expr.Copy(),incr.Copy( scope ),block.CopyBlock( scope ) )
+		Return New TForStmt.Create( init.Copy( scope ),expr.Copy(),incr.Copy( scope ),block.CopyBlock( scope ),TLoopLabelDecl(loopLabel.Copy()) )
 	End Method
 	
 	Method OnSemant()

+ 52 - 2
translator.bmx

@@ -653,6 +653,7 @@ End Rem
 
 		Local count:Int = LoopTryDepth()
 		If count > 0 Then
+			' TODO : handle loop labels
 			Local bc:TTryBreakCheck = GetTopLoop()
 			If bc Then
 				NextContId(bc)
@@ -664,7 +665,11 @@ End Rem
 				InternalErr
 			End If
 		Else
-			Return "continue"
+			If stmt.label And TLoopLabelExpr(stmt.label) Then
+				Emit "goto " + TransLoopLabelCont(TLoopLabelExpr(stmt.label).loop.loopLabel.ident, False)
+			Else
+				Return "continue"
+			End If
 		End If
 	End Method
 	
@@ -674,6 +679,7 @@ End Rem
 		
 		Local count:Int = LoopTryDepth()
 		If count > 0 Then
+			' TODO : handle loop labels
 			Local bc:TTryBreakCheck = GetTopLoop()
 			If bc Then
 				NextExitId(bc)
@@ -685,7 +691,11 @@ End Rem
 				InternalErr
 			End If
 		Else
-			Return "break"
+			If stmt.label And TLoopLabelExpr(stmt.label) Then
+				Emit "goto " + TransLoopLabelExit(TLoopLabelExpr(stmt.label).loop.loopLabel.ident, False)
+			Else
+				Return "break"
+			End If
 		End If
 	End Method
 	
@@ -746,6 +756,22 @@ End Rem
 		End If
 	End Method
 
+	Method TransLoopLabelCont:String(id:String, jmp:Int = True)
+		If jmp Then
+			Return "_loopcont_" + id.ToLower() + ": ;"
+		Else
+			Return "_loopcont_" + id.ToLower() + ";"
+		End If
+	End Method
+
+	Method TransLoopLabelExit:String(id:String, jmp:Int = True)
+		If jmp Then
+			Return "_loopexit_" + id.ToLower() + ": ;"
+		Else
+			Return "_loopexit_" + id.ToLower() + ";"
+		End If
+	End Method
+
 	'***** Block statements - all very C like! *****
 	
 	Method Emit( t$, useIndent:Int = True )
@@ -936,11 +962,19 @@ End Rem
 			Emit TransLabelCont(check)
 		End If
 
+		If stmt.loopLabel Then
+			Emit TransLoopLabelCont(stmt.loopLabel.ident, True)
+		End If
+		
 		Emit "}"
 
 		If check.exitId Then
 			Emit TransLabelExit(check)
 		End If
+
+		If stmt.loopLabel Then
+			Emit TransLoopLabelExit(stmt.loopLabel.ident, True)
+		End If
 		
 		If broken=nbroken And TConstExpr( stmt.expr ) And TConstExpr( stmt.expr ).value unreachable=True
 		broken=nbroken
@@ -962,6 +996,10 @@ End Rem
 			Emit TransLabelCont(check)
 		End If
 
+		If stmt.loopLabel Then
+			Emit TransLoopLabelCont(stmt.loopLabel.ident, True)
+		End If
+		
 		SetOutput("source")
 
 		Local s:String = "}while(!"+Bra( stmt.expr.Trans() )+");"
@@ -974,6 +1012,10 @@ End Rem
 			Emit TransLabelExit(check)
 		End If
 
+		If stmt.loopLabel Then
+			Emit TransLoopLabelExit(stmt.loopLabel.ident, True)
+		End If
+
 		If broken=nbroken And TConstExpr( stmt.expr ) And Not TConstExpr( stmt.expr ).value unreachable=True
 		broken=nbroken
 	End Method
@@ -1006,6 +1048,10 @@ End Rem
 			Emit TransLabelCont(check)
 		End If
 
+		If stmt.loopLabel Then
+			Emit TransLoopLabelCont(stmt.loopLabel.ident, True)
+		End If
+		
 		Emit "}"
 		
 		If decl Then
@@ -1015,6 +1061,10 @@ End Rem
 		If check.exitId Then
 			Emit TransLabelExit(check)
 		End If
+
+		If stmt.loopLabel Then
+			Emit TransLoopLabelExit(stmt.loopLabel.ident, True)
+		End If
 		
 		If broken=nbroken And TConstExpr( stmt.expr ) And TConstExpr( stmt.expr ).value unreachable=True
 		broken=nbroken