Yeonnnnny

신택스 분석기 - (9) 수식 분석 본문

컴파일러

신택스 분석기 - (9) 수식 분석

yeonny_do 2024. 11. 10. 00:37

 

1. 기본 수식 (Primary_expression) 분석

 

primary_expression
	: IDENTIFIER      	{$$=makeNode(N_EXP_IDENT, 0, getIdentifierDeclared($1),0);}
	| INTEGER_CONSTANT	{$$=makeNode(N_EXP_INT_CONST, 0, $1, 0);}
	| FLOAT_CONSTANT  	{$$=makeNode(N_EXP_FLOAT_CONST, 0, $1, 0);}
	| CHARACTER_CONSTANT  {$$=makeNode(N_EXP_CHAR_CONST, 0, $1, 0);}
	| STRING_LITERAL  	{$$=makeNode(N_EXP_STRING_LITERAL, 0, $1, 0);}
	| LP expression RP	{$$=$2;}
	;

 

 기본 수식은 간단한 명칭이나 상수 혹은 일반 수식에 소괄호를 묶은 형식으로 가장 먼서 계산되는 피연산자를 말함. 기본 수식을 분석한 후 <primary_expression>은 다음과 같이 새롭게 생성되는 신택스 트리를 가리킴.

  • 명칭인 경우, 수식에서 사용할 수 있는 명칭이어야 하므로, 그 종류가 올바른 명칭인지 검사하고, N_EXP_IDNET 이름의 노드를 한 개 가지는 새로운 신택스 트리를 만듦. 노드의 자식은 명칭을 위한 심볼 테이블을 가리키도록 함.
  • 정수형 상수인 경우, N_EXP_INT_CONST 이름의 노드를 한 개 가지는 새로운 신택스 트리를 만듦, 노드의 자식은 정수 값을 가지도록 함.
  • 실수형 상수인 경우에, N_EXP_FLOAT_CONST 이름의 노드를 한 개 가지는 새로운 신택스 트리를 만듦. 노드의 자식은 실수 스트링을 가리키도록 함.
  • 문자형 상수인 경우, N_EXP_CHAR_CONST 이름의 노드를 한 개 가지는 새로운 신택스 트리를 만듦, 노드의 자식은 문자값을 가지도록 함.
  • 스트링 리터럴인 경우, N_EXP_STRING_LITERAL 이름의 노드를 한 개 가지는 새로운 신택스 트리를 만듦. 노드의 자식은 스트링을 가리키도록 함.

 소괄호로 묶인 수식의 형식인 경우에  <expression> 수식을 분석하여 만든 신택스 트리의 루트 노드를 그대로 가리킴.

 

 

 

2. 후위 수식(Postfix_expression) 분석

 

postfix_expression
	: primary_expression  {$$=$1;}
	| postfix_expression LB expression RB {$$=makeNode(N_EXP_ARRAY, $1, 0, $3);}
	| postfix_expression LP arg_expression_list_opt RP {$$=makeNode(N_EXP_FUNCTION_CALL, $1, 0, $3);}
	| postfix_expression PERIOD IDENTIFIER {$$=makeNode(N_EXP_STRUCT, $1, 0, $3);}
	| postfix_expression ARROW IDENTIFIER  {$$=makeNode(N_EXP_ARROW, $1, 0, $3);}
	| postfix_expression PLUSPLUS      	{$$=makeNode(N_EXP_POST_INC, 0, $1, 0);}
	| postfix_expression MINUSMINUS    	{$$=makeNode(N_EXP_POST_DEC, 0, $1, 0);}
	;

arg_expression_list_opt
	: /* empty */     	{$$=makeNode(N_ARG_LIST_NIL, 0, 0, 0);}
	| arg_expression_list {$$=$1;}
	;

