본문 바로가기

study/42Seoul

[minishell] parsing - 1.preprocessing

1-1.tokenization

관련 PR : #33
token.c arr.c libft/lst*.c

 

 

토큰화 (tokenization)는 입력으로 받아온 문자열 형태의 데이터를 해석할 수 있는 token으로 만드는 과정이다.

아래의 구조체 struct s_token을 사용하여 토큰화를 진행하였다.
token 구조체는 생성될 때 libft에 구현된 연결리스트 nodecontent에 저장된다.

구조체 정보

typedef struct s_token
{
    t_ttype    type;
    char    *str;
}    t_token;

 

enum e_token_type ( t_ttype ) 정보

typedef enum e_token_type
{
    T_WORD,     // space 문자와 아래 문자들을 제외한 모든 문자
    T_PIPE,     // |
    T_IO,       // <<, <, >>, >
    T_PAREN,    // (, )
    T_OPER      // &&, ||
    T_QUOTE,    // ", '
    T_SPACE,
    T_DOLLER,   // $
    T_ENVP
}    t_ttype;

 

처음에는 enum e_token_type에서 실제로 사용될 수 있는 token에 대한 정보만 남겨두려고 했는데

코드를 작성하다 보니 이후에 쓰이는 경우가 생겨 필요한 모든 token type을 추가해서 총 9개가 되었다.

구조체를 활용하는 부분은 이곳에 자세히 작성해두었다.

 

구현 과정

토큰화를 진행할 때 구조체 리스트를 어떤 방법으로 생성할 지에 대해 굉장히 고민이 많았다.

팀원과 함께 같이 상의하면서 배열을 활용하기로 했다.

입력 문자열 str과 동일한 크기의 int 배열 arr을 사용하여 각 문자에 해당하는 token type을 매기는 방식이다.

token type을 매길 때 사용하는 함수는 이후에 재사용하기 때문에 함수 포인터를 활용했다.

 

검사하는 token에 대한 정보들은 다음과 같이 Norm을 고려하여 const 배열로 선언해주었다.

symbol에서 작성된 순서대로 우선순위가 높다. 여기서는 이 우선순위가 가장 높게 되어있다.

cust_idx에서 십의 자리는 enum e_token_type 에 정의된 type을 의미하고, 일의 자리는 symbol의 길이 확인용으로 아래와 같이 사용하였다.

const char    symbol[12][3] = {"\"", "\'", "&&", "||", "(", ")", \
                 "<<", "<", ">>", ">", "|", " "};
const int    cust_idx[] = {50, 52, 41, 43, 30, 32, \
                  21, 22, 23, 24, 10, 60};
// len = cust_idx % 10 % 2 + 1;

 

배열을 cust_idx에 맞게 다 채우고 나면 따옴표 처리를 진행했다.

따옴표로 감싸는 문자열에 대해서는 해석되지 않도록 모두 T_WORD type으로 채워주었다.

 

그리고 나서 만들어진 int 배열을 바탕으로 단방향 연결리스트를 만들어준다.

만들 때 단방향 연결리스트의 head를 생성해두어서 head는 있고 tail은 없는 구조로 되어있다.

단방향 연결리스트의 각 nodetoken 정보는 앞에서 본 구조체 형태처럼 type과 그에 해당하는 문자열(str)이 동적할당되어 들어있게 된다.


1-2.check syntax error

관련 PR: #44   
check_syntax.c, check_type.c

 

 

token으로 이루어진 단방향 연결리스트는 이후 이진 트리 형태로 변경한다.
이진 트리 형태로 변경하기 전에 syntax error를 검사한다.

 

검사 기준

  1. 괄호가 올바른 짝을 이루고 있는가?
    • )( , (() , )() , )) 와 같은 경우는 올바르지 않음
    • error message: minishell: syntax error: invalid parenthesis pair
  2. redirection( T_IO ) 뒤에 file명( T_WORD )이 입력되었는가?
    • error message: minishell: syntax error: redirection file does not exist
  3. 괄호 chunk가 &&, || 의 앞 또는 뒤에 위치하는가?
    • 괄호 앞 뒤는 괄호를 하나의 chunk로 보고 검사를 진행한다.
    • (( cmd )) , () , (()) 와 같은 경우는 올바르지 않음
    • error message : minishell: syntax error: invalid parenthesis position
  4. dsv( &&, ||, | )라면 dsv 기준 왼쪽 오른쪽에 cmd가 입력되었는가?
    • error message
      • minishell: syntax error: &&
      • minishell: syntax error: ||
      • minishell: syntax error: |
  5. cmd가 하나 이상 들어왔는가?
    • 스페이스만 들어왔을 경우, 또는 redirection만 입력될 경우는 올바르지 않음
    • error message : minishell: syntax error: command not found

각 기준은 번호 순서대로 우선순위를 가진다.
따라서 먼저 검사되는 기준에 부합하지 않을 경우, 그에 해당하는 에러 메시지를 출력하고 새로운 입력을 받게 된다.

 

subject에서 요구하는 괄호는 &&, || 의 우선순위를 표현하는 것에 의의가 있다고 생각해서 3번에 대한 검사 기준을 설정해두었다.

그리고 bash에서는 cmd가 존재하지 않는 redirection만 들어온 입력의 경우에도 실행되지만, 우리의 minishell에서는 syntax error로 처리했다.

'study > 42Seoul' 카테고리의 다른 글

[C] stat / lstat / fstat 함수  (0) 2023.01.06