[루아2.2] hash inout tree table

4 분 소요

hash.c

코드가 많이 바뀌거나 큰 기능이 추가되지 않았습니다. Value 구조체에 Byte가 TFunc로 바뀐 것에 대응하는 코드를 변경했습니다. 이런 패턴입니다.

[2.1]
    case LUA_T_NIL: return 1;
    case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2);
    case LUA_T_STRING: return streq(svalue(t1), svalue(t2));
    case LUA_T_ARRAY: return avalue(t1) == avalue(t2);
    case LUA_T_FUNCTION: return bvalue(t1) == bvalue(t2);
    case LUA_T_CFUNCTION: return fvalue(t1) == fvalue(t2);
    default: return uvalue(t1) == uvalue(t2);

[2.2]
    case LUA_T_NIL: return 1;
    case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2);
    case LUA_T_STRING: return streq(svalue(t1), svalue(t2));
    case LUA_T_ARRAY: return avalue(t1) == avalue(t2);
    case LUA_T_FUNCTION: return t1->value.tf == t2->value.tf;
    case LUA_T_CFUNCTION: return fvalue(t1) == fvalue(t2);
    default: return uvalue(t1) == uvalue(t2);

바뀐 코드가 한 번에 눈에 들어오지 않을 정도로 작은 코드 변경입니다. 어디냐면 LUA_T_FUNCTION에 대한 case 구문 코드가 다릅니다.

그리고 에러 메시지 출력하는 함수 이름을 바꿨네요.

[2.1]
lua_reportbug ("unexpected type to index table");

[2.2]
lua_error ("unexpected type to index table");

더 직관적인 이름으로 바꿨습니다. 이게 낫네요.

이 정도 변화 외에 hash.c 파일은 바뀐 부분이 없습니다.

inout.c

역시 동작을 바꾸거나 버그를 수정한 것으로 보이는 코드 변경점은 보이지 않습니다. 코드를 정리한 수준의 변경입니다.

[2.1]
/* Exported variables */
Word lua_linenumber;
Bool lua_debug;
Word lua_debugline = 0;


/* Internal variables */
 
#ifndef MAXFUNCSTACK
#define MAXFUNCSTACK 100
#endif

[2.2]
#ifndef MAXFUNCSTACK
#define MAXFUNCSTACK 100
#endif

#define MAXMESSAGE MAXFUNCSTACK*80


/* Exported variables */
Word lua_linenumber;
Bool lua_debug = 0;
char *lua_parsedfile;

이런 수준 변경입니다.

[2.1]
char *lua_openfile (char *fn)
{
 lua_linenumber = 1;
 lua_setinput (fileinput);
 fp = fopen (fn, "r");
 if (fp == NULL)
 {
   static char buff[32];
   sprintf(buff, "unable to open file %.10s", fn);
   return buff;
 }
 return lua_addfile (fn);
}

[2.2]
char *lua_openfile (char *fn)
{
 lua_setinput (fileinput);
 if (fn == NULL)
 {
   fp = stdin;
   fn = "(stdin)";
 }
 else
   fp = fopen (fn, "r");
 if (fp == NULL)
 {
   static char buff[255];
   sprintf(buff, "unable to open file `%.200s'", fn);
   return buff;
 }
 lua_linenumber = 1;
 lua_parsedfile = lua_constcreate(fn)->ts.str;
 return NULL;
}

기능 확장에 관련된 변경이라고 볼 수도 있을 것 같습니다. 루아 2.1에서는 파일 이름이 null이면 에러였지만, 루아 2.2에서는 파일 이름이 null이면 표준 입력에 연결합니다.

tree.c

다듬는 수준의 코드 수정도 없고 제가 루아 2.1 코드를 읽을 때 이상하다고 생각했던 tree_next() 함수를 아예 삭제했습니다. 역시 코드가 이상하다 했더니만..

[2.1]
static TreeNode *tree_next (TreeNode *node, char *str)
{
 if (node == NULL) return NULL;
 else if (str == NULL) return node;
 else
 {
  int c = lua_strcmp(str, node->ts.str);
  if (c == 0)
   return node->left != NULL ? node->left : node->right;
  else if (c < 0)
  {
   TreeNode *result = tree_next(node->left, str);
   return result != NULL ? result : node->right;
  }
  else
   return tree_next(node->right, str);
 }
}

TreeNode *lua_varnext (char *n)
{
  TreeNode *result;
  char *name = n;
  while (1)
  { /* repeat until a valid (non nil) variable */
    result = tree_next(constant_root, name);
    if (result == NULL) return NULL;
    if (result->varindex != NOT_USED &&
        s_tag(result->varindex) != LUA_T_NIL)
      return result;
    name = result->ts.str;
  }
}

