[루아2.5] lex

2 분 소요

루아 2.5

드디어 루아 2.x 대 버전의 마지막 릴리즈입니다. 루아 2.4 대비 루아 2.5는 바뀐 부분이 많이 없어 보입니다. 변경점 위주로 빨리 읽고 버전 3.0에서 다시 자세히 읽기를 하겠습니다. 그럼 이번에도 루아 개발자가 작성한 릴리즈 노드를 보겠습니다.

  • io and string libraries are now based on pattern matching; the old libraries are still available for compatibility
  • dofile and dostring can now return values (via return statement)
  • better support for 16- and 64-bit machines
  • expanded documentation, with more examples

라는 군요. 대충 번역하겠습니다. IO와 스트링 라이브러리를 패턴 매칭 베이스로 바꿨답니다. 그래도 여전히 예전 라이브러리도 쓸 수 있다고 하네요. dofile과 dostring 함수가 리턴값을 가진다고 합니다. 16비트와 64비트 머신을 더 잘 지원한다고 하네요. 그리고 문서화를 더 열심히 했다고 합니다. 그럼 바뀐 내용을 염두하고 소스 코드를 읽겠습니다.

lex.c

오늘도 lex.c부터 읽기 시작하겠습니다. 변경 내용은 그리 많지 않습니다.

[2.4]
#define next() { current = input(); }
#define save(x) { *yytextLast++ = (x); }
#define save_and_next()  { save(current); next(); }

static int current;
static char *yytext = NULL;
static int textsize = 0;
static char *yytextLast;

static Input input;

[2.5]
#define next() (current = input())
#define save(x) (yytext[tokensize++] = (x))
#define save_and_next()  (save(current), next())


static int current;  /* look ahead character */
static Input input;  /* input function */

정적 전역 변수인 yytext가 없어졌습니다. 그러나 save() 매크로에는 여전히 yytext를 쓰네요. yytext는 어디로 간 걸까요? 조금 이따가 나옵니다. 그 때 코드를 읽으면서 다시 말하겠습니다. 변경된 코드를 그대로 해석만 해보면, 루아 2.4까지는 yytext 버퍼 포인터를 yytextLast 포인터에 받아서 yytextLast 포인터를 늘리면서 토큰 텍스트 데이터를 입력합니다. 루아 2.5부터는 포인터를 따로 사용하지 않고 tokensize 변수를 배열 인덱스로 삼아서 토큰 텍스트 데이터를 입력합니다. 그러고 보니 루아 2.4에서도 textsize 변수로 같은 동작을 했었네요. 코드를 더 깔끔하게 바꿨습니다.

[2.4]
void lua_setinput (Input fn)
{
  current = ' ';
  input = fn;
  if (yytext == NULL)
  {
    textsize = MINBUFF;
    yytext = newvector(textsize, char);
  }
}

[2.5]
void lua_setinput (Input fn)
{
  current = '\n';
  lua_linenumber = 0;
  input = fn;
}

인풋 소스를 지정하는 함수입니다. lexer를 초기화할 때 호출합니다. 루아 2.4에서는 yytext가 전역 변수이므로 초기화하는 이 함수에서 yytext에 메모리를 할당합니다. 그러나 루아 2.5에서는 해당 코드가 없습니다. 점점 yytext의 정체가 궁금해집니다.

[2.4]
int luaY_lex (void)
{
  double a;
  static int linelasttoken = 0;
  if (lua_debug)
    luaI_codedebugline(linelasttoken);
  linelasttoken = lua_linenumber;

[2.5]
int luaY_lex (void)
{
  static int linelasttoken = 0;
  double a;
  int buffsize = MINBUFF;
  char *yytext = luaI_buffer(buffsize);
  yytext[1] = yytext[2] = yytext[3] = 0;
  if (lua_debug)
    luaI_codedebugline(linelasttoken);
  linelasttoken = lua_linenumber;

사라졌던 yytext는 여기에 있습니다. 정적 전역 변수가 로컬 변수로 갔네요.

[2.4]
      case EOF:
      case 0:
       return 0;
      case '\n': linelasttoken = ++lua_linenumber;
      case ' ':
      case '\r':  /* CR: to avoid problems with DOS/Windows */
      case '\t':
        next();
        continue;

[2.5]
      case ' ': case '\t': case '\r':  /* CR: to avoid problems with DOS */
        next();
        continue;

동작 차이는 없고 코드를 조금 더 보기 좋게 만든 수준으로 바꿨습니다.

[2.4]
        a=0.0;
        do { a=10.0*a+(current-'0'); save_and_next(); } while (isdigit(current));
        if (current == '.') save_and_next();

[2.5]
	    a=0.0;
        do {
          a=10.0*a+(current-'0');
          save_and_next();
        } while (isdigit(current));
        if (current == '.') {
          save_and_next();
          if (current == '.')
            luaI_syntaxerror(
              "ambiguous syntax (decimal point x string concatenation)");
        }

에러 추가 코드를 제외하면 완전히 동일한 코드입니다. 다만 루아 2.4까지 코드에서 한 줄에 statement 여러 개 쓴 코드를 한 줄에 한 statement를 쓴 일반적인 코드로 바꿨습니다.

lex.c 파일에 변경 부분이 몇개 더 있는데, 대부분 이런 패턴입니다.

댓글남기기