[[FrontPage]]

2008/07/07からのアクセス回数 &counter;

#contents

[[antlr/構文木を使った解析]]では、構文木を使った四則演算プログラムを紹介しましたが、
ここでは[[Cコンパイラ設計(yacc・lexの応用)/第7章 コードの生成]]と同じアセンブラ
コードを出力するコンパイラを作成します。

** SampleC構文解析 [#f916548a]
SampleCは、Cのサブセットで
- 型はintのスカラーのみ
- フロー制御は、if文、while文のみ
をサポートしています。

最初に、sample.yをベースに以下の処理をします。
- 左再帰をEBNFに変更
- 優先順位を明示的に記述
- エラー処理を外す

*** 生成する構文木の形 [#zca43761]
入力として以下のデータを入力すると
#pre{{
main()
{	
	gcd(36,54);
}

gcd(a,b)
int a;
int b;
{
	if (a == b)
		return a;
	else if (a > b)
		return gcd(a-b, b);
	else
		return gcd(a, b-a);
}
}}

nilノードに2個のFUNCノードを持つツリーが作成されます。
1個目のFUNCノードは、
#ref(func_tree1.jpg);

2個目のFUNCノードは、
#ref(func_tree2.jpg);
のようになります。

- FUNCノードには、以下のノードが付いています。
-- 関数の型
-- 関数名
-- 関数パラメータのFUNCPARノード
-- パラメータの型定義のPARDEFノード
-- 関数本体のBLOCKノード


- 関数呼び出しCALLノードには、以下のノードが付いています。
-- 関数名
-- 引数リストのARGノード

- IF文のIFノードには、以下のノードが付いています。
-- 条件文
-- 条件がTRUEの時の処理ノード
-- 条件がFALSEの時の処理ノード

また、SampleCの構文木のみの特徴として式の後にセミコロンがきた
タイミングでスタックをクリアするためにCLEARノードを追加します。