arg_expression_list
	: assignment_expression {$$=makeNode(N_ARG_LIST, $1, 0, makeNode(N_ARG_LIST_NIL, 0, 0, 0);)}
	| arg_expression_list COMMA assignment_expression {$$=makeNodeList(N_ARG_LIST,$1,$3);}
	;

 

  후위 수식을 분석한 후 <postfix_expression>은 다음과 같이 새롭게 생성되는 신택스 트리를 가리킴.

  • 후위 수식 뒤에 대괄호와 수식, 즉 배열을 참조하는 형식인 경우, N_EXP_ARRAY 이름의 새로운 노드 아래 <postfix_expression>과 <expression>을 자식으로 연결한 신택스 트리를 만듦.
  • 후위 수식 뒤에 소괄호, 즉 함수를 호출하는 형식인 경우, N_EXP_FUNCTION_CALL 이름의 새로운 노드 아래 <postfix_expression>과 <arg_expression_list_opt>를 자식으로 연결한 신택스 트리를 만듦. <arg_expression_list_opt>는 함수를 호출할 때 사용되는 실 매개 변수 목록을 나타내는 신택스 트리를 가리킴.
  • 후위 수식 뒤에 마침표, 즉 구조체의 필드를 참조하는 형식인 경우, N_EXP_STRUCT 이름의 새로운 노드 아래 <postfix_expression>과 필드 명칭 스트링을 자식으로 연결한 신택스 트리를 만듦.
  • 후위 수식 뒤에 화살표, 즉 포인터를 이용하여 간점 참조하는 형식인 경우에는 N_EXP_ARROW 이름의 새로운 노드 아래 <postfix_expression>과 필드명칭 스트링을 자식으로 연결한 신택스 트리를 만듦. 
  • 후위 수식 뒤에 후위 증감 연산자가 있는 경우에는, N_EXP_POST_INC나 N_EXP_POST_DEC 이름의 새로운 노드 아래 <postfix_expression>을 자식으로 연결한 신택스 트리를 만듦.

 

 후위 수식이 기본 수식(primary_expression)과 같은 형식인 경우에, <postfix_expression>은 <primary_expression>이 가리키는 신택스 트리를 그대로 가리키도록 함. 

 

  함수 호출 형식의 후위 수식에는 매개변수 수식 목록이 나올 수 있는데, <arg_expression_list_opt>는 매개변수 수식 목록을 위한 신택스 트리를 가리키도록 함. 매개변수 수식 목록을 위한 신택스 트리는 다음과 같이 구성함.

  • 매개변수 수식이 없는 경우, N_ARG_LIST_NIL 이름의 노드 하나로 구성
  • 매개변수 수식이 하나 이상 여러 개인 경우, N_ARG_LIST 이름의 노드를 루트로 하여, 좌측 자식이 수식을 위한 신택스 트리를 가리키고, 우측 자식은 다음의 매개변수 수식 목록을 위한 신택스 트리를 재귀적으로 가리키도록 함.
  • 매개변수 수식을 위한 신택스 트리는 가장 우측의 단말노드가 항상 N_ARG_LIST_NIL이 되도록 함.

 

후위수식 사용 예시)

... kim[i+3]...
... lee[10].a->b++ ...
... fun(c, d+10) ...

 

 

 

3. 단항 수식(Unary_expression)과 타입 변환 수식(Cast_expression) 분석

 

// 단항 수식
unary_expression
	: postfix_expression      	{$$=$1;}
	| PLUSPLUS unary_expression   {$$=makeNode(N_EXP_PRE_INC, 0, $2, 0);}
	| MINUSMINUS unary_expression {$$=makeNode(N_EXP_PRE_DEC, 0, $2, 0);}
	| AMP cast_expression     	{$$=makeNode(N_EXP_AMP, 0, $2, 0);}
	| STAR cast_expression    	{$$=makeNode(N_EXP_STAR, 0, $2, 0);}
	| EXCL cast_expression    	{$$=makeNode(N_EXP_NOT, 0, $2, 0);}
	| MINUS cast_expression   	{$$=makeNode(N_EXP_MINUS, 0, $2, 0);}
	| PLUS cast_expression    	{$$=makeNode(N_EXP_PLUS, 0, $2, 0);}
	| SIZEOF_SYM unary_expression {$$=makeNode(N_EXP_SIZE_EXP, $2, 0, 0);}
	| SIZEOF_SYM LP type_name RP  {$$=makeNode(N_EXP_SIZE_TYPE, $3, 0, 0);}
	;

