代码拉取完成,页面将自动刷新
/**
* 语义分析功能
* @version 0.5
* @author 宫文学
* @license 木兰开源协议
* @since 2021-06-04
*
* 当前特性:
* 1.树状的符号表
* 2.简单的引用消解:没有考虑声明的先后顺序,也没有考虑闭包
* 3.简单的作用域
*
*/
import {AstVisitor, AstNode, Block, Prog, Decl, VariableDecl, FunctionDecl, ParameterList, FunctionCall, Statement, Expression, ExpressionStatement, Binary, IntegerLiteral, DecimalLiteral, StringLiteral, Variable, ReturnStatement, IfStatement, ForStatement, Unary, CallSignature, BooleanLiteral, NullLiteral, VariableStatement, PredefinedTypeExp, ArrayPrimTypeExp, ParenthesizedPrimTypeExp, UnionOrIntersectionTypeExp, TypeReferenceExp, LiteralTypeExp} from './ast';
import {time, assert } from 'console';
import {Symbol, SymKind, FunctionSymbol, VarSymbol, built_ins} from './symbol';
import {Scope} from './scope';
import {SysTypes, Type, FunctionType, ValueType, UnionType} from './types';
import {Op, Operators, Keyword} from './scanner';
import {CompilerError} from './error'
export class SemanticAnalyer{
passes: SemanticAstVisitor[] = [
new TypeResolver(),
new Enter(),
new RefResolver(),
new TypeChecker(),
new AssignAnalyzer(),
new LiveAnalyzer(),
// new TypeConverter(),
new LeftValueAttributor(),
];
errors:CompilerError[] = []; //语义错误
warnings:CompilerError[] = []; //语义报警信息
execute(prog:Prog):void{
this.errors= [];
this.warnings = [];
for (let pass of this.passes){
pass.visitProg(prog);
this.errors = this.errors.concat(pass.errors);
this.warnings = this.warnings.concat(pass.warnings);
}
}
}
export class SemanticError extends CompilerError{
node:AstNode;
constructor(msg:string, node:AstNode, isWarning = false){
super(msg, node.beginPos, /* node.endPos, */ isWarning);
this.node = node;
}
}
abstract class SemanticAstVisitor extends AstVisitor{
errors:CompilerError[] = []; //语义错误
warnings:CompilerError[] = []; //语义报警信息
addError(msg:string, node:AstNode){
this.errors.push(new SemanticError(msg,node));
console.log("Error: @" + node.beginPos.toString() +" : " + msg);
}
addWarning(msg:string, node:AstNode){
this.warnings.push(new SemanticError(msg,node,true));
console.log("Warning: @" + node.beginPos.toString() +" : " + msg);
}
}
/////////////////////////////////////////////////////////////////////////
// 消解类型
//
/**
* 基于TypeExp的AST节点,来确定真正的Type。
* 注意:这个步骤一定要在建立符号表的前面去做,因为创建符号的时候,需要把类型信息拷贝过去。
* todo: 需要处理类型先使用后声明的情况。
*/
class TypeResolver extends SemanticAstVisitor{
visitVariableDecl(variableDecl:VariableDecl):any{
if(variableDecl.typeExp != null){
variableDecl.theType = this.visit(variableDecl.typeExp) as Type;
}
}
visitCallSignature(callSignature:CallSignature):any{
if (callSignature.returnTypeExp != null)
callSignature.returnType = this.visit(callSignature.returnTypeExp) as Type;
super.visitCallSignature(callSignature);
}
visitPredefinedTypeExp(te:PredefinedTypeExp):any{
let t:SysTypes = SysTypes.Any;
switch(te.keyword){
case Keyword.Boolean:
t = SysTypes.Boolean;
break;
case Keyword.Number:
t = SysTypes.Number;
break;
case Keyword.String:
t = SysTypes.String;
break;
case Keyword.Void:
t = SysTypes.Void;
break;
}
return t;
}
visitLiteralTypeExp(te:LiteralTypeExp):any{
let v = te.literal.value;
switch (typeof te.literal){
case 'number':
if (Number.isInteger(v)){
return new ValueType(v, SysTypes.Integer);
}
else{
return new ValueType(v, SysTypes.Decimal);
}
case 'string':
return new ValueType(v, SysTypes.String);
case 'boolean':
return new ValueType(v, SysTypes.Boolean);
case 'object' :
return new ValueType(v, SysTypes.Object); //主要对应null。
case 'undefined' :
return new ValueType(v, SysTypes.UndefinedType);
default:
this.addError("Unsupported type of literal in visitLiteralTypeExp: " + v, te);
}
}
visitArrayPrimTypeExp(te:ArrayPrimTypeExp):any{
// let t = this.visit(te.primType) as Type;
// return new
}
visitParenthesizedPrimTypeExp(te:ParenthesizedPrimTypeExp):any{
return this.visit(te.typeExp) as Type;
}
visitUnionOrIntersectionTypeExp(te:UnionOrIntersectionTypeExp):any{
if (te.op == Op.BitOr){ //'|'
let types:Type[] = [];
for(let t of te.types){
types.push(this.visit(t) as Type);
}
return new UnionType(types);
}
}
visitTypeReferenceExp(te:TypeReferenceExp):any{
}
}
/////////////////////////////////////////////////////////////////////////
// 建立符号表
//
/**
* 把符号加入符号表。
*/
class Enter extends SemanticAstVisitor{
scope : Scope|null = null; //当前所属的scope
functionSym: FunctionSymbol|null = null;
/**
* 返回最顶级的Scope对象
* @param prog
*/
visitProg(prog:Prog){
let sym = new FunctionSymbol('main', new FunctionType(SysTypes.Integer, []));
prog.sym = sym;
this.functionSym = sym;
return super.visitProg(prog);
}
/**
* 把函数声明加入符号表
* @param functionDecl
*/
visitFunctionDecl(functionDecl: FunctionDecl):any{
let currentScope = this.scope as Scope;
//创建函数的symbol
let paramTypes:Type[] = [];
if (functionDecl.callSignature.paramList != null){
for (let p of functionDecl.callSignature.paramList.params){
paramTypes.push(p.theType);
}
}
let sym = new FunctionSymbol(functionDecl.name, new FunctionType(functionDecl.callSignature.returnType,paramTypes));
sym.decl = functionDecl;
functionDecl.sym = sym;
//把函数加入当前scope
if (currentScope.hasSymbol(functionDecl.name)){
this.addError("Dumplicate symbol: "+ functionDecl.name, functionDecl);
}
else{
currentScope.enter(functionDecl.name, sym);
}
//修改当前的函数符号
let lastFunctionSym = this.functionSym;
this.functionSym = sym;
//创建新的Scope,用来存放参数
let oldScope = currentScope;
this.scope = new Scope(oldScope);
functionDecl.scope = this.scope;
//遍历子节点
super.visitFunctionDecl(functionDecl);
//恢复当前函数
this.functionSym = lastFunctionSym;
//恢复原来的Scope
this.scope = oldScope;
}
/**
* 遇到块的时候,就建立一级新的作用域。
* 支持块作用域
* @param block
*/
visitBlock(block:Block):any{
//创建下一级scope
let oldScope = this.scope;
this.scope = new Scope(this.scope);
block.scope = this.scope;
//调用父类的方法,遍历所有的语句
super.visitBlock(block);
//重新设置当前的Scope
this.scope = oldScope;
}
/**
* 把变量声明加入符号表
* @param variableDecl
*/
visitVariableDecl(variableDecl : VariableDecl):any{
let currentScope = this.scope as Scope;
if (currentScope.hasSymbol(variableDecl.name)){
this.addError("Dumplicate symbol: "+ variableDecl.name, variableDecl);
}
//把变量加入当前的符号表
let sym = new VarSymbol(variableDecl.name, variableDecl.theType);
variableDecl.sym = sym;
currentScope.enter(variableDecl.name, sym);
//把本地变量也加入函数符号中,可用于后面生成代码
this.functionSym?.vars.push(sym);
}
/**
* 对于for循环来说,由于可以在for的init部分声明变量,所以要新建一个Scope。
* @param forStmt
*/
visitForStatement(forStmt:ForStatement):any{
//创建下一级scope
let oldScope = this.scope;
this.scope = new Scope(this.scope);
forStmt.scope = this.scope;
//调用父类的方法,遍历所有的语句
super.visitForStatement(forStmt);
//重新设置当前的Scope
this.scope = oldScope;
}
}
/////////////////////////////////////////////////////////////////////////
// 引用消解
// 1.函数引用消解
// 2.变量应用消解
/**
* 引用消解
* 遍历AST。如果发现函数调用和变量引用,就去找它的定义。
*/
class RefResolver extends SemanticAstVisitor{
scope:Scope|null=null; //当前的Scope
//每个Scope已经声明了的变量的列表
declaredVarsMap:Map<Scope, Map<string,VarSymbol>> = new Map();
visitFunctionDecl(functionDecl:FunctionDecl):any{
//1.修改scope
let oldScope = this.scope;
this.scope = functionDecl.scope as Scope;
assert(this.scope != null, "Scope不可为null");
//为已声明的变量设置一个存储区域
this.declaredVarsMap.set(this.scope, new Map());
//2.遍历下级节点
super.visitFunctionDecl(functionDecl);
//3.重新设置scope
this.scope = oldScope;
}
/**
* 修改当前的Scope
* @param block
*/
visitBlock(block:Block):any{
//1.修改scope
let oldScope = this.scope;
this.scope = block.scope as Scope;
assert(this.scope != null, "Scope不可为null");
//为已声明的变量设置一个存储区域
this.declaredVarsMap.set(this.scope, new Map());
//2.遍历下级节点
super.visitBlock(block);
//3.重新设置scope
this.scope = oldScope;
}
visitForStatement(forStmt:ForStatement):any{
//1.修改scope
let oldScope = this.scope;
this.scope = forStmt.scope as Scope;
assert(this.scope != null, "Scope不可为null");
//为已声明的变量设置一个存储区域
this.declaredVarsMap.set(this.scope, new Map());
//2.遍历下级节点
super.visitForStatement(forStmt);
//3.重新设置scope
this.scope = oldScope;
}
/**
* 做函数的消解。
* 函数不需要声明在前,使用在后。
* @param functionCall
*/
visitFunctionCall(functionCall:FunctionCall):any{
let currentScope = this.scope as Scope;
// console.log("in semantic.visitFunctionCall: " + functionCall.name);
if (built_ins.has(functionCall.name)){ //系统内置函数
functionCall.sym = built_ins.get(functionCall.name) as FunctionSymbol;
}
else{
functionCall.sym = currentScope.getSymbolCascade(functionCall.name) as FunctionSymbol|null;
}
// console.log(functionCall.sym);
//调用下级,主要是参数。
super.visitFunctionCall(functionCall);
}
/**
* 标记变量是否已被声明
* @param variableDecl
*/
visitVariableDecl(variableDecl : VariableDecl):any{
let currentScope = this.scope as Scope;
let declaredSyms = this.declaredVarsMap.get(currentScope) as Map<string, VarSymbol>;
let sym = currentScope.getSymbol(variableDecl.name);
if (sym != null){ //TODO 需要检查sym是否是变量
declaredSyms.set(variableDecl.name, sym as VarSymbol);
}
//处理初始化的部分
super.visitVariableDecl(variableDecl);
}
/**
* 变量引用消解
* 变量必须声明在前,使用在后。
* @param variable
*/
visitVariable(variable: Variable):any{
let currentScope = this.scope as Scope;
variable.sym = this.findVariableCascade(currentScope, variable);
}
/**
* 逐级查找某个符号是不是在声明前就使用了。
* @param scope
* @param name
* @param kind
*/
private findVariableCascade(scope:Scope, variable:Variable):VarSymbol|null{
let declaredSyms = this.declaredVarsMap.get(scope) as Map<string,VarSymbol>;
let symInScope = scope.getSymbol(variable.name);
if (symInScope != null){
if (declaredSyms.has(variable.name)){
return declaredSyms.get(variable.name) as VarSymbol; //找到了,成功返回。
}
else{
if (symInScope.kind == SymKind.Variable){
this.addError("Variable: '" + variable.name + "' is used before declaration.", variable);
}
else{
this.addError("We expect a variable of name: '" + variable.name + "', but find a " + SymKind[symInScope.kind] + ".", variable);
}
}
}
else{
if (scope.enclosingScope != null){
return this.findVariableCascade(scope.enclosingScope, variable);
}
else{
this.addError("Cannot find a variable of name: '" + variable.name +"'", variable);
}
}
return null;
}
}
/////////////////////////////////////////////////////////////////////////
// 属性分析
// 1.类型计算和检查
//
class LeftValueAttributor extends SemanticAstVisitor{
parentOperator: Op|null = null;
/**
* 检查赋值符号和.符号左边是否是左值
* @param binary
*/
visitBinary(binary:Binary):any{
if (Operators.isAssignOp(binary.op) || binary.op == Op.Dot){
let lastParentOperator = this.parentOperator;
this.parentOperator = binary.op;
//检查左子节点
this.visit(binary.exp1);
if (!binary.exp1.isLeftValue){
this.addError("Left child of operator "+ Op[binary.op] + " need a left value",binary.exp1);
}
//恢复原来的状态信息
this.parentOperator = lastParentOperator;
//继续遍历右子节点
this.visit(binary.exp2);
}
else{
super.visitBinary(binary);
}
}
visitUnary(u:Unary):any{
//要求必须是个左值
if (u.op == Op.Inc || u.op == Op.Dec){
let lastParentOperator = this.parentOperator;
this.parentOperator = u.op;
this.visit(u.exp);
if(!u.exp.isLeftValue){
this.addError("Unary operator " + Op[u.op] + "can only be applied to a left value" ,u);
}
//恢复原来的状态信息
this.parentOperator = lastParentOperator;
}
else{
super.visitUnary(u);
}
}
/**
* 变量都可以作为左值,除非其类型是void
* @param v
*/
visitVariable(v:Variable):any{
if (this.parentOperator != null){
let t = v.theType as Type;
if (!t.hasVoid()){
v.isLeftValue = true;
}
}
}
/**
* 但函数调用是在.符号左边,并且返回值不为void的时候,可以作为左值
* @param functionCall
*/
visitFunctionCall(functionCall:FunctionCall):any{
if (this.parentOperator == Op.Dot){
let functionType = functionCall.theType as FunctionType;
if (!functionType.returnType.hasVoid()){
functionCall.isLeftValue = true;
}
}
}
}
/**
* 类型检查
*/
class TypeChecker extends SemanticAstVisitor{
visitVariableDecl(variableDecl:VariableDecl):any{
super.visitVariableDecl(variableDecl);
if (variableDecl.init != null){
let t1 = variableDecl.theType as Type;
let t2 = variableDecl.init.theType as Type;
if (!Type.LE(t2,t1)){
this.addError("Operator '=' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,variableDecl);
}
//类型推断:对于any类型,变成=号右边的具体类型
if (t1===SysTypes.Any){
variableDecl.theType = t2; //TODO:此处要调整
// variableDecl.inferredType = t2;
//重点是把类型记入符号中,这样相应的变量声明就会获得准确的类型
//由于肯定是声明在前,使用在后,所以变量引用的类型是准确的。
(variableDecl.sym as VarSymbol).theType = t2;
}
}
}
visitBinary(bi:Binary):any{
super.visitBinary(bi);
let t1 = bi.exp1.theType as Type;
let t2 = bi.exp2.theType as Type;
if (Operators.isAssignOp(bi.op)){
bi.theType = t1;
if(!Type.LE(t2,t1)){ //检查类型匹配
this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
}
}
else if (bi.op == Op.Plus){ //有一边是string,或者两边都是number才行。
if (t1 == SysTypes.String || t2 == SysTypes.String){
bi.theType = SysTypes.String;
}
else if (Type.LE(t1,SysTypes.Number) && Type.LE(t2,SysTypes.Number)){
bi.theType = Type.getUpperBound(t1, t2);
}
else if (t1 == SysTypes.Any || t2 == SysTypes.Any){
bi.theType = SysTypes.Any;
}
else{
this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
}
}
else if (Operators.isArithmeticOp(bi.op)){
if (Type.LE(t1,SysTypes.Number) && Type.LE(t2,SysTypes.Number)){
bi.theType = Type.getUpperBound(t1, t2);
}
else{
this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
}
}
else if (Operators.isRelationOp(bi.op)){
if (Type.LE(t1, SysTypes.Number) && Type.LE(t2, SysTypes.Number)){
bi.theType = SysTypes.Boolean;
}
else{
this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
}
}
else if (Operators.isLogicalOp(bi.op)){
if (Type.LE(t1,SysTypes.Boolean) && Type.LE(t2,SysTypes.Boolean)){
bi.theType = SysTypes.Boolean;
}
else{
this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
}
}
else{
this.addError("Unsupported binary operator: " + Op[bi.op],bi);
}
}
visitUnary(u:Unary):any{
super.visitUnary(u);
let t = u.exp.theType as Type;
//要求必须是个左值
if (u.op == Op.Inc || u.op == Op.Dec){
if (Type.LE(t,SysTypes.Number)){
u.theType = t;
}
else{
this.addError("Unary operator " + Op[u.op] + "can not be applied to '"+t.toString()+"'." ,u);
}
}
else if (u.op == Op.Minus || u.op == Op.Plus){
if (Type.LE(t,SysTypes.Number)){
u.theType = t;
}
else{
this.addError("Unary operator " + Op[u.op] + "can not be applied to '"+t.toString()+"'." ,u);
}
}
else if (u.op == Op.Not){
if (Type.LE(t,SysTypes.Boolean)){
u.theType = t;
}
else{
this.addError("Unary operator " + Op[u.op] + "can not be applied to '"+t.toString()+"'." ,u);
}
}
else{
this.addError("Unsupported unary operator: " + Op[u.op] + " applied to '"+t.toString()+"'." ,u);
}
}
/**
* 用符号的类型(也就是变量声明的类型),来标注本节点
* @param v
*/
visitVariable(v:Variable):any{
if (v.sym != null){
v.theType = v.sym.theType;
}
}
visitFunctionCall(functionCall:FunctionCall):any{
if (functionCall.sym != null){
let functionType = functionCall.sym.theType as FunctionType;
//注意:不使用函数类型,而是使用返回值的类型
functionCall.theType = functionType.returnType;
//检查参数数量
if(functionCall.arguments.length != functionType.paramTypes.length){
this.addError("FunctionCall of " + functionCall.name +" has " + functionCall.arguments.length + " arguments, while expecting " + functionType.paramTypes.length +".",functionCall);
}
//检查注意检查参数的类型
for (let i = 0; i< functionCall.arguments.length; i++){
this.visit(functionCall.arguments[i]);
if (i < functionType.paramTypes.length){
let t1 = functionCall.arguments[i].theType as Type;
let t2 = functionType.paramTypes[i] as Type;
if (!Type.LE(t1,t2) && t2 !== SysTypes.String){
this.addError("Argument " + i + " of FunctionCall " + functionCall.name + "is of Type " + t1.toString() + ", while expecting "+t2.toString(), functionCall);
}
}
}
}
}
}
/**
* 类型转换
* 添加必要的AST节点,来完成转换
* 目前特性:其他类型转换成字符串
*/
class TypeConverter extends SemanticAstVisitor{
visitBinary(bi:Binary):any{
super.visitBinary(bi);
let t1 = bi.exp1.theType as Type;
let t2 = bi.exp2.theType as Type;
if (Operators.isAssignOp(bi.op)){
if (t1 === SysTypes.String && t2 !== SysTypes.String){
if (t2 === SysTypes.Integer){
let exp = new FunctionCall(bi.exp2.beginPos, bi.exp2.endPos,"integer_to_string",[bi.exp2]);
exp.sym = built_ins.get("integer_to_string") as FunctionSymbol;
bi.exp2 = exp;
}
}
}
else if (bi.op == Op.Plus){ //有一边是string,或者两边都是number才行。
if (t1 === SysTypes.String || t2 === SysTypes.String){
if (t1 === SysTypes.Integer || t1 === SysTypes.Number){
let exp = new FunctionCall(bi.exp1.beginPos, bi.exp1.endPos,"integer_to_string",[bi.exp1]);
exp.sym = built_ins.get("integer_to_string") as FunctionSymbol;
bi.exp1 = exp;
}
if (t2 === SysTypes.Integer || t2 === SysTypes.Number){
let exp = new FunctionCall(bi.exp2.beginPos, bi.exp2.endPos,"integer_to_string",[bi.exp2]);
exp.sym = built_ins.get("integer_to_string") as FunctionSymbol;
bi.exp2 = exp;
}
}
}
}
visitFunctionCall(functionCall:FunctionCall):any{
if (functionCall.sym != null){
let functionType = functionCall.sym.theType as FunctionType;
//看看参数有没有可以转换的。
for (let i = 0; i< functionCall.arguments.length; i++){
this.visit(functionCall.arguments[i]);
if (i < functionType.paramTypes.length){
let t1 = functionCall.arguments[i].theType as Type;
let t2 = functionType.paramTypes[i] as Type;
if ((t1 === SysTypes.Integer || t1 === SysTypes.Number) && t2 === SysTypes.String){
let exp = new FunctionCall(functionCall.arguments[i].beginPos, functionCall.arguments[i].endPos,"integer_to_string",[functionCall.arguments[i]]);
exp.sym = built_ins.get("integer_to_string") as FunctionSymbol;
functionCall.arguments[i] = exp;
}
}
}
}
}
}
/**
* 常量折叠
*/
class ConstFolder extends SemanticAstVisitor{
visitBinary(bi:Binary):any{
let v1 = bi.exp1.constValue;
let v2 = bi.exp2.constValue;
if (Operators.isAssignOp(bi.op)){
if (typeof v2 != 'undefined'){
if (bi.op == Op.Assign){ //暂时只支持=号
bi.exp1.constValue = v1;
bi.constValue = v1;
}
else{
this.addError("Unsupported operator: " + Op[bi.op] +"in ConstFolder",bi);
}
}
}
else if(typeof v1 != 'undefined' && typeof v2 != 'undefined'){
let v:any;
switch(bi.op){
case Op.Plus: //'+'
v = v1 + v2;
break;
case Op.Minus: //'-'
v = v1 - v2;
break;
case Op.Multiply: //'*'
v = v1 * v2;
break;
case Op.Divide: //'/'
v = v1 / v2;
break;
case Op.Modulus: //'%'
v = v1 % v2;
break;
case Op.G: //'>'
v = v1 > v2;
break;
case Op.GE: //'>='
v = v1 >= v2;
break;
case Op.L: //'<'
v = v1 < v2;
break;
case Op.LE: //'<='
v = v1 <= v2;
break;
case Op.EQ: //'=='
v = v1 == v2;
break;
case Op.NE: //'!='
v = v1 != v2;
break;
case Op.And: //'&&'
v = v1 && v2;
break;
case Op.Or: //'||'
v = v1 || v2;
break;
default:
this.addError("Unsupported binary operator: " + Op[bi.op] +"in ConstFolder",bi);
}
bi.op = v;
}
}
visitUnary(u:Unary):any{
let v1 = u.exp.constValue;
if (typeof v1 != 'undefined'){
if (u.op == Op.Inc){
if (u.isPrefix){
u.exp.constValue += 1;
u.constValue = u.exp.constValue;
}
else{
u.constValue = v1;
u.exp.constValue += 1;
}
}
else if (u.op == Op.Dec){
if (u.isPrefix){
u.exp.constValue -= 1;
u.constValue = u.exp.constValue;
}
else{
u.constValue = v1;
u.exp.constValue -= 1;
}
}
else if (u.op == Op.Plus){
u.constValue = v1;
}
else if (u.op == Op.Minus){
u.constValue = -v1;
}
else if (u.op == Op.Not){
u.constValue = !v1;
}
else{
this.addError("Unsupported unary operator: " + Op[u.op] +"in ConstFolder",u);
}
}
}
}
/**
* 检查每个变量是否都被赋值了。
*/
class AssignAnalyzer extends SemanticAstVisitor{
//每个变量的赋值情况
assignMode:Map<VarSymbol, boolean> = new Map();
private cloneMap(map1:Map<VarSymbol, boolean>):Map<VarSymbol, boolean>{
let map2:Map<VarSymbol, boolean> = new Map();
for (let sym of map1.keys()){
let value = map1.get(sym) as boolean;
map2.set(sym,value);
}
return map2;
}
private merge(map1:Map<VarSymbol, boolean>, map2:Map<VarSymbol, boolean>):Map<VarSymbol, boolean>{
let map:Map<VarSymbol, boolean> = new Map();
for (let sym of map1.keys()){
let value1 = map1.get(sym) as boolean;
let value2 = map2.get(sym) as boolean;
map.set(sym, value1 && value2);
}
return map;
}
visitProg(prog:Prog):any{
this.assignMode = new Map();
super.visitProg(prog);
return this.assignMode;
}
//参数都是被赋值过的。
visitParameterList(paramList:ParameterList):any{
for (let varDecl of paramList.params){
this.assignMode.set(varDecl.sym as VarSymbol, true);
}
}
//略过死代码
visitBlock(block:Block):any{
for (let stmt of block.stmts){
let alive = this.visit(stmt) as boolean;
if(typeof alive == 'boolean'){
//如果遇到return语句,后面的就是死代码了,必须忽略掉。
return;
}
}
}
//检测return语句
visitReturnStatement(rtnStmt: ReturnStatement):any{
if(rtnStmt.exp != null) this.visit(rtnStmt.exp);
return false; //表示代码活跃性为false
}
//变量声明中可能会初始化变量
visitVariableDecl(variableDecl: VariableDecl):any{
if (variableDecl.init != null) this.visit(variableDecl.init);
//如果有初始化部分,那么assigned就设置为true
this.assignMode.set(variableDecl.sym as VarSymbol, variableDecl.init != null);
}
//检查变量使用前是否被赋值了
visitVariable(variable: Variable):any{
let varSym = variable.sym as VarSymbol;
if (this.assignMode.has(varSym)){
let assigned = this.assignMode.get(varSym) as boolean;
if (!assigned){
this.addError("variable '" + variable.name + "' is used before being assigned.", variable);
}
}
else{
console.log("whoops,不可能到这里@semantic.ts/visitVariable");
}
}
//处理赋值语句
visitBinary(binary:Binary):any{
if (Operators.isAssignOp(binary.op)){
this.visit(binary.exp2); //表达式右侧要照常遍历,但左侧就没有必要了。
if (typeof (binary.exp1 as Variable).sym == 'object'){
let varSym = (binary.exp1 as Variable).sym as VarSymbol;
this.assignMode.set(varSym, true);
}
}
else{
super.visitBinary(binary);
}
}
visitIfStatement(ifStmt:IfStatement):any{
//if条件有没有常量的值,是否为常真或常假
if (typeof ifStmt.condition.constValue != 'undefined'){
if (ifStmt.condition.constValue){
}
else{
if (ifStmt.elseStmt == null){
}
else{
}
}
}
else{
//算法:把assignMode克隆两份,分别代表遍历左支和右支的结果,然后做交汇运算
let oldMode = this.cloneMap(this.assignMode);
//遍历if块
this.visit(ifStmt.stmt);
let mode1 = this.assignMode;
//遍历else块
this.assignMode = this.cloneMap(oldMode);
if (ifStmt.elseStmt != null) this.visit(ifStmt.elseStmt);
let mode2 = this.assignMode;
//交汇运算
this.assignMode = this.merge(mode1, mode2);
}
}
/**
* 因为我们现在不支持break,所以检查起来比较简单。
* @param forStmt
*/
visitForStatement(forStmt:ForStatement):any{
//for循环语句的初始化部分也可能有
if (forStmt.init != null)
super.visit(forStmt.init);
//查看是否满足进入条件
let skipLoop = forStmt.condition != null && typeof forStmt.condition.constValue != 'undefined' && forStmt.condition.constValue;
if (!skipLoop){
this.visit(forStmt.stmt);
if (forStmt.increment!=null)
this.visit(forStmt.increment);
}
}
}
/**
* 检查函数的所有分枝是否都正确的返回。
*/
class LiveAnalyzer extends SemanticAstVisitor{
/**
* 分析主程序是否正确的renturn了。如果没有,那么自动添加return语句。
* @param prog
*/
visitProg(prog:Prog):any{
let alive = super.visitBlock(prog);
//如果主程序没有return语句,那么在最后面加一下。
if (alive){
prog.stmts.push(new ReturnStatement(prog.endPos, prog.endPos, null));
}
}
/**
* 检查每个函数是否都正确的return了。也就是alive是false。
* @param functionDecl
*/
visitFunctionDecl(functionDecl:FunctionDecl):any{
let alive = true;
let sym = functionDecl.sym as FunctionSymbol;
let functionType = sym.theType as FunctionType;
if (functionType.returnType != SysTypes.Any && functionType.returnType != SysTypes.Void && functionType.returnType != SysTypes.Undefined){
alive = super.visitBlock(functionDecl.body);
}
else{
alive = false;
}
if (alive){
this.addError("Function lacks ending return statement and return type does not include 'undefined'.", functionDecl);
}
return alive;
}
visitBlock(block:Block):any{
let alive:boolean = true;
let deadCodes:Statement[] = []; //死代码
for (let stmt of block.stmts){
if (alive){
alive = this.visit(stmt) as boolean;
}
//return语句之后的语句,都是死代码。
else{
//作为Warning,而不是错误。
this.addWarning("Unreachable code detected.",stmt);
deadCodes.push(stmt);
}
}
//去除死代码
for (let stmt of deadCodes){
let index = block.stmts.indexOf(stmt);
block.stmts.splice(index,1);
}
return alive;
}
visitReturnStatement(stmt:ReturnStatement):any{
return false;
}
visitVariableStatement(stmt:VariableStatement):any{
return true;
}
visitExpressionStatement(stmt:ExpressionStatement):any{
return true;
}
/**
*
* @param ifStmt
*/
visitIfStatement(ifStmt:IfStatement):any{
let alive:boolean;
//if条件有没有常量的值,是否为常真或长假
if (typeof ifStmt.condition.constValue != 'undefined'){
if (ifStmt.condition.constValue){
alive = this.visit(ifStmt.stmt) as boolean;
}
else{
if (ifStmt.elseStmt == null){
alive = true;
}
else{
alive = this.visit(ifStmt.stmt) as boolean;
}
}
}
else{
let alive1 = this.visit(ifStmt.stmt) as boolean;
let alive2 = ifStmt.elseStmt == null ? true : (this.visit(ifStmt.elseStmt) as boolean);
alive = alive1 || alive2; //只有两个分支都是false,才返回false;
}
return alive;
}
/**
* 因为我们现在不支持break,所以检查起来比较简单。只要有return语句,我们就认为alive=false;
* @param forStmt
*/
visitForStatement(forStmt:ForStatement):any{
//查看是否满足进入条件
if (forStmt.condition != null && typeof forStmt.condition.constValue != 'undefined'){
if (forStmt.condition.constValue){
return this.visit(forStmt.stmt);
}
else{ //如果不可能进入循环体,那么就不用继续遍历了
return true;
}
}
else{
return this.visit(forStmt.stmt);
}
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。