正在加载图片...
creating labels, calling functions, etc. Since we have a lot to do, we will make the mechanics of generating the TAC as easy as possible. In our parser, we will create the TAC instructions one at a time. We can immediately print them out or store them for further processing. We will simplify the Decaf language a little by excluding doubles for code generation and internally treating bools as 4-byte integers. Classes, arrays, and strings will be implemented with 4-byte pointers. This means we only ever need to deal with 4-byte integer/pointer variables As each production is reduced, we will create the necessary instructions. This strategy makes our code-generation a bit limited--particularly for the way we would have to do switch statements-but we can translate more-or-less any language structure into an executable program in a single pass, without needing to go back and edit anything which is pretty convenient. To see how a syntax-directed translation can generate TAC, we need to look at the derivation, and figure out where the different TaC statements should be generated as the productions are reduced Lets start with a trivial program void main() Print (hello world") to = hello world call Printstring( to)i Endfunc Notice that we call the library function labelled Print String to do the actual printing Library functions are called like any ordinary global function, but the code for the definition is provided by the compiler as part of linking with the standard language libraries. Here is the derivation of the source program. The trick is to identify where and what processing occurs as these productions are reduced to generate the given TAC Dec⊥List-> ype - Void Formals - Constant - string Constant E -> Constant 4 ExprList-> Expr Printstmt - Print ExprList stmt - printstmt stmtlist - stmtlist stmt StmtBlock - Stmtlist 1 FunctionDefn - Type identifier Formals StmtBlock Decl -> Functiondefncreating labels, calling functions, etc. Since we have a lot to do, we will make the mechanics of generating the TAC as easy as possible. In our parser, we will create the TAC instructions one at a time. We can immediately print them out or store them for further processing. We will simplify the Decaf language a little by excluding doubles for code generation and internally treating bools as 4-byte integers. Classes, arrays, and strings will be implemented with 4-byte pointers. This means we only ever need to deal with 4-byte integer/pointer variables. As each production is reduced, we will create the necessary instructions. This strategy makes our code-generation a bit limited—particularly for the way we would have to do switch statements—but we can translate more-or-less any language structure into an executable program in a single pass, without needing to go back and edit anything, which is pretty convenient. To see how a syntax-directed translation can generate TAC, we need to look at the derivation, and figure out where the different TAC statements should be generated as the productions are reduced. Let’s start with a trivial program: void main() { Print("hello world"); } main: BeginFuncWithParams; Var _t0; _t0 = "hello world"; LCall _PrintString(_t0); EndFunc; Notice that we call the library function labelled _PrintString to do the actual printing. Library functions are called like any ordinary global function, but the code for the definition is provided by the compiler as part of linking with the standard language libraries. Here is the derivation of the source program. The trick is to identify where and what processing occurs as these productions are reduced to generate the given TAC: DeclList -> Type -> Void Formals -> StmtList -> Constant -> stringConstant Expr -> Constant 4 ExprList-> Expr PrintStmt -> Print ( ExprList ) Stmt -> PrintStmt ; StmtList -> StmtList Stmt StmtBlock -> { StmtList } FunctionDefn -> Type identifier ( Formals ) StmtBlock Decl -> FunctionDefn
<<向上翻页向下翻页>>
©2008-现在 cucdc.com 高等教育资讯网 版权所有