*** SampleC.g [#zb4c1cd3]
SampleC.gは次のようになります。

#pre{{
grammar SampleC;

options{
	output = AST;
	ASTLabelType = CommonTree;
}

tokens{
	PROGRAM; FUNC; FUNCPAR; PARDEF; VARDEF; BLOCK; ASSIGN;  
	CALL; NOT; NEGATE; ARG; NUM; VAR; PREFIX; NOP; CLEAR;
	ALU_ADD; ALU_SUB; ALU_MUL; ALU_DIV; ALU_LT; 
	ALU_GT; ALU_LE; ALU_GE; ALU_EQ; ALU_NE; 
	ALU_AND; ALU_OR; ALU_XOR;
	INT; VOID; IF; WHILE;
}

program
	: (
	  d=definition
	  	{ if ($d.tree != null) System.out.println($d.tree.toStringTree());}
	  )+
	  	-> ^(PROGRAM definition+)
	;
definition
	: functionDefintion
		-> functionDefintion
	| declaration
		-> declaration
	;
functionDefintion
	: funcType IDENTIFIER '(' parameterList ')' parameterDeclarations compoundStatement
		-> ^(FUNC funcType IDENTIFIER ^(FUNCPAR parameterList) parameterDeclarations compoundStatement)
	;
funcType
	: type
		-> type
	|	-> INT
	;
parameterList
	: (IDENTIFIER (',' IDENTIFIER)*)?
		-> IDENTIFIER*
	;
parameterDeclarations
	: parameterDeclaration*
		-> ^(PARDEF parameterDeclaration*)
	;
parameterDeclaration
	: (t=type id=IDENTIFIER
		-> ^(VARDEF $t $id)
	  )
	  (',' (id=IDENTIFIER)
	  	-> $parameterDeclaration ^(VARDEF $t $id)
	  )* ';'
	;
compoundStatement
	: '{' declarations statements '}'
		-> ^(BLOCK declarations statements)
	;
declarations
	: declaration*
	;
declaration
	: (t=type id=IDENTIFIER
		-> ^(VARDEF $t $id)
	  )
	  (',' (id=IDENTIFIER)
	  	-> $declaration ^(VARDEF $t $id)
	  )* ';'
	;
statements
	: statement*
	;
statement
options {
	backtrack=true;
}
	: e=expression ';'
		-> $e CLEAR
	| ';'
		-> NOP
	| BREAK 
		-> BREAK
	| CONTINUE
		-> CONTINUE
	| RETURN ';'
		-> RETURN
	| RETURN e=expression ';'
		-> ^(RETURN $e)
	| c=compoundStatement
		-> $c
	| ifstm
		-> ifstm
	| 'while' '(' e=expression ')' s=statement
		-> ^(WHILE $e $s)
	;
ifstm
options{
	backtrack=true;
}
	: 'if' '(' e=expression ')' s1=statement ELSE s2=statement
		-> ^(IF $e $s1 $s2)
	| 'if' '(' e=expression ')' s1=statement
		-> ^(IF $e $s1 NOP)
	;
expression 
	: binary
		-> binary
	;
binary
	: i=IDENTIFIER '=' e=expression
		-> ^(ASSIGN $i $e)
	| IDENTIFIER PE e=expression
		-> ^(ASSIGN IDENTIFIER ^(ALU_ADD IDENTIFIER $e))
	| IDENTIFIER ME e=expression
		-> ^(ASSIGN IDENTIFIER ^(ALU_SUB IDENTIFIER $e))
	| IDENTIFIER TE e=expression
		-> ^(ASSIGN IDENTIFIER ^(ALU_MUL IDENTIFIER $e))
	| IDENTIFIER DE e=expression
		-> ^(ASSIGN IDENTIFIER ^(ALU_DIV IDENTIFIER $e))
	| equalityExpr
		-> equalityExpr
	;
equalityExpr
	: comparisonExpr (eqOp^ comparisonExpr)*
	;
eqOp
	: '==' 
		-> ALU_EQ
	| ('!=' | '<>')
		-> ALU_NE
	;
comparisonExpr
	: additiveExpr (compOp^ additiveExpr)*
	;
compOp
	: '>'
		-> ALU_GT
	| '<'
		-> ALU_LT
	| '<='
		-> ALU_LE
	| '>='
		-> ALU_GE
	;
additiveExpr
	: multiplicativeExpr (addOp^ multiplicativeExpr)*
	;
addOp
	: '+'
		-> ALU_ADD
	| '-'
		-> ALU_SUB
	;
multiplicativeExpr
	: bitExpr (mulOp^ bitExpr)*
	;	
mulOp	
	: '*'
		-> ALU_MUL
	| '/'
		-> ALU_DIV
	;
bitExpr
	: notExpr (bitOp^ notExpr)*
	;
bitOp
	: '&'
		-> ALU_AND
	| '|'
		-> ALU_OR
	| '^'
		-> ALU_XOR
	;
notExpr
	: op='!'? negationExpr
		-> {$op != null}? ^(NOT negationExpr)
		-> negationExpr
	;
negationExpr
	: op='-'? primary
		-> {$op != null}? ^(NEGATE primary)
		-> primary
	;
primary
	: atom
	| '('! expression ')'!
	;
atom
	: IDENTIFIER
		-> IDENTIFIER
	| PP IDENTIFIER
		-> ^(PREFIX IDENTIFIER PP)
	| MM IDENTIFIER
		-> ^(PREFIX IDENTIFIER MM)
	| CONSTANT
		-> CONSTANT
	| IDENTIFIER '(' a=argumentList ')'
		-> ^(CALL IDENTIFIER $a)
	;

argumentList
	: (expression (',' expression)*)?
		-> ^(ARG expression*)
	;
type
	: 'int' 
		-> INT
	;
	
BREAK		: 'break' ;
CONTINUE	: 'continue' ;
RETURN		: 'return' ;
ELSE		: 'else' ;
PP		: '++' ;
MM		: '--' ;
PE		: '+=' ;
ME		: '-=' ;
TE		: '*=' ;
DE		: '/=' ;	
IDENTIFIER	: ('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z'|'0'..'9')* ;
CONSTANT	: '0'..'9'+ ;
WS		: (' '|'\t'|'\r'|'\n')+ {skip();} ;
}}


** コメント [#b42076b0]
この記事は、

#vote(おもしろかった,そうでもない,わかりずらい)

皆様のご意見、ご希望をお待ちしております。

#comment


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
SmartDoc