基于Node.JS的SNL词法分析和语法分析

工具

编程语言: Node.JS

工具包: XSLT

SNL程序示例

program p
type t1 = integer;
var integer v1, v2;
procedure
    q(integer i);
var integer a;
begin
    a := i;
    write(a)
end
begin
    read(v1);
    if v1 < 10
        then v1 := v1 + 10
        else v1 := v1 - 10
        fi;
    q(v1)
end.

具体分析流程

1.将源代码读入为字符流

2.通过状态机进行分词,状态转换图如下所示

												识别SNL单词的DFA表示

3.对从状态机中读出来的单词进一步处理,形成token列表,放在数组中,供下一步语法分析使用

示例如下:

{ lex: 'PROGRAM', sem: 'program', row: 1 },
{ lex: 'ID', sem: 'p', row: 1 },
{ lex: 'TYPE', sem: 'type', row: 2 },
{ lex: 'ID', sem: 't1', row: 2 },
{ lex: '=', sem: null, row: 2 },
{ lex: 'INTEGER', sem: 'integer', row: 2 },
{ lex: ';', sem: null, row: 2 },
{ lex: 'VAR', sem: 'var', row: 3 },
{ lex: 'INTEGER', sem: 'integer', row: 3 },
{ lex: 'ID', sem: 'v1', row: 3 },
{ lex: ',', sem: null, row: 3 },
{ lex: 'ID', sem: 'v2', row: 3 },
{ lex: ';', sem: null, row: 3 },
{ lex: 'PROCEDURE', sem: 'procedure', row: 4 },
{ lex: 'ID', sem: 'q', row: 5 },
{ lex: '(', sem: null, row: 5 },
{ lex: 'INTEGER', sem: 'integer', row: 5 },
{ lex: 'ID', sem: 'i', row: 5 },
{ lex: ')', sem: null, row: 5 },
{ lex: ';', sem: null, row: 5 },
{ lex: 'VAR', sem: 'var', row: 6 },
{ lex: 'INTEGER', sem: 'integer', row: 6 },
{ lex: 'ID', sem: 'a', row: 6 },
{ lex: ';', sem: null, row: 6 },
{ lex: 'BEGIN', sem: 'begin', row: 7 },
{ lex: 'ID', sem: 'a', row: 8 },
{ lex: ':=', sem: null, row: 8 },
{ lex: 'ID', sem: 'i', row: 8 },
{ lex: ';', sem: null, row: 8 },
{ lex: 'WRITE', sem: 'write', row: 9 },
{ lex: '(', sem: null, row: 9 },
{ lex: 'ID', sem: 'a', row: 9 },
{ lex: ')', sem: null, row: 9 },
{ lex: 'END', sem: 'end', row: 10 },
{ lex: 'BEGIN', sem: 'begin', row: 11 },
{ lex: 'READ', sem: 'read', row: 12 },
{ lex: '(', sem: null, row: 12 },
{ lex: 'ID', sem: 'v1', row: 12 },
{ lex: ')', sem: null, row: 12 },
{ lex: ';', sem: null, row: 12 },
{ lex: 'IF', sem: 'if', row: 13 },
{ lex: 'ID', sem: 'v1', row: 13 },
{ lex: '<', sem: null, row: 13 },
{ lex: 'INTC', sem: '10', row: 13 },
{ lex: 'THEN', sem: 'then', row: 14 },
{ lex: 'ID', sem: 'v1', row: 14 },
{ lex: ':=', sem: null, row: 14 },
{ lex: 'ID', sem: 'v1', row: 14 },
{ lex: '+', sem: null, row: 14 },
{ lex: 'INTC', sem: '10', row: 14 },
{ lex: 'ELSE', sem: 'else', row: 15 },
{ lex: 'ID', sem: 'v1', row: 15 },
{ lex: ':=', sem: null, row: 15 },
{ lex: 'ID', sem: 'v1', row: 15 },
{ lex: '-', sem: null, row: 15 },
{ lex: 'INTC', sem: '10', row: 15 },
{ lex: 'FI', sem: 'fi', row: 16 },
{ lex: ';', sem: null, row: 16 },
{ lex: 'ID', sem: 'q', row: 17 },
{ lex: '(', sem: null, row: 17 },
{ lex: 'ID', sem: 'v1', row: 17 },
{ lex: ')', sem: null, row: 17 },
{ lex: 'END', sem: 'end', row: 18 } ]

4.进行语法分析,采用的方法为LL(1)分析法

