yacc 질문~~

luftpalen의 이미지

안녕하세요 간단한 IDE 만들어보고자 하는데 컴파일러는 GCC와 연결하구요 : )

C 언어 소스파일을 파싱해서 심볼테이블을 만드는 것은 BNF로 돌리기로 하였습니다.
다만 identifier 만 찾는것이기 때문에 심볼의 종류는 변수와 함수 이름, 그밖에 storage class 선언부로
한정됩니다. 이틀째 flex 와 bison으로 돌리고 있는 중인데 함수명을 뽑아내기 위해서 이런 방법을 고안했습니다.

먼저 C 언어의 BNF의 function_definition 부분에서
function_definition
:declaration_specifiers declarator declaration_list compound_statement
..(하략)

이 있다면 제가 알기로 yacc에서 사용자 코드를 넣는것은 맨 마지막에 넣을 수 있는데
declaration_specifiers declarator declaration_list compound_statement{사용자코드}

declarator 에서 함수명 즉 identifier 가 튀어나오구요, identifier를 잡을때 이것이 함수명인지 변수명인
지만 구분해주면 됩니다만, 그냥 변수선언인 declaration 에서도 declarator가 있기 때문에 어떤것인지 알
수가 없습니다. 위 처럼 사용자 코드를 두면 compound_statement , 즉 {} 가 끝나면 사용자 코드가 실행되
기 때문에 효과가 없더군요. 따라서

(이부분!!!!) declaration_specifiers declarator declaration_list compound_statement

위부분에 변수인지 함수인지 알 수 있는 플래그를 하나 두려고 하는데 당체 되지가 않는군요. 실은
set_func_flag:{func_flag = 1;}; 로 잡아서 하려했습니다

set_func_flag declaration_specifiers declarator declaration_list compound_statement

이런식으로 두었을때 conflict 가 나면서 삽입전에 잘 파싱되던 소스도 문법 오류가 나더군요. 약간 갑갑하면서 .... 지금 그냥 '내가 파서를 짤까' 하는 생각도 들곤합니다.

필요한 심볼은 함수 리턴타입, 함수 파라미터, 함수명, 변수명, storage class 선언명 이 필요한데 도움을 얻을수 있을까요?

날씨 쌀쌀한데 건강조심하세요~

File attachments: 
첨부파일 크기
파일 calc.tar100 KB
lacovnk의 이미지

declaration_specifiers declarator

이부분이 모호해서 conflict나는건가요? (기억이 가물..)

declaration_specifiers declarator declaration_list {여기}compound_statement

이렇게 하면 되려나.. (벌써 기억이 안나다니! 버럭)

결론은, {}는 중간에 들어갈 수 있다.. 입니다. 대신 순서가 밀리죠.

A B C => {1,2,3}
A B {요것} C => {1,2,3,4}
seoleda의 이미지

Abstract Syntax Tree를 잘 그려보면 declarator가 변수명인지 함수명인지 구분가능하지 않나요?

제 생각엔 declarator 정의 부분에서 심볼테이블을 생성하도록 하고, (이때는 무조건 변수로 간주),

 
declaration_specifiers declarator declaration_list compound_statement{사용자코드}

이 부분에서 {사용자 코드} 부분에 해당 심볼테이블을 찾아서 함수로 변경하도록 짜면 될거 같습니다.

luftpalen의 이미지

일단 끝 말고 중간에 {} 을 넣으면 잘되던것도 syntax error 나는군요.

마지막 부분에서 찾으면 되는데.. 그것을 어떻게 찾으런지 모르겠습니다. 마지막에서 찾는다는 것은 일단 하위 expression tree 가 다 종료된 다음인데 어떠한 방법으로 찾아야할까요..;; 함수인지 아닌지 어떻게 구분해야 할까 모르겠습니다. 제가 그것때문에 앞쪽에다가 플래그를 넣는다라고 생각했었는데..

무식한 머리로는 여기가 한계라...

seoleda의 이미지

