微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

修改lua的代码解析

有时候希望在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行的代码^_^

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