5.录入原始形式的生成式,存放在对象(哈希表)中,如下所示:

  Program: 'ProgramHead DeclarePart ProgramBody',
        ProgramHead: 'PROGRAM ProgramName',
        ProgramName: 'ID',

        DeclarePart: 'TypeDecpart VarDecpart ProcDecpart',

        TypeDecpart: 'ε | TypeDec',
        TypeDec: 'TYPE TypeDecList',
        TypeDecList: 'TypeId = TypeDef ; TypeDecMore',
        TypeDecMore: 'ε | TypeDecList',
        TypeId: 'ID',

        TypeDef: 'BaseType | StructureType | ID',
        BaseType: 'INTEGER | CHAR',
        StructureType: 'ArrayType | RecType',
        ArrayType: 'ARRAY [ Low .. Top ] OF BaseType',
        Low: 'INTC',
        Top: 'INTC',
        RecType: 'RECORD FieldDecList END',
        FieldDecList: 'BaseType IdList ; FieldDecMore | ArrayType IdList ; FieldDecMore',
        FieldDecMore: 'ε | FieldDecList',
        IdList: 'ID IdMore',
        IdMore: 'ε | , IdList',

        VarDecpart: 'ε | VarDec',
        VarDec: 'VAR VarDecList',
        VarDecList: 'TypeDef VarIdList ; VarDecMore',
        VarDecMore: 'ε | VarDecList',
        VarIdList: 'ID VarIdMore',
        VarIdMore: 'ε | , VarIdList',

        ProcDecpart: 'ε | ProcDec',
        ProcDec: 'PROCEDURE ProcName ( ParamList ) ; ProcDecPart ProcBody ProcDecMore',
        ProcDecMore: 'ε | ProcDec',
        ProcName: 'ID',

        ParamList: 'ε | ParamDecList',
        ParamDecList: 'Param ParamMore',
        ParamMore: 'ε | ; ParamDecList',
        Param: 'TypeDef FormList | VAR TypeDef FormList',
        FormList: 'ID FidMore',

        FidMore: 'ε | , FormList',

        ProcDecPart: 'DeclarePart',

        ProcBody: 'ProgramBody',

        ProgramBody: 'BEGIN StmList END',

        StmList: 'Stm StmMore',
        StmMore: 'ε | ; StmList',

        Stm: 'ConditionalStm | LoopStm | InputStm | OutputStm | ReturnStm | ID AssCall',

        AssCall: 'AssignmentRest | CallStmRest',

        AssignmentRest: 'VariMore := Exp',

        ConditionalStm: 'IF RelExp THEN StmList ELSE StmList FI',

        LoopStm: 'WHILE RelExp DO StmList ENDWH',

        InputStm: 'READ ( Invar ) ',

        Invar: 'ID',

        OutputStm: 'WRITE ( Exp ) ',

        ReturnStm: 'RETURN',

        CallStmRest: '( ActParamList )',

        ActParamList: 'ε | Exp ActParamMore',

        ActParamMore: 'ε | ,ActParamList',

        RelExp: 'Exp OtherRelE',
        OtherRelE: 'CmpOp Exp',

        Exp: 'Term OtherTerm',
        OtherTerm: 'ε | AddOp Exp',

        Term: 'Factor OtherFactor',
        OtherFactor: 'ε | MultOp Term',

        Factor: '( Exp ) | INTC | Variable',
        Variable: 'ID VariMore',
        VariMore: 'ε | [ Exp ] | . FieldVar',

        FieldVar: 'ID FieldVarMore',
        FieldVarMore: 'ε | [ Exp ]',

        CmpOp: '< | =',
        AddOp: '+ | -',
        MultOp: '* | /'

6.构建LL1分析表,如下所示

7.根据LL1的分析方法,构建相应的符号栈,输入流栈,终极符列表,非终极符列表,生成式列表,LL1分析表对象,按照LL1的分析流程进行分析,如果出错,则抛出错误,告诉用户分析失败,同时给出出错的行数,此时分析栈中的具体内容,如果分析通过,则显示分析通过。

成功的运行结果

失败的运行结果

结论

此程序实现了SNL的词法分析和语法分析的基本功能,可以通过用例产生预期效果。在程序编写的过程中借鉴了教材《编译程序的设计与实现》。此次编写程序使我更加了解到编译器的重要性,并且提高了自己编程能力,希望以后自己有时间多多学习一下这方面。

猜你喜欢

转载自blog.csdn.net/newlw/article/details/124980850