所谓的状态机实质其实很很简单,其存在的目的也是把大量复杂的处理分散,使处理变得简单化一些。状态机只有一个当前状态,并且在当前状态下根据输入进行处理,然后再决定是否改变当前状态,然后再处理下一个输入,如此往复直到所有输入结束。
  所以,相同的输入在不同的当前状态下的处理是不一样的,以字符串的处理为例,我们来看看怎么处理下面这条语句:

str="123\"abc";

  我们需要得到的结果序列应该是:
    标识符str,标点符号=,字面量"123\"abc",标点符号;

  首先我们会建立起几种处理的状态(这里只是针对这个列子,实际开发的状态比这多得多T_T):
    a.一般状态处理;
    b.标识符状态处理;
    c.标点符号状态处理;
    d.双引号字符串字面量状态处理;
    e.双引号字符串字面量遇到\符号时的状态处理;

  建立完成状态处理方法后,我们将语句作为字符串输入流,一个个字符地进行输入处理:
    1)输入s,首先进入状态a进行一般处理,判断出该字符符合js标识符规则,记录当前字符,将当前状态转换为状态b;
    2)继续输入下一个字符t,进入状态b进行字符处理,字符t符合js标识符规则,记录当前字符,并且当前状态还是状态b,不发生改变;
    3)继续输入下一个字符r,进入状态b进行字符处理,字符r符合js标识符规则,记录当前字符,并且当前状态还是状态b,不发生改变;
    4)继续输入下一个字符=,进入状态b进行字符处理,字符=不符合当前状态需要的js标识符规则,于是保存之前记录的字符集,并标记为id类型,即["id","str"]。再将当前状态转换为状态a;
    5)在当前状态a下继续输入刚才未处理的字符=,判断出其符合js标点符号规则,记录当前字符,并将当前状态转换为状态c;
    6)继续输入下一个字符",进入状态c进行标点符号处理,判读出字符"并不符合标点符号规则,于是保存记录的字符集,并标记为标点符号类型["pun","="]。再将当前状态转换为状态a;
    7)在当前状态a下继续输入刚才未处理的字符",判断出其符合js字符串字面量规则,记录当前字符,并将当前状态转换为状态d;
    8)继续输入下一个字符,在状态d下处理,符合js字符串字面量规则,记录当前字符;
    9)继续输入下一个字符,在状态d下处理,符合js字符串字面量规则,记录当前字符;
    10)继续输入下一个字符,在状态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));

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

状态机——Javascript词法扫描示例的更多相关文章

  1. JavaScript 词法 All In One

    JavaScript 词法 All In One JavaScript 词法 这部分描述了JavaScript 的词法(lexical grammar). ECMAScript 源码文本会被从左到右扫 ...

  2. XAMARIN ANDROID 二维码扫描示例

    现在二维码的应用越来越普及,二维码扫描也成为手机应用程序的必备功能了.本文将基于 Xamarin.Android 平台使用 ZXing.Net.Mobile  做一个简单的 Android 条码扫描示 ...

  3. Javascript调用ActiveX示例

      Javascript调用ActiveX示例   写一个ActiveX控件比如叫做MyNameSpace.SecreteInfo,安装在客户机器上,这样可以通过c++获取到机器的几乎任何信息. 在网 ...

  4. 第二章:Javascript词法结构

    编程语言的词法结构是一套基础性的规则,用来描述你如何编写这门语言.作为语法的基础,它规定了变量名是怎么样的,如何写注释,以及语句之间是如何区分的.本节用很短的篇幅来介绍javascript的词法结构. ...

  5. 网易JS面试题与Javascript词法作用域说明

    调用对象位于作用域链的前端,局部变量(在函数内部用var声明的变量).函数参数及Arguments对象都在函数内的作用域中--这意味着它们隐藏了作用域链更上层的任何同名的属性. 2010年9月14日, ...

  6. JavaScript 词法句法

    JavaScript 中的几个重要概念 JavaScript 遵循 ECMA-262 规范,目前其最新版是 ECMAScript 2018,而获得所有主流浏览器完全支持的则是 ECMAScript 5 ...

  7. 【译】Spring 4 自动装配、自动检测、组件扫描示例

    前言 译文链接:http://websystique.com/spring/spring-auto-detection-autowire-component-scanning-example-with ...

  8. 将百度坐标转换的javascript api官方示例改写成传统的回调函数形式

    改写前: 百度地图中坐标转换的JavaScript API示例官方示例如下: var points = [new BMap.Point(116.3786889372559,39.90762965106 ...

  9. javascript 词法结构小结

    作为一名前端程序员,自然学习了一些框架,但是学的越多越发现自己基础的不足,于是想系统的学习一下js基础,然后把它记录下来. 如其他编程语言一样,词法结构是一门语言的基础,它规定了诸如如何给变量起名字. ...

随机推荐

  1. cocos2d-x基础元素之显示对象

    bool HelloWorld::init() { if ( !Layer::init() ) { return false; } Size visibleSize = Director::getIn ...

  2. Android开发学习总结(一)——搭建最新版本的Android开发环境

    Android开发学习总结(一)——搭建最新版本的Android开发环境(转) 最近由于工作中要负责开发一款Android的App,之前都是做JavaWeb的开发,Android开发虽然有所了解,但是 ...

  3. kvm解决1000M网卡问题

    1.当我们安装完虚拟机, 发现虚拟机竟然是 100M 网络, 传输速率很低, 那是怎么导致的呢,如何来解决呢? 需要我们修改 vm01.xml 配置文件网卡段,添加如下红色标记行,改 为 e1000, ...

  4. CS193P学习笔记(一)

    1>iOS系统分层   1.Core OS 核心操作系统层,很接近硬件的一层: 本质是一个Unix内核,使用基于BSD的Unix版本,拥有文件系统.套接字.权限等一系列Unix所具有的特性,并且 ...

  5. [转][ASP.NET MVC 小牛之路]12 - Section、Partial View 和 Child Action

    本文转自:http://www.cnblogs.com/willick/p/3410855.html 概括的讲,View中的内容可以分为静态和动态两部分.静态内容一般是html元素,而动态内容指的是在 ...

  6. 关于extern和static关键字引出的一些关于作用域和链接属性和存储类型的问题

    在进入正题前我们必须了解一些概念: 标识符:标识符不仅仅代表着变量的名字,main()函数的main也是一个标识符,这点很重要. 存储类型:即变量的存储位置及其生存周期:静态区:分为两块 .date ...

  7. Solr字段配置错误

    在站内搜索Solr Schema设计时,有个FTS_URL字段(之前设计url也会参与检索和打分),因此其配置信息如下: <field name="FTS_URL" type ...

  8. python中property干什么用的?

    先来段官方文档压压惊.. property(fget=None, fset=None, fdel=None, doc=None) Return a property attribute. fget i ...

  9. Mango DS Training #48 ---线段树2 解题手记

    Training address: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=38966#overview A.Count Color ...

  10. Android 可拖拽的GridView效果实现, 长按可拖拽和item实时交换

    转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17718579),请尊重他人的辛勤劳动成果,谢谢! 在And ...