[2.2]
static TreeNode *nodebysymbol (TreeNode *root, Word symbol)
{
  TreeNode *t;
  if (root == NULL) return NULL;
  if (root->varindex == symbol) return root;
  t = nodebysymbol(root->left, symbol);
  if (t) return t;
  return nodebysymbol(root->right, symbol);
}

TreeNode *luaI_nodebysymbol (Word symbol)
{
  return nodebysymbol(constant_root, symbol); 
}

루아 2.2에서 변경된 코드가 훨씬 직관적이고 납득되는 코드입니다.

table.c

가비지 컬랙션 관련해서 소소한 변화가 있습니다. 가비지 컬랙션 블럭 사이즈를 느렸고, 함수를 가비지 컬랙션 대상에 포함하면서 관련 코드를 수정했습니다.

[2.1]
#define GARBAGE_BLOCK 256
#define MIN_GARBAGE_BLOCK 10

[2.2]
#define GARBAGE_BLOCK 1024
#define MIN_GARBAGE_BLOCK (GARBAGE_BLOCK/2)

GARBAGE_BLOCK 값을 4배로 늘렸습니다.

[2.1]
void lua_travsymbol (void (*fn)(Object *))
{
 Word i;
 for (i=0; i<lua_ntable; i++)
  fn(&s_object(i));
}

[2.2]
static char *lua_travsymbol (int (*fn)(Object *))
{
 Word i;
 for (i=0; i<lua_ntable; i++)
  if (fn(&s_object(i)))
    return luaI_nodebysymbol(i)->ts.str;
 return NULL;
}

함수 포인터로 테이블 오브젝트에 일괄 작업을 하는 함수 (사실은 그냥 mark 만 하는…) 구현을 바꿨습니다. 루아 2.1은 파라메터 함수 포인터가 리턴이 없는 함수지만 루아 2.2는 함수 포인터가 int를 리턴해서 리턴이 0이 아닐 때에는 심볼의 문자열 정보를 리턴하면서 심볼 테이블 순회를 멈춥니다. 루아 2.2에 새로 구현한 함수 때문에 이렇게 수정한 것인데, 잠시 후에 읽겠습니다.

[2.1]
void lua_markobject (Object *o)
{
 if (tag(o) == LUA_T_STRING && !tsvalue(o)->marked)
   tsvalue(o)->marked = 1;
 else if (tag(o) == LUA_T_ARRAY)
   lua_hashmark (avalue(o));
}

[2.2]
int lua_markobject (Object *o)
{
 if (tag(o) == LUA_T_STRING && !tsvalue(o)->marked)
   tsvalue(o)->marked = 1;
 else if (tag(o) == LUA_T_ARRAY)
   lua_hashmark (avalue(o));
 else if ((o->tag == LUA_T_FUNCTION || o->tag == LUA_T_MARK)
           && !o->value.tf->marked)
   o->value.tf->marked = 1;
 return 0;
}

일단 기존 기능을 유지하는 코드는 바뀐 lua_travsymbol() 함수 코드에 영향을 주지 않도록 항상 0을 리턴합니다. 이러면 lua_markobject() 함수를 함수 포인터로 넘기는 코드는 루아 2.1과 동일하게 동작합니다.

static Object *functofind;
static int checkfunc (Object *o)
{
  if (o->tag == LUA_T_FUNCTION)
    return
       ((functofind->tag == LUA_T_FUNCTION || functofind->tag == LUA_T_MARK)
            && (functofind->value.tf == o->value.tf));
  if (o->tag == LUA_T_CFUNCTION)
    return
       ((functofind->tag == LUA_T_CFUNCTION || functofind->tag == LUA_T_CMARK)
            && (functofind->value.f == o->value.f));
  return 0;
}


char *getobjname (lua_Object o, char **name)
{ /* try to find a name for given function */
  functofind = luaI_Address(o);
  if ((*name = luaI_travfallbacks(checkfunc)) != NULL)
    return "fallback";
  else if ((*name = lua_travsymbol(checkfunc)) != NULL)
    return "global";
  else return "";
}

위 코드의 checkfunc() 함수와 getobjname() 함수가 루아 2.2에 새로 추가한 함수입니다. 코드 구현을 보아하니 호스트 프로그램에 공개하는 루아 API 함수인 것 같습니다. 함수 오브젝트 객체를 루아 스택에서 읽어서 해당 함수의 이름을 심볼 테이블에서 읽어옵니다.

댓글남기기