// 타입 변환 수식
cast_expression
	: unary_expression  {$$=$1;}
	| LP type_name RP cast_expression {$$=makeNode(N_EXP_CAST, $2, $4, 0);}
	;

type_name
	: declaration_specifiers abstract_declarator_opt {$$=setTypeNameSpecifier($2,$1);}
	;

 

  단항 수식이 후위 수식과 같은 형식인 경우, <unary_expression>은 <postfix_expression>이 가리키는 신택스 트리를 그대로 가리키도록 함. 타입 변환 수식이 단항 수식과 같은 형식인 경우, <cast_expression>은 <unary_expression>이 가리키는 신택스 트리를 그대로 가리키도록 함. 단항 연산자를 포함하는 수식을 분석한 후 <unary_expression>이나 <casting_expression>은 다음과 같이 새롭게 생성되는 신택스 트리를 가리킴.

  • 단항 수식 앞에 전위 증감 연산자가 있는 경우, N_EXP_PRE_INC나 N_EXP_PRE_DEC 이름의 새로운 노드 아래 <unary_expression>을 자식으로 연결한 신택스 트리를 만듦.
  • 타입 변환 수식 앞에 주소 계산(&), 간접 참조(*), 논리역(!), 마이너스(-), 플러스(+) 같은 연산자가 있는 경우, N_EXP_AMP, N_EXP_STAR, N_EXP_NOT, N_EXP_MINUS나 N_EXP_PLUS 이름의 새로운 노드 아래 <cast_expression>을 자식으로 연결한 신택스 트리를 만듦.
  • 단항 수식 앞에 수식의 크기를 계산하는 sizeof 연산자가 있는 경우, N_EXP_SIZEOF_EXP 이름의 새로운 노드 아래 <unary_expression>을 자식으로 연결한 신택스 트리를 만듦.
  • 타입의 크기를 계산하는 sizeof 연산자 다음에 소괄호와 타입이 나오는 수식인 경우,<type_name>은 해당 타입 테이블 주소를 가리키고 있으므로, N_EXP_SIZEOF_TYPE이름의 새로운 노드 아래 <type_name>을 자식으로 연결한 신택스 트리를 만듦.
  • 타입 변환 연산을 위한 수식의 경우, N_EXP_CAST 이름의 새로운 노드 아래 <cast_expression>이 가리키는 신택스 트리를 자식으로 연결한 신택스 트리를 만듦.
  • <type_name>은 타입 명시자(즉, 단순 타입 명칭, 구조체나 나열형 타입 명시자)로만 되어있는 경우와, 복잡하게는 타입 명시자 뒤에 추상 선언자(즉, 포인터나 배열구조를 복합적으로 나타내는 타입 선언 형식)가 있는 경우가 있는데, 그 타입을 분석하여 타입 테이블을 만들고, <type_name>은 그 주소를 가리키도록 함.

 

  • A_TYPE *setTypeNameSpecifier(A_TYPE *, A_SPECIFIER *);
    • 두 번쨰 매개 변수로 받은 타입 명시자가 기억 장소 명시자를 포함하고 있는지 검사
    • 있는 경우 에러 처리
    • 생략된 타입 명시자를 확인하여 설정 (없는 경우, int형으로 설정)
    • 첫 번째 매개 변수로 받은 타입의 엘리먼트 타입으로 타입 명시자의 타입 정보 저장
A_TYPE *setTypeNameSpecifier(A_TYPE *t, A_SPECIFIER *p){
    	// 타입 명시자에 기억 장소 명시자(storage class)가 있는지 검사
    	if(p->stor) syntax_error(20);
    	setDefaultSpecifier(p);
    	t = setTypeElementType(t, p->type);
    	return(t);
}

 

 

 