http://www.lysator.liu.se/c/ANSI-C-grammar-y.html#direct-abstract-declarator
을 참고하면, 두가지 방법이 있을 듯 합니다.

여기서,

direct_declarator
	: IDENTIFIER
	| '(' declarator ')'
	| direct_declarator '[' constant_expression ']'
	| direct_declarator '[' ']'
	| direct_declarator '(' parameter_type_list ')'
	| direct_declarator '(' identifier_list ')'
	| direct_declarator '(' ')'
	;


direct_abstract_declarator
	: '(' abstract_declarator ')'
	| '[' ']'
	| '[' constant_expression ']'
	| direct_abstract_declarator '[' ']'
	| direct_abstract_declarator '[' constant_expression ']'
	| '(' ')'
	| '(' parameter_type_list ')'
	| direct_abstract_declarator '(' ')'
	| direct_abstract_declarator '(' parameter_type_list ')'
	;

이 두부분을 보면, 함수와 변수의 차이는 declarator 다음에 '(', 와 ')'가 오느냐 오지 않느냐의 차이 같습니다. 따라서, 아래쪽 뒤에 괄호가 나오는 부분이 함수이며 나오지 않거나, 대괄호가 나오는 부분은 배열이나 변수 표현 같습니다.
그러므로, 결론은 이 두부분에 따로따로 코드를 추가하는 방법이 있을 것 같습니다.
그러나, 이 방법은 제가 변수뒤에 괄호가 나오는 경우는 못본것 같아서 이러한 방법을 제시했는데, 씨언어를 열심히 안해서 혹시 그런 경우가 있는지 잘 모르겠습니다.

그리고, 또 한가지 방법은 전에도 언급했다 시피..

function_definition
	: declaration_specifiers declarator declaration_list compound_statement
	| declaration_specifiers declarator compound_statement
	| declarator declaration_list compound_statement
	| declarator compound_statement
	;

이 코드에서 첫번째 문법을 예로 들면,
$1은 declaration_specifiers,
$2는 declator
$3는 declaration_list 를 의미합니다.

그러므로, 코드 부분에 $2에 해당하는 심볼을 찻고, 그 그 심볼은 무조건 함수심볼로 표시합니다. 또한, declator 부분의 문법을 찾아서 그 부분에는 심볼테이블에 해당 심볼을 추가하는 루틴을 작성하고요.

첨부 화일은 예전에 lex, yacc로 구현한 공학용 계산기 입니다.

숙제 내용은 "미/적분이 가능한 계산기를 구현하라" 여서 symbol processing을 하라는 의미였습니다만, 그건 구현하지 못하고 수치 미분/적분을 구현했습니다. 혹시 참고가 되면 좋겠습니다. 사용법은 help를 치면 나옵니다.

댓글 첨부 파일: 
첨부파일 크기
파일 0바이트
익명 사용자의 이미지

identifier 만 찾는용도라면 ctags 를 호출해서 그결과를 사용하는것도 한 방법일수 있을것 같습니다.

제경우 Java 를 주로 사용하는데 대부분의IDE들이 무거워서 Scite 를 사용하고 있습니다. Scite는 tag navigation 기능이 없어서 에서 파일을 저장할때 ctags 를 저장하는 파일에 대해서 실행하고 그 결과를 sqlite DB 에 저장합니다.
그리고 그 데이타를 이용해서 Quick-outline , goto Definition ,Open by File Name 등의 기능을 구현했습니다.

yacc를 사용해서 프로그램을 해보는것이 목적이 아니라
identifier 만 간단히 tree 로 보여준다거나 vim 의 tag navigation(?) 기능을 흉내내는정도라면 제생각엔 ctags(또는 cscope) 를 사용하시는게 구현이 훨씬빠르고 쉬울거 같습니다.

tomyun의 이미지

seoleda wrote:
그러나, 이 방법은 제가 변수뒤에 괄호가 나오는 경우는 못본것 같아서 이러한 방법을 제시했는데, 씨언어를 열심히 안해서 혹시 그런 경우가 있는지 잘 모르겠습니다.

