自著——30天自制红孩儿解释器 第9天 解析简单的赋值语句
在第8天的基础上,到了对赋值语句的解析与执行的时候了。
下面举一个赋值语句的简单的例子。 做法是一贯的。
从最简单的出发,再逐渐地增加复杂度。
a=3; 是一个例子,最主要的特征是有一个等号,左边有一个变量名,
右边是一个数值 ,这个语句的含义很简单,把3这个数值赋给a 这个变量。
分号是语句的结束符。
上面是对赋值语句的直观的印象与含义解释。
下面给出一个 赋值语句的比较严格的BNF定义如下:
<assign statment> :== <variable name> = <expression> ; | <variable name> = <value> ;
第9天第一版本程序
需求 : aa=1; 这样的赋值语句的解析,生成 (= aa 1)这样的LISP风格的程序。
实现:
增加parse_variable
parse_assign_statement
第9天第二版本程序
需求 :aa=1; 这样的赋值语句的执行,把变量a的值,记录到符号表中。
实现:增加一个执行按钮,在WEB页面上区别了解析与执行的过程。
增加以下的函数:区别了解析与执行的过程。从程序上看,解析
只进行语法的AST检查。执行过程涉及到符号表的操作。execute
execute_assign_statement
execute_variable
第9天第三版本程序
需求 :aa=1;bb=2;cc=3 这样的多个复合的赋值语句的执行,把变量a的值,记录到符号表中。
实现:增加以下的一个函数,处理多个赋值语句。现在在分号结束符方面还有一个错误。
在最后处目前最多只能有一个分号。如果有两个及两个的分号存在,则出错。
execute_assign_compound_statement
主页面的代码如下:
<HTML>
<HEAD>
<TITLE> 30天自制解释器 9.1 </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<script src='get_token_general.js' ></script>
<script src='execute_lib.js' ></script>
</HEAD>
<BODY>
<p></p>
<p></p>
<p> aget_token_general=5;
b=a+1;
a
</p>
<p> </p>
<p>解析 赋值语句</p>
<p></p>
<textarea id='txt1' rows="20" cols="80"></textarea>
<input type='button' value='执行' οnclick='eval()'>第九天第一版</input>
<textarea id='txt2' rows="20" cols="80"></textarea>
<p>error show area:</p>
<textarea id='txt3' rows="20" cols="80"></textarea>
<script>
function eval()
{
var str=document.getElementById("txt1").innerText;
var result=0;
var token_array=[];
var result_str="";
token_array=get_token_general({"lineno":1,"linelength":str.length,"str":str},token_array);
// result=parse_sim_exp(token_array,0,0);
// result=parse_relation_exp(token_array,0,0);
// result=parse_logic_exp(token_array,0,0);
result= parse_assign_statement(token_array,0,0);
// result=test_symboltable_operation(token_array);
// if (hasError(result.res)==0)
// result=execute_exp(token_array);
// result_str=sysmbol_table_arrtostring(result);
document.getElementById("txt2").innerText=result.res;//result_str; //
}
function test_symboltable_operation(token_arr)
{
var symbol_table_arr=[];
for (var i=0;i<token_arr.length;i++)
{
if (isVariable(token_arr[i])==1)
{symbol_table_arr=symbol_table_do_variable(symbol_table_arr,token_arr[i].value,token_arr[i]);}
}
return symbol_table_arr;
}
function sysmbol_table_arrtostring(c)
{
var tempstr="";
var tempstr_sub="";
for(var k=0;k<c.length;k++)
{
tempstr_sub="";
for(var j=0;j<c[k].ref.length;j++)
{tempstr_sub=tempstr_sub+' [l]: '+c[k].ref[j].lineno+' [p]:'+c[k].ref[j].position;}
tempstr=tempstr+c[k].id+' '+c[k].type+' '+c[k].text+' '+c[k].value+' '+tempstr_sub+'----------';
}
return tempstr;
}
function symbol_table_do_variable(symbol_table_arr,variable_name,token_obj)
{
var result=[];
var lineno=token_obj.lineno;
var position=token_obj.startindex;
if (symbol_table_isexistvar(symbol_table_arr,variable_name)==1)
{
result=symbol_table_setvar_position(symbol_table_arr,variable_name,lineno,position);
}
else
{
if(token_obj.value.length>64)
{ document.getElementById("txt3").innerText=" variable name:["+token_obj.value+"] is too long"+" at "+lineno+" ,position:"+position;
}
else {
result=symbol_table_insertvar(symbol_table_arr,token_obj);
}
}
return result;
}
function symbol_table_findvar(symbol_table_arr,variable_name)
{
var result=-1;
for (var i=0;i<symbol_table_arr.length ;i++ )
{
if (symbol_table_arr[i].text==variable_name)
{
result=i;
break;
}
}
return result;
}
function symbol_table_isexistvar(symbol_table_arr,variable_name)
{
var result =symbol_table_findvar(symbol_table_arr,variable_name);
if(result>=0)
{result=1;}
else
{result=0;}
return result;
}
function symbol_table_setvalue(symbol_table_arr,variable_name,value)
{
var result=symbol_table_arr;
var index =symbol_table_findvar(symbol_table_arr,variable_name);
result[index].value=value;
return result;
}
function symbol_table_setvar_position(symbol_table_arr,variable_name,lineno,position)
{
var index =symbol_table_findvar(symbol_table_arr,variable_name);
var result=symbol_table_arr;
result[index].ref.push({"lineno":lineno,"position":position});
return result;
}
function symbol_table_insertvar(symbol_table_arr,variable_obj)
{
var result=symbol_table_arr;
result.push({"id":symbol_table_arr.length,"type":"variable","value":"","text":variable_obj.value,"ref":[{"lineno":variable_obj.lineno,"position":variable_obj.startindex}],"level":0,"parentid":0});
return result;
}
function sysbom_table_selectvar(symbol_table_arr,variable_name)
{
var index =symbol_table_findvar(symbol_table_arr,variable_name);
return symbol_table_arr[index].value;
}
function parse_assign_statement(arr,i,level)
{
var operator1={};
var operator2={};
var result="";
operator1= parse_variable(arr,i,level);
if(hasError(operator1.res)>=0)
{
return {"res":operator1.res,"i":i};
}
else {result =operator1.res;
i=operator1.i;
}
if ( i<arr.length-2 &&(arr[i+1].value=='=') )
{
operator2= parse_sim_exp(arr,i+2,level);
if( hasError(operator2.res)==-1)
{
result=make_lisp_program_action(arr[i+1].value,result,operator2.res);
//result=execute_binary_relation_operator_action(arr[i+1].value,result,operator2.res);
i=operator2.i;
}
else if(hasError(operator2.res)>=0)
{result=operator2.res;
// break;
}
}
return {"res":result,"i":i};
}
function parse_variable(arr,i,level)
{
var result=0;
// var resultObj={};
if(isVariable(arr[i])==1)
{result=arr[i].value;}
else
{result='[error]: is not a vairable: at '+arr[i].startindex+" value: "+arr[i].value;}
return {"res":result,"i":i};
}
function parse_logic_exp(arr,i,level)
{
var operator1={};
var operator2={};
var result="";
operator1= parse_relation_exp(arr,i,level);
if(hasError(operator1.res)>=0)
{
return {"res":operator1.res,"i":i};
}
else {result =operator1.res;
i=operator1.i;
}
while( i<arr.length-2 &&(arr[i+1].value=='&&'||arr[i+1].value=='||' || arr[i+1].value=='^^') )
{
operator2= parse_relation_exp(arr,i+2,level);
if( hasError(operator2.res)==-1)
{
result=execute_binary_logic_operator_action(arr[i+1].value,result,operator2.res);
i=operator2.i;
}
else if(hasError(operator2.res)>=0)
{result=operator2.res;
break;
}
}
return {"res":result,"i":i};
}
function parse_relation_exp(arr,i,level)
{
var operator1={};
var operator2={};
var result="";
operator1= parse_sim_exp(arr,i,level);
if(hasError(operator1.res)>=0)
{
return {"res":operator1.res,"i":i};
}
else {result =operator1.res;
i=operator1.i;
}
if ( i<arr.length-2 &&(arr[i+1].value=='>'||arr[i+1].value=='<'||arr[i+1].value=='>='||arr[i+1].value=='<='||arr[i+1].value=='=='||arr[i+1].value=='<>') )
{
operator2= parse_sim_exp(arr,i+2,level);
if( hasError(operator2.res)==-1)
{
result=execute_binary_relation_operator_action(arr[i+1].value,result,operator2.res);
i=operator2.i;
}
else if(hasError(operator2.res)>=0)
{result=operator2.res;
// break;
}
}
return {"res":result,"i":i};
}
function parse_sim_exp(arr,i,level)
{
var operator1={};
var operator2={};
var result="";
operator1= parse_term(arr,i,level);
if(hasError(operator1.res)>=0)
{
return {"res":operator1.res,"i":i};
}
else {result =operator1.res;
i=operator1.i;
}
while( i<arr.length-2 &&(arr[i+1].value=='+'||arr[i+1].value=='-') )
{
operator2= parse_term(arr,i+2,level);
if( hasError(operator2.res)==-1)
{
result=execute_binary_calc_operator_action(arr[i+1].value,result,operator2.res);
i=operator2.i;
}
else if(hasError(operator2.res)>=0)
{result=operator2.res;
break;
}
}
return {"res":result,"i":i};
}
function parse_term(arr,i,level)
{
var operator1=0;
var operator2=0;
var result="";
operator1= parse_factor(arr,i,level);
if(hasError(operator1.res)>=0)
{
return {"res":operator1.res,"i":i};
}
else {result =operator1.res;
i=operator1.i;}
while( i<arr.length-2 &&(arr[i+1].value=='*'||arr[i+1].value=='/') )
{
operator2= parse_factor(arr,i+2,level);
if( hasError(operator2.res)==-1)
{
result=execute_binary_calc_operator_action(arr[i+1].value,result,operator2.res);
i=operator2.i;
}
else if(hasError(operator2.res)>=0)
{result=operator2.res;
break;
}
}
return {"res":result,"i":i};
}
function parse_factor(arr,i,level)
{
var result=0;
var resultObj={};
if(arr[i].type==5)
{result=arr[i].value;}
else if (arr[i].type==7)
{
if (arr[i].value=='(')
{
resultObj=parse_sim_exp(arr,i+1,level+1);
result=resultObj.res;
i=resultObj.i;
}
if (i<arr.length-1&& arr[i+1].value==')')
{
i=i+1;
}
else if (i==arr.length-1 && arr[i]!=')')
{
result='[error]: should be ) : at '+arr[i].startindex+" but value: "+arr[i].value;
}
else
{
result='[error]: should be ) : at '+arr[i].startindex+" but value: "+arr[i].value;
}
}
else
{result='[error]: is not number: at '+arr[i].startindex+" value: "+arr[i].value;}
return {"res":result,"i":i};
}
function hasError(str)
{
if(isNum(str)==1)
return -1;
else
return str.indexOf("error");
}
function make_lisp_program_action(operand,operator1,operator2)
{
return "("+ operand + " "+operator1+" "+operator2+")";
}
</script>
</BODY>
</HTML>