下面来分析
flex文件的最后一部份,就是辅助代码部份,这部份代码是原封不动地拷贝到生成的文件里。它的代码如下:
#001 %%
这个双百分号开始,就表示
flex文件的第三部分开始了。
#002
#003 LLScriptAllocationManager *gAllocationManager;
定义分配管理器指针。
#004 LLScriptScript
*gScriptp;
定义脚本的指针。
#005
#006 // Prototype for the yacc parser entry point
#007 int yyparse(void);
前置声明
yacc的语法分析的函数。
#008
#009 int yyerror(const char *fmt, ...)
#010 {
#011
gErrorToText.writeError(yyout, gLine, gColumn, LSERROR_SYNTAX_ERROR);
#012
return 0;
#013 }
分析出错时输出错误位置。
#014
#015 //#define EMERGENCY_DEBUG_PRINTOUTS
#016 //#define EMIT_CIL_ASSEMBLER
#017
下面开始进行脚本编译处理。
#018 BOOL lscript_compile(const char* src_filename, const char* dst_filename,
#019
const char* err_filename, BOOL is_god_like)
#020 {
#021
BOOL b_parse_ok = FALSE;
#022
BOOL b_dummy = FALSE;
#023
U64 b_dummy_count = FALSE;
#024
LSCRIPTType type = LST_NULL;
#025
#026
gInternalColumn = 0;
#027
gInternalLine = 0;
#028
gScriptp = NULL;
#029
#030
gErrorToText.init();
#031
init_supported_expressions();
#032
init_temp_jumps();
#033
gAllocationManager = new LLScriptAllocationManager();
#034
下面打开脚本文件。
#035
yyin = LLFile::fopen(src_filename, "r");
#036
if (yyin)
#037
{
打开错误输出文件。
#038
yyout = LLFile::fopen(err_filename, "w");
#039
#040
// Reset the lexer's internal buffering.
#041
读入脚本文件。
#042
yyrestart(yyin);
#043
进行语法分析。
#044
b_parse_ok = !yyparse();
#045
#046
if (b_parse_ok)
#047
{
语法分析成功。
#048 #ifdef EMERGENCY_DEBUG_PRINTOUTS
#049
char compiled[256];
#050
sprintf(compiled, "%s.o", src_filename);
#051
FILE* compfile;
#052
compfile = LLFile::fopen(compiled, "w");
#053 #endif
#054
#055
if(dst_filename)
#056
{
#057
gScriptp->setBytecodeDest(dst_filename);
#058
}
#059
#060
gScriptp->mGodLike = is_god_like;
#061
#062
gScopeStringTable = new LLStringTable(16384);
#063 #ifdef EMERGENCY_DEBUG_PRINTOUTS
下面的代码遍历语法树,生成脚本的中间代码。
#064
gScriptp->recurse(compfile, 0, 4, LSCP_PRETTY_PRINT, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count, NULL, NULL,
#065 0, NULL, 0, NULL);
#066 #endif
#067
gScriptp->recurse(yyout, 0, 0, LSCP_PRUNE, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count,
#068 NULL, NULL, 0, NULL, 0, NULL);
#069
gScriptp->recurse(yyout, 0, 0, LSCP_SCOPE_PASS1, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count, NULL, NULL, 0,
#070 NULL, 0, NULL);
#071
gScriptp->recurse(yyout, 0, 0, LSCP_SCOPE_PASS2, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count, NULL, NULL, 0,
#072 NULL, 0, NULL);
#073
gScriptp->recurse(yyout, 0, 0, LSCP_TYPE, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count,
#074 NULL, NULL, 0, NULL, 0, NULL);
#075
if (!gErrorToText.getErrors())
#076
{
#077
gScriptp->recurse(yyout, 0, 0, LSCP_RESOURCE, LSPRUNE_INVALID, b_dummy,
#078 NULL, type, type, b_dummy_count, NULL, NULL, 0, NULL, 0, NULL);
#079 #ifdef EMERGENCY_DEBUG_PRINTOUTS
#080
gScriptp->recurse(yyout, 0, 0, LSCP_EMIT_ASSEMBLY, LSPRUNE_INVALID, b_dummy, NULL, type, type,
#081 b_dummy_count, NULL, NULL, 0, NULL, 0, NULL);
#082 #endif
#083 #ifdef EMIT_CIL_ASSEMBLER
#084
const char* cil_output_file_name = dst_filename? dst_filename : "lscript.cil";
#085
FILE* cilout = LLFile::fopen(cil_output_file_name, "w");
#086
if(NULL == cilout)
#087
{
#088
fprintf(yyout, "Error opening cil output file %s/n", cil_output_file_name);
#089
}
#090
else
#091
{
#092
gScriptp->recurse(cilout, 0, 0, LSCP_EMIT_CIL_ASSEMBLY, LSPRUNE_INVALID, b_dummy, NULL,
#093 type, type, b_dummy_count, NULL, NULL, 0, NULL, 0, NULL);
#094
if(fclose(cilout) == EOF)
#095
{
#096
fprintf(yyout, "Error closing cil output file %s/n", cil_output_file_name);
#097
}
#098
}
#099 #endif
#100
gScriptp->recurse(yyout, 0, 0, LSCP_EMIT_BYTE_CODE, LSPRUNE_INVALID, b_dummy, NULL, type, type,
#101 b_dummy_count, NULL, NULL, 0, NULL, 0, NULL);
#102
}
#103
delete gScopeStringTable;
#104
gScopeStringTable = NULL;
#105 #ifdef EMERGENCY_DEBUG_PRINTOUTS
#106
fclose(compfile);
#107 #endif
#108
}
#109
fclose(yyout);
#110
}
#111
#112
fclose(yyin);
#113
delete gAllocationManager;
#114
delete gScopeStringTable;
#115
#116
return b_parse_ok && !gErrorToText.getErrors();
#117 }
#118
#119
输入文件名称的脚本编译函数。
#120 BOOL lscript_compile(char *filename, BOOL is_god_like = FALSE)
#121 {
生成输入和输出文件名称。
#122
char src_filename[MAX_STRING];
#123
sprintf(src_filename, "%s.lsl", filename);
#124
char err_filename[MAX_STRING];
#125
sprintf(err_filename, "%s.out", filename);
调用前面脚本编译函数。
#126
return lscript_compile(src_filename, NULL, err_filename, is_god_like);
#127 }
#128
#129
下面处理
GCC编译问题。
#130 S32 yywrap()
#131 {
#132 #if defined(FLEX_SCANNER) && !defined(LL_WINDOWS)
#133
// get gcc to stop complaining about lack of use of yyunput
#134
(void) yyunput;
#135 #endif
#136
return(1);
#137 }
#138
跳过所有脚本注释部份。
#139 void comment()
#140 {
#141
char c;
#142
#143
while ((c = yyinput()) != '/n' && c != 0 && c != EOF)
#144
;
#145 }
#146
统计编译所在的行号和列号。
#147 void count()
#148 {
#149
S32 i;
#150
#151
gColumn = gInternalColumn;
#152
gLine = gInternalLine;
#153
#154
for (i = 0; yytext[i] != '/0'; i++)
#155
if (yytext[i] == '/n')
#156
{
#157
gInternalLine++;
#158
gInternalColumn = 0;
#159
}
#160
else if (yytext[i] == '/t')
#161
gInternalColumn += 4 - (gInternalColumn % 8);
#162
else
#163
gInternalColumn++;
#164 }
#165
分析脚本的字符串。
#166 void parse_string()
#167 {
#168
S32 length = (S32)strlen(yytext);
#169
length = length - 2;
#170
char *temp = yytext + 1;
#171
#172
S32 i;
#173
S32 escapes = 0;
#174
S32 tabs = 0;
#175
for (i = 0; i < length; i++)
#176
{
#177
if (temp[i] == '//')
#178
{
#179
escapes++;
#180
i++;
#181
if (temp[i] == 't')
#182
tabs++;
#183
}
#184
}
#185
#186
S32 newlength = length - escapes + tabs*3;
#187
yylval.sval = new char[newlength + 1];
#188
#189
char *dest = yylval.sval;
#190
#191
for (i = 0; i < length; i++)
#192
{
#193
if (temp[i] == '//')
#194
{
#195
i++;
#196
// linefeed
#197
if (temp[i] == 'n')
#198
{
#199
*dest++ = 10;
#200
}
#201
else if (temp[i] == 't')
#202
{
#203
*dest++ = ' ';
#204
*dest++ = ' ';
#205
*dest++ = ' ';
#206
*dest++ = ' ';
#207
}
#208
else
#209
{
#210
*dest++ = temp[i];
#211
}
#212
}
#213
else
#214
{
#215
*dest++ = temp[i];
#216
}
#217
}
#218
yylval.sval[newlength] = 0;
#219 }
#220
辅助代码部份主要调用语法分析生成函数来编译脚本,当然语法分析的函数里又调用词法分析的函数来获取所需要的单词,最后生成脚本的树中间代码。