아마도..
int *fp(int);
이렇게 함수 포인터를 선언하려면 위와 같은 룰이 필요할 것 같습니다.

그리고 abstract_declarator는 IDENTIFIER를 포함하는 것이 아니라 파라미터의 타입 선언과 같은 곳에 사용되는 룰이고, declarator가 실제 IDENTIFIER 토큰을 처리해주는 룰인 것 같은데..

단순히 괄호가 있거나 없는 것만으로는 위의 함수 포인터와 같은 경우를 처리해주지 못하니 정확한 방법이 되지 못 할 듯 보이네요.

제 생각에도 두번째 말씀하신 것처럼 function_definition쪽에서 처리해주는 방향이 되어야 할 것 같아요(사실 Yacc는 잘 모릅니다-_-;).

seoleda의 이미지

거 참 애매하군요.
본래 목적이 함수심볼과 변수 심볼을 구분하는 것이였는데...

함수 포인터라면, 변수심볼로 분류해야 할지 함수심볼로 분류해야 할지 애매한것 같습니다. 혹시 실제 C언어에서는 어떻게 분류했는지 아시는분 계시나요?

lifthrasiir의 이미지

seoleda wrote:
거 참 애매하군요.
본래 목적이 함수심볼과 변수 심볼을 구분하는 것이였는데...

함수 포인터라면, 변수심볼로 분류해야 할지 함수심볼로 분류해야 할지 애매한것 같습니다. 혹시 실제 C언어에서는 어떻게 분류했는지 아시는분 계시나요?

함수 포인터라면 변수 심볼로 처리하는 게 맞는 거 아닌가요? 보통 포인터 변수처럼 말이죠.

- 토끼군

seoleda의 이미지

제 생각으로는 함수 포인터라고 하면, 내용이야 어찌 됐건 주소를 담고 있으니 변수심볼로 볼 수도 있을것 같고, 어쨋뜬 담고있는 내용이 함수의 시작번지이고 하니 컴파일시에 함수포인터에 대해서는 함수에 준하는 처리를 해줘야 할 듯 하니 함수심볼이라고 할 수도 있을 것 같습니다.

토끼군님은 왜 함수포인터를 변수 심볼로 처리하는게 맞다고 생각하는지 설명해 주실수 있으신가요?

lifthrasiir의 이미지

seoleda wrote:
제 생각으로는 함수 포인터라고 하면, 내용이야 어찌 됐건 주소를 담고 있으니 변수심볼로 볼 수도 있을것 같고, 어쨋뜬 담고있는 내용이 함수의 시작번지이고 하니 컴파일시에 함수포인터에 대해서는 함수에 준하는 처리를 해줘야 할 듯 하니 함수심볼이라고 할 수도 있을 것 같습니다.

토끼군님은 왜 함수포인터를 변수 심볼로 처리하는게 맞다고 생각하는지 설명해 주실수 있으신가요?

함수의 주소를 저장할 수 있다고 해서 포인터 변수라는 게 바뀌는 건 아니라고 생각해서 그렇게 썼습니다. 실제로 함수 포인터 변수에 항상 일정한 함수만 대입되지 않는 경우도 많고요. (함수 심볼이라면 그 함수가 절대로 변할 일이 없어야 겠죠) 이걸 함수 심볼로 처리하면 혼란을 줄 수 있지 않을까요?

그리고 함수 포인터에 대한 처리가 그렇게 많이 필요한 건지도 모르겠습니다. 기껏해 봐야 call할 때 immediate value가 아닌 뭔가 다른 걸 넘겨 주는 것 뿐이지 않나요.

- 토끼군

luftpalen의 이미지

답변과 관심 감사합니다 : )

또 하나 물어볼것이 있는데,
파싱하면 yyerror 함수가 호출되면서 파싱이 중단되어 버리는데,
문법 오류가 나도 그 부분을 건너뛰면서 계속 파싱을 할 수 있을까요?

doldori의 이미지

seoleda wrote:
혹시 실제 C언어에서는 어떻게 분류했는지 아시는분 계시나요?

