修改lua的代码解析

来源:互联网 发布:c语言insert函数 编辑:程序博客网 时间:2024/06/05 22:32

有时候希望在lua中加入自定义风格的代码,例如将某个经常用的函数简化为一个符号,在开发某个GAL引擎时,因为需要大量的用到回显文字的命令,所以希望将该命令简化,可以极大地提升写脚本的效率.例如:

//原有脚本实现echo("这真是一个糟糕的事情","人物1");echo("这真是一个糟糕的事情","人物2");echo("这真是一个糟糕的事情","人物3");echo("这真是一个糟糕的事情","人物4");...//修改后的实现@人物1:"这真是一个不错的事情"@人物2:"这真是一个不错的事情"@人物3:"这真是一个不错的事情"@人物4:"这真是一个不错的事情"...

这看起来是一件不错的事,^_^想象一下一个文字游戏,基本上都是文字回显的命令,简化后的效率提升不言而喻.

当然,这就要拿lua(遵循GPL协议)的源码开刀,lua的脚本解析主要在llex.c文件中,通过分析每个字符,提取出关键字,符号,变量等传递给lparser.c检查语法.

而在llex.c中最主要的函数是static int llex (LexState *ls, SemInfo *seminfo),该函数负责分割并解析每个WORD,然后返回给语法检查器,我们需要在这里动手将lua中没有定义的符号@解析为echo命令并将两个参数返回.

//翻译并传递echo命令           char *str_echo=0,*str_rolename=0;           int len_echo=0,len_rolename=0;           int trans_echo_command_step = -1;                                   static int llex (LexState *ls, SemInfo *seminfo) {             luaZ_resetbuffer(ls->buff);                                     if(trans_echo_command_step!=-1)             {                 switch(trans_echo_command_step)                 {                 case 1:   //返回左括号                     trans_echo_command_step++;                     return 40;                                         case 2:   //返回echo字符串                     trans_echo_command_step++;                     seminfo->ts = luaX_newstring(ls, str_echo, len_echo);                     return TK_STRING;                                         case 3:   //返回逗号                     trans_echo_command_step++;                     return 44;                                         case 4:   //返回rolename字符串                     trans_echo_command_step++;                     seminfo->ts = luaX_newstring(ls, str_rolename, len_rolename);                     return TK_STRING;                                         case 5:   //返回右括号                     trans_echo_command_step=-1;                     return 41;                 }             }                                                             for (;;) {               switch (ls->current) {                 case '\n': case '\r': {  /* line breaks */        inclinenumber(ls);                   break;                 }                 case ' ': case '\f': case '\t': case '\v': {  /* spaces */        next(ls);                   break;                 }                                       /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!                                    fscript_echo_process                           */      case '@':                     {                             TString *ts;                             str_echo=0,str_rolename=0;                             len_echo=0,len_rolename=0;                                                     next(ls);                                                     if(ls->current != 34)   // 如果不是 " 则读取rolename                             {                                 // 读取人名                                 do                      {                                        save_and_next(ls);                                 }                                    while (ls->current != ':');                                                         // 复制人名                                 str_rolename = luaZ_buffer(ls->buff);                                 len_rolename = ls->buff->n;                                                         next(ls); // 跳过 :                             }                                                     fs_get_string(ls, ls->current);                             str_echo = luaZ_buffer(ls->buff) + len_rolename + 1;                             len_echo = ls->buff->n - len_rolename - 2;                                                     //第一步返回命令                             trans_echo_command_step = 1;                                                     ts = luaX_newstring(ls, "doecho",6);                               seminfo->ts = ts;                             if (isreserved(ts))  /* reserved word? */                       return ts->tsv.extra - 1 + FIRST_RESERVED;                                else                      return TK_NAME;                     }                                         case '-': {  /* '-' or '--' (comment) */        next(ls);                   if (ls->current != '-') return '-';                   /* else is a comment */        next(ls);                   if (ls->current == '[') {  /* long comment? */          int sep = skip_sep(ls);                     luaZ_resetbuffer(ls->buff);  /* `skip_sep' may dirty the buffer */          if (sep >= 0) {                       read_long_string(ls, NULL, sep);  /* skip long comment */            luaZ_resetbuffer(ls->buff);  /* previous call may dirty the buff. */            break;                     }                   }                   /* else short comment */        while (!currIsNewline(ls) && ls->current != EOZ)                     next(ls);  /* skip until end of line (or end of file) */        break;                 }                 case '[': {  /* long string or simply '[' */        int sep = skip_sep(ls);                   if (sep >= 0) {                     read_long_string(ls, seminfo, sep);                     return TK_STRING;                   }                   else if (sep == -1) return '[';                   else lexerror(ls, "invalid long string delimiter", TK_STRING);                 }                 case '=': {                   next(ls);                   if (ls->current != '=') return '=';                   else { next(ls); return TK_EQ; }                 }                 case '<': {                   next(ls);                   if (ls->current != '=') return '<';                   else { next(ls); return TK_LE; }                 }                 case '>': {                   next(ls);                   if (ls->current != '=') return '>';                   else { next(ls); return TK_GE; }                 }                 case '~': {                   next(ls);                   if (ls->current != '=') return '~';                   else { next(ls); return TK_NE; }                 }                 case ':': {                   next(ls);                   if (ls->current != ':') return ':';                   else { next(ls); return TK_DBCOLON; }                 }                 case '"': case '\'': {  /* short literal strings */        read_string(ls, ls->current, seminfo);                   return TK_STRING;                 }                 case '.': {  /* '.', '..', '...', or number */        save_and_next(ls);                   if (check_next(ls, ".")) {                     if (check_next(ls, "."))                       return TK_DOTS;   /* '...' */          else return TK_CONCAT;   /* '..' */        }                   else if (!lisdigit(ls->current)) return '.';                   /* else go through */      }                 case '0': case '1': case '2': case '3': case '4':                 case '5': case '6': case '7': case '8': case '9': {                   read_numeral(ls, seminfo);                   return TK_NUMBER;                 }                 case EOZ: {                   return TK_EOS;                 }                 default: {                     if (lislalpha(ls->current)||  ls->current > 0x80) {  /* identifier or reserved word? */               TString *ts;                            do {                                if(ls->current > 0x80)                                {                                    save_and_next(ls);                                    save_and_next(ls);                                }                                else                        save_and_next(ls);                            }                            while (lislalnum(ls->current) || ls->current > 0x80);                            ts = luaX_newstring(ls, luaZ_buffer(ls->buff),                                luaZ_bufflen(ls->buff));                            seminfo->ts = ts;                            if (isreserved(ts))  /* reserved word? */                   return ts->tsv.extra - 1 + FIRST_RESERVED;                            else {                                return TK_NAME;                            }                        }                        else {  /* single-char tokens (+ - / ...) */               int c = ls->current;                            next(ls);                            return c;                        }                             }               }                                     }           }

加感叹号的地方为解析@符号的地方,要注意的是这里要完全按照lua的流程依次将命令,左右括号,逗号和两个参数都按照顺序传递回去,不然的话语法检查器会认为语法错误!

另外,这里已经添加了中文的支持,想得到中文支持的朋友可以参考第166到177行的代码^_^