4. 이항 연산 수식(산술 수식, 관계 수식, 논리 수식)

 

// 산술 수식
multiplicative_expression
	: cast_expression {$$=$1;}
	| multiplicative_expression STAR cast_expression	{$$=makeNode(N_EXP_MUL, $1, 0, $3);}
	| multiplicative_expression SLASH cast_expression   {$$=makeNode(N_EXP_DIV, $1, 0, $3);}
	| multiplicative_expression PERCENT cast_expression {$$=makeNode(N_EXP_MOD, $1, 0, $3);}
	;

additive_expression
	: multiplicative_expression {$$=$1;}
	| additive_expression PLUS multiplicative_expression  {$$=makeNode(N_EXP_ADD, $1, 0, $3);}
	| additive_expression MINUS multiplicative_expression {$$=makeNode(N_EXP_SUB, $1, 0, $3);}
	;

// 관계 수식
relational_expression
	: additive_expression {$$=$1;}
	| relational_expression LSS additive_expression {$$=makeNode(N_EXP_LSS, $1, 0, $3);}
	| relational_expression GTR additive_expression {$$=makeNode(N_EXP_GTR, $1, 0, $3);}
	| relational_expression LEQ additive_expression {$$=makeNode(N_EXP_LEQ, $1, 0, $3);}
	| relational_expression GEQ additive_expression {$$=makeNode(N_EXP_GEQ, $1, 0, $3);}
	;

// 논리 수식
equality_expression
	: relational_expression {$$=$1;}
	| equality_expression EQL relational_expression {$$=makeNode(N_EXP_EQL, $1, 0, $3);}
	| equality_expression NEQ relational_expression {$$=makeNode(N_EXP_NEQ, $1, 0, $3);}
	;

logical_and_expression
	: equality_expression {$$=$1;}
	| logical_and_expression AMPAMP equality_expression {$$=makeNode(N_EXP_AND, $1, 0, $3);}
	;

logical_or_expression
	: logical_and_expression {$$=$1;}
	| logical_or_expression BARBAR logical_and_expression {$$=makeNode(N_EXP_OR, $1, 0, $3);}
	;

 

  이항 연산자를 포함하는 수식을 분석하면 <logical_expression> 등은 다음과 같이 새롭게 생성되는 신택스 트리를 가리킴

  • 이항 연산자 (*, /, %, +, -, <, >, <=, >=, !=, ==, &&, ||) 를 포함하는 수식이 나오는 경우, 연산자 우선순위에 맞게 새로운 노드를 만들어, 좌측 자식으로 연산자 앞의 수식을 위한 신택스 트리를 연결하고 , 우측 자식으로 연산자 뒤의 수식을 위한 신택스 트리를 연결함.

 

 

5. 상수 수식과 일반 수식

 

// 상수 수식
constant_expression_opt
	: /*empty*/       	{$$=NIL;}
	| constant_expression {$$=$1;}
	;

constant_expression
	: expression {$$=$1;}
	;

// 일반 수식
expression
	: assignment_expression {$$=$1;}
	;

assignment_expression
	: logical_or_expression {$$=$1;}
	| unary_expression ASSIGN assignment_expression {$$=makeNode(N_EXP_ASSIGN, $1, NIL, $3);}
	;

 

  상수 수식은 일반 수식과 그 문법적 형식은 같아서 신택스 트리의 구성 형태는 같지만 컴파일 단계에서 즉시 계산할 수 있는 수식을 의미함. 치환 연산자를 포함하는 수식을 분석하면 <expression>은 다음과 같이 새롭게 생성되는 신택스 트리를 가리킴.

  •  치환 연산자(=)가 나오는 경우, N_EXP_ASSIGN 을 만들어, 좌측 자식으로 연산자 앞의 수식을 위한 신택스 트리를 연결하고, 우측 자식으로 연산자 뒤의 수식을 위한 신택스 트리를 연결.