博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
状态机——Javascript词法扫描示例
阅读量:4708 次
发布时间:2019-06-10

本文共 5116 字,大约阅读时间需要 17 分钟。

  所谓的状态机实质其实很很简单,其存在的目的也是把大量复杂的处理分散,使处理变得简单化一些。状态机只有一个当前状态,并且在当前状态下根据输入进行处理,然后再决定是否改变当前状态,然后再处理下一个输入,如此往复直到所有输入结束。

  所以,相同的输入在不同的当前状态下的处理是不一样的,以字符串的处理为例,我们来看看怎么处理下面这条语句:

str="123\"abc";

  我们需要得到的结果序列应该是:

    标识符str,标点符号=,字面量"123\"abc",标点符号;

  首先我们会建立起几种处理的状态(这里只是针对这个列子,实际开发的状态比这多得多T_T):

    a.一般状态处理;
    b.标识符状态处理;
    c.标点符号状态处理;
    d.双引号字符串字面量状态处理;
    e.双引号字符串字面量遇到\符号时的状态处理;

  建立完成状态处理方法后,我们将语句作为字符串输入流,一个个字符地进行输入处理:

    1)输入s,首先进入状态a进行一般处理,判断出该字符符合,记录当前字符,将当前状态转换为状态b;
    2)继续输入下一个字符t,进入状态b进行字符处理,字符t符合js标识符规则,记录当前字符,并且当前状态还是状态b,不发生改变;
    3)继续输入下一个字符r,进入状态b进行字符处理,字符r符合js标识符规则,记录当前字符,并且当前状态还是状态b,不发生改变;
    4)继续输入下一个字符=,进入状态b进行字符处理,字符=不符合当前状态需要的js标识符规则,于是保存之前记录的字符集,并标记为id类型,即["id","str"]。再将当前状态转换为状态a;
    5)在当前状态a下继续输入刚才未处理的字符=,判断出其符合,记录当前字符,并将当前状态转换为状态c;
    6)继续输入下一个字符",进入状态c进行标点符号处理,判读出字符"并不符合标点符号规则,于是保存记录的字符集,并标记为标点符号类型["pun","="]。再将当前状态转换为状态a;
    7)在当前状态a下继续输入刚才未处理的字符",判断出其符合,记录当前字符,并将当前状态转换为状态d;
    8)继续输入下一个字符1,在状态d下处理,符合js字符串字面量规则,记录当前字符;
    9)继续输入下一个字符2,在状态d下处理,符合js字符串字面量规则,记录当前字符;
    10)继续输入下一个字符3,在状态d下处理,符合js字符串字面量规则,记录当前字符;
    11)继续输入下一个字符\,在状态d下处理,\字符在状态d里会触发状态转换,记录当前字符,将当前状态转换为状态e;
    12)继续输入下一个字符",在状态e下处理,判断符合当前的处理规则,记录当前字符",将状态转换为状态d;
    13)继续输入下一个字符a,在状态d下处理,符合js字符串字面量规则,记录当前字符;
    14)继续输入下一个字符b,在状态d下处理,符合js字符串字面量规则,记录当前字符;
    15)继续输入下一个字符c,在状态d下处理,符合js字符串字面量规则,记录当前字符;
    16) 继续输入下一个字符",在状态d下处理,状态d接收到"时就可以判断出当前状态结束了,于是保存当前的记录的字符集,并标记为字符串字面量类型["str","\"123\\\"abc\""],再将当前状态转换为状态a;
    17)继续输入下一个字符;,在状态a下处理,判断出其符合js标点符号规则,记录当前字符,将状态转换为状态c;
    18)现在所有字符都扫描完了,我们可以人为加一个终止符,当再读到最后的终止符时,判断出不符合标点符号规则,保存字符集,标记为标点符号类型["pun",";"];
    19)处理结束。

  于是我们就得到了我们需要的词法序列:

    [["id","str"], ["pun","="], ["str","\"123\\\"abc\""], ["pun",";""]]

  简化版的代码看起来大概就是这个样子:  

var Reader= function(str){        var index=0;        var stream=str;                    stream +=" ";                var me={            get char(){                return stream[index];            },                        get length(){                return stream.length;            },                        get stream(){                return stream;            },                        get pchar(){                return stream[index-1];            },                        get nchar(){                return stream[index+1];            },                        get eof(){                return index === stream.length;            },                        next : function(){                index++;            },                        prev : function(){                index--;            }                    };                return me;    };        var statement="str=\"123\\\"abc\";";    var reader=Reader(statement);    var l=reader.length;    var i;    var newState;    var state;    var tokenList=[];    var word="";        var punctuatorList=["{", "}", "(", ")", "[", "]", ".", ";", ",", "<", ">", "<=",                    ">=", "==", "!=", "===", "!==", "+", "-", "*", "%", "++", "--",                    "<<", ">>", ">>>", "&", "|", "^", "!", "~", "&&", "||", "?", ":",                    "=", "+=", "-=", "*=", "%=", "<<=", ">>=", ">>>=", "&=", "|=", "^="];                        function checkUnicodeLetter(c){        return c.match(/[a-z]/i); //囧oz    }        function checkUnicodeNumber(c){        return (c.charCodeAt() >= "\u0030".charCodeAt() && c.charCodeAt() <= "\u0039".charCodeAt())            || (c.charCodeAt() >= "\u1D7CE".charCodeAt() && c.charCodeAt() <= "\u1D7FF".charCodeAt());                }        function emitToken(type){        tokenList.push([type, word]);           word="";    }                function dataState(c){        if(punctuatorList.indexOf(c) > -1){            word=c;            return punctuatorState;                    }else if(checkUnicodeLetter(c) || c==="_" || c==="$" || c==="\\"){            word=c;            return identifierState;                    }else if(c==="\""){            word=c;            return doubleStringLiteralState;        }    }        function punctuatorState(c){        if(punctuatorList.indexOf(word+c) === -1){            emitToken("pun");            reader.prev();            return dataState;        }else{            word += c;        }    }        function identifierState(c){        if(checkUnicodeLetter(c) || checkUnicodeNumber(c)){            word += c;                    }else{                        emitToken("id");            reader.prev();            return dataState;        }    }        function doubleStringLiteralState(c){        if(c==="\\"){            word += c;            return doubleStringLiteralEscapeSequenceState;                    }else if(c==="\""){            word += c;            emitToken("str");            return dataState;        }else{            word += c;        }    }    function doubleStringLiteralEscapeSequenceState(c){        word+=c;        return doubleStringLiteralState;    }            state=dataState;    while(!reader.eof){        newState=state(reader.char);        newState && (state=newState);        reader.next();    }        alert(JSON.stringify(tokenList));
View Code

  这就是状态机的运作方式,不过要写全各种状态这种事真特么不是人干的~~

转载于:https://www.cnblogs.com/Random/p/3343074.html

你可能感兴趣的文章
jdk环境变量配置
查看>>
Oracle的自增长主键
查看>>
素数-牛客网[求大数内所有素数]
查看>>
bower 安装后 jade 引用404问题
查看>>
sencha touch 模仿tabpanel导航栏TabBar的实现代码
查看>>
spring-AOP
查看>>
点分治学习笔记
查看>>
MQTT开源代理Mosquitto源码分析(访问控制篇)
查看>>
ubuntu 14.04/15.10 安装基于eclipse的android app开发环境
查看>>
<转>创建支持eclipse的多模块maven项目
查看>>
Interface + Abstract + Implements
查看>>
采用一维数组输出等腰三角形的杨辉三角
查看>>
Linux 十六进制转换十进制的函数
查看>>
About me
查看>>
numpy array_split()
查看>>
关于JSON的jar
查看>>
u-boot分析——struct gd_t与struct bd_t
查看>>
Android双击返回按钮退出程序
查看>>
Python3 json、pickle序列化与反序列化
查看>>
好久没有写博客了,最近一段时间做一下总结吧!
查看>>