zoukankan      html  css  js  c++  java
  • python等缩进语言的词法分析实现

    python等缩进语言的词法分析实现:

    定义两个虚拟的Token:

    tokens {
        INDENT;
        DEDENT;
    }

    还有一个缩进栈,用于确定是缩进一行,还是回退一行:
    Stack<Integer> _indentStack = new Stack<Integer>();

    在开始做词法分析之前,压入一个默认的Indent,这一步其实没什么必要,只是用来避免写判断栈顶是否为空的冗余判断:
    _indentStack = new Stack<Integer>();
    _indentStack.push(new Integer(0));

    针对每一个新行,首先判断行首是否是空格,如果是空格,则空格计1、Tab键计8个空格,如果仅仅是空行,跳过。如果在碰到行尾之前碰有非空字符,则将空格数与栈顶的空格对比,如果大于,压入当前行的空格数,并生成一个虚拟的Indent Token,如果小于,将所有空格数大于当前行的出栈,并生成一个虚拟的Dedent Token:

    NEWLINE
    @init {
        int spaces = 0;
    }
        :   ((('\u000C')?('\r')? '\n' ) | '\t' | ' ')* (('\u000C')?('\r')? '\n')
            leading_space = (' ' { spaces++; } | '\t' { spaces += 8; spaces -= (spaces \% 8); })*
            {
                if ( !_inATable &&
                     (getCharPositionInLine() == 0 ||
                      implicitLineJoiningLevel > 0) ) {
                    emit(new ClassicToken(NEWLINE, this.getText(), HIDDEN));
                } else {
                    emit(new ClassicToken(NEWLINE, this.getText(), HIDDEN));
                }

                if ( implicitLineJoiningLevel == 0 &&
                     _indentStack.size() > 0) {
                    if (spaces > _indentStack.peek().intValue() ) {
                        _indentStack.push(new Integer(spaces));                   
                        emit(new ClassicToken(INDENT, ">"));
                    }
                    else {
                        while ( spaces < _indentStack.peek().intValue() ) {
                            _indentStack.pop();
                            emit(new ClassicToken(DEDENT, "<"));
                        }
                    }
                }
            }
        | ((('\u000C')?('\r')? '\n' ) | '\t' | ' ')* (('\u000C')?('\r')? '\n')
          (' ' | '\t')* '#' (~'\n')*
            {
                $channel = HIDDEN;
            }
        ;

    当然还要考虑纯注释行,和空格后仅跟有注释的情形。

    这样词法分析过程中,缩进的词法分析过程就完了,在语法分析中,Indent是透明的,例如:

    compound_stmt
        : IF compound_condition (suite)+ elif_clause* else_clause?
        | assignment
        ;

    suite
        : INDENT (compound_stmt)+ (DEDENT | EOF)
        ;

    上面的语法中,INDENT和DEDENT就跟括号的处理没什么区别,只不过DEDENT可选,主要是考虑直接在代码后就EOF的情况。

  • 相关阅读:
    1113.层级 Walker
    118.防止高度塌陷 Walker
    1114.实战移入切换 Walker
    116.清除浮动 Walker
    Vue使用——vue设置浏览器显示图标
    MFC如何高效地绘图(转)
    Ugly Windows HDU2487 ACM算法设计
    CImage类的介绍与使用 【图像打开,另存为,转为灰度图像(利用cimage方法实现)】
    Ogre 3D 配置
    WPF文本框只允许输入数字[转]
  • 原文地址:https://www.cnblogs.com/killmyday/p/2646719.html
Copyright © 2011-2022 走看看