第二人生的源码分析(108)脚本的语法分析(1)
当玩家书写一个脚本时,如果写错了脚本,那么肯定运行不了。现在就来分析怎么样确保脚本是正确的问题,如果不正确就需要显示出来那里不正确。脚本是否正确,其实是根据脚本的语法来判断的。那么又怎么样来构造语法分析的程序呢?在第二人生里是通过使用程序bison.exe来创建的。
下面先来看看bison.exe是做什么东西的:
Yacc 代表 Yet Another Compiler Compiler。 Yacc 的 GNU 版叫做 Bison。它是一种工具,将任何一种编程语言的所有语法翻译成针对此种语言的 Yacc 语 法解析器。它用巴科斯范式(BNF, Backus Naur Form)来书写。按照惯例,Yacc 文件有 .y 后缀。编译行如下调用 Yacc 编译器:
$ yacc <options> <filename ending with .y>
我们看到 Lex 从输入序列中识别标记。如果你在查看标记序列,你可能想在这一序列出现时执行某一动作。这种情况下有效序列的规范称为语法。Yacc 语法文件包括这一语法规范。它还包含了序列匹配时你想要做的事。
bison的语法文件,也是定义、规则和辅助代码部份。第二人生里的定义语法文件如下:
#001 %{
#002 #include "linden_common.h"
#003 #include "lscript_tree.h"
#004
#005 #ifdef __cplusplus
#006 extern "C" {
#007 #endif
#008
#009 int yylex(void);
#010 int yyparse( void );
#011 int yyerror(const char *fmt, ...);
#012
#013 #if LL_LINUX
#014 // broken yacc codegen... --ryan.
#015 #define getenv getenv_workaround
#016 #endif
#017
#018 #ifdef LL_WINDOWS
#019 #pragma warning (disable : 4702) // warning C4702: unreachable code
#020 #pragma warning( disable : 4065 ) // warning: switch statement contains 'default' but no 'case' labels
#021 #endif
#022
#023 #ifdef __cplusplus
#024 }
#025 #endif
#026 %}
#027
#028 %union
#029 {
#030 S32 ival;
#
#032 char *sval;
#033 class LLScriptType *type;
#034 class LLScriptConstant *constant;
#035 class LLScriptIdentifier *identifier;
#036 class LLScriptSimpleAssignable *assignable;
#037 class LLScriptGlobalVariable *global;
#038 class LLScriptEvent *event;
#039 class LLScriptEventHandler *handler;
#040 class LLScriptExpression *expression;
#041 class LLScriptStatement *statement;
#042 class LLScriptGlobalFunctions *global_funcs;
#043 class LLScriptFunctionDec *global_decl;
#044 class LLScriptState *state;
#045 class LLScritpGlobalStorage *global_store;
#046 class LLScriptScript *script;
#047 };