함수형과 함수 포인터형은 다릅니다. 함수 포인터형은 함수형으로부터 유도된 포인터형입니다.
함수형은 함수의 반환형이 될 수 없고 sizeof의 피연산자도 될 수 없으며 배열의 원소형도
될 수 없습니다.
typedef void F(void);      // F is a function type
typedef void (*PF)(void);  // PF is a pointer-to-function type

F f(void);   // error
PF g(void);  // ok

sizeof(F);   // error
sizeof(PF);  // ok

F fa[];      // error
PF pfa[];    // ok
seoleda의 이미지

tokigun wrote:
seoleda wrote:
제 생각으로는 함수 포인터라고 하면, 내용이야 어찌 됐건 주소를 담고 있으니 변수심볼로 볼 수도 있을것 같고, 어쨋뜬 담고있는 내용이 함수의 시작번지이고 하니 컴파일시에 함수포인터에 대해서는 함수에 준하는 처리를 해줘야 할 듯 하니 함수심볼이라고 할 수도 있을 것 같습니다.

토끼군님은 왜 함수포인터를 변수 심볼로 처리하는게 맞다고 생각하는지 설명해 주실수 있으신가요?

함수의 주소를 저장할 수 있다고 해서 포인터 변수라는 게 바뀌는 건 아니라고 생각해서 그렇게 썼습니다. 실제로 함수 포인터 변수에 항상 일정한 함수만 대입되지 않는 경우도 많고요. (함수 심볼이라면 그 함수가 절대로 변할 일이 없어야 겠죠) 이걸 함수 심볼로 처리하면 혼란을 줄 수 있지 않을까요?

그리고 함수 포인터에 대한 처리가 그렇게 많이 필요한 건지도 모르겠습니다. 기껏해 봐야 call할 때 immediate value가 아닌 뭔가 다른 걸 넘겨 주는 것 뿐이지 않나요.

- 토끼군

네.. 답변 감사합니다. 궁금해서 간단하게 프로그램 작성해서 gdb로 심볼테이블을 확인해 봤는데 함수포인터는 변수로 분류되는 군요.

그런데, 이건 다른 얘기긴 한데, 자동변수는 심볼테이블로 관리하지 않나요?
함수포인터를 지역변수로 선언하고, info variable var 이런식으로 gdb에 명령을 내리니깐 없다고 하더군요. 혹시나 해서 전역변수로 선언하니, 함수포인터는 심볼테이블에서 변수로 관리하더군요. 이것때문에 한참 헤멨습니다. ^^

저는 컴파일러가 함수포인터 심볼을 발견하면, jmp 어쩌구 저꺼구. 하는 어셈블러를 생성하고, 그냥 변수를 만나면 mov 어쩌구 저쩌구 .. 라고 생성할 것이라고 혼자 상상했습니다.

seoleda의 이미지

luftpalen wrote:
답변과 관심 감사합니다 : )

또 하나 물어볼것이 있는데,
파싱하면 yyerror 함수가 호출되면서 파싱이 중단되어 버리는데,
문법 오류가 나도 그 부분을 건너뛰면서 계속 파싱을 할 수 있을까요?

글세요. 조금 어려울 것 같습니다. 언뜻 생각하기로는 에러가 난 부분에서 그 부분과 관련된 AST를 찾아서 모두 지우거나 복구를 해아 할 것 같은데 잘 모르겠네요.

제가 예전에 짰을대는 라인 단위로 파싱을 하도록 해서 중간에 에러가 나면 그 라인만 건너뛰고 돌아가도록 한적은 있었습니다만, 4년도 넘은 일이라... 제 기억에 어느 책에서 yyerror을 처리하는 방법을 본것도 같은데 그게 그 내용인지는 모르겠네요. 지금은 책도 없고요. ^^
오랄리 인가요? 거기서 나온 빨간색 책이였는데.. lex and yacc인가? 그런 비스무리한 재목이였습니다. 그 책이 yacc 이해하는데는 좋았습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.