• 使用bison和yacc制作脚本语言(2)


    我们先来想一下语法

    一般脚本语言不需要定义类型直接在赋值的时候确定

    1. 我们主要考虑一下变量的类型
    a = 1;
    b = 1.1;
    c = "str";
    

    一般来讲,我们使用这三种类型,整形,浮点型,字符串型

    不过我们以后还可能使用原生类型等

    1. 变量的基本运算和其他语言基本相同
    a = b + 12.4;
    c = "hehe" + a + "haha"
    
    1. 函数定义 我们可以模仿一下js的函数定义方式,不过变量使用的时候我们需要声明才可以使用全局变量
    function func(){global outervar;}
    
    1. 简单的流程控制
    for(a = 0;a<10;a++) {break;continue;}
    if(a){}
    

    文法

    我们先简单写一下文法,因为bison是LALR文法,注意一下和LL系列文法的区别

    如果是自己要制作编程语言的话不妨参考一下C语言的bison文法:http://www.quut.com/c/ANSI-C-grammar-y-1998.html

    一般情况下,非终结符我们规定都是小写的,终结符都是大写的

    先看开头部分

    translation_unit: definition_or_statement 
            | translation_unit definition_or_statement 
            ;
    

    我们认为所有的语句,函数等都会规约成 translation_unit ,多个语句或者是定义可以被规约成一个,

    |是代表或的意思,;这小段文法的结束

    definition_or_statement:function_definition
    		|statement
    		;
    

    一般语句和定义可以由语句或者函数定义规约

    函数定义我们认为类似于这样的 function funcname(arg1,arg2){} 和下面对应,我们可以定义有参数和无参的函数

    function_definition: FUNCTION IDENTIFIER LP arglist RP block
            |FUNCTION IDENTIFIER LP RP block
            ;
    

    语句:

    statement:expression_statement
            |global_declaration
            |for_statement 
            |if_statement
            |break_statement
            |continue_statement
            |return_statement
            ;
    

    表达式语句:我们每个语句都是由;结尾的,SEMICOLON就是分号

    expression_statement:expression SEMICOLON
    		;
    

    表达式 一般就都有值,可以计算的,比如赋值,加减乘除计算等等

    LALR 文法一般是运算级高的先规约,一般情况下常量先规约,一般是单目运算符,括号,函数调用先规约

    primary_expression:SUB primary_expression /* 取负 */
            |LP expression RP /* 括号 */
            |IDENTIFIER /* 变量名 */
            |STRING_LITERAL /* 字符串 */
            |INT_LITERAL /* 整数 */
            |DOUBLE_LITERAL /* 浮点 */
            |IDENTIFIER LP RP /* 无参数函数调用 */
            |IDENTIFIER LP arglist RP
            ;
    

    下面开始简单的四则运算乘除法会比加减有更高的优先级别,所以primary_expression优先规约成mul_div_expression

    mul_div_expression:primary_expression
            |mul_div_expression DIV primary_expression
            |mul_div_expression MUL primary_expression
            ;
    

    加减法:

    add_sub_expression:mul_div_expression 
            |add_sub_expression ADD mul_div_expression
            |add_sub_expression SUB mul_div_expression
            ;
    

    同理比较运算和等于不等于运算省略

    上面的可以规约为赋值表达式 (ASSIGN 是等于=在lex文件中定义)

    expression: value_expression
            |IDENTIFIER ASSIGN expression
    

    表达式可以在上面规约为语句,因此表达式部分的文法就完成了

    if语句也很简单

    if_statement: IF LP expression RP block
    		;
    

    for语句:

    for_statement: FOR LP expression_option SEMICOLON expression_option SEMICOLON expression_option  RP block
    	;
    

    程序块:

    block:LC RC
    	|LC statement_list RC
    	;
    

    break,return,continue都一样

    break_statement:BREAK SEMICOLON
            ;
    continue_statement:CONTINUE SEMICOLON
            ;
    

    还有一些没解释的都很容易理解

    现在已经定义的全部文法:

    translation_unit: definition_or_statement 
            | translation_unit definition_or_statement
            ;
    definition_or_statement:function_definition
            |statement
            ;
    function_definition: FUNCTION IDENTIFIER LP arglist RP block
            |
            FUNCTION IDENTIFIER LP RP block
            ;
    statement:expression_statement
            |global_declaration
            |for_statement 
            |if_statement
            |break_statement
            |continue_statement
            |return_statement
            ;
    expression_statement:expression SEMICOLON
            ;
    expression: value_expression
            |IDENTIFIER ASSIGN expression
            ;
    value_expression: compare_expression
            |value_expression EQ compare_expression
            |value_expression NE compare_expression
            ;
    compare_expression:add_sub_expression 
            |compare_expression GT add_sub_expression
            |compare_expression GE add_sub_expression
            |compare_expression LT add_sub_expression
            |compare_expression LE add_sub_expression
            ;
    add_sub_expression:mul_div_expression 
            |add_sub_expression ADD mul_div_expression
            |add_sub_expression SUB mul_div_expression
            ;
    mul_div_expression:primary_expression
            |mul_div_expression DIV primary_expression
            |mul_div_expression MUL primary_expression
            ;
    primary_expression:SUB primary_expression
            |LP expression RP
            |IDENTIFIER
            |STRING_LITERAL
            |INT_LITERAL
            |DOUBLE_LITERAL
            |IDENTIFIER LP RP
            |IDENTIFIER LP arglist RP
            ;
    statement_list:statement_list statement
            |statement
            ;
    block:LC RC
            |LC statement_list RC
    
            ;
    arglist:arglist COMMA arg
            |
            arg
            ;
    arg:    IDENTIFIER
            ;
    expression_option:
            |expression
            ;
    for_statement: FOR LP expression_option SEMICOLON expression_option SEMICOLON expression_option  RP block
            ;
    if_statement: IF LP expression RP block
            ;
    break_statement:BREAK SEMICOLON
            ;
    continue_statement:CONTINUE SEMICOLON
            ;
    return_statement:RETURN IDENTIFIER
            ;
    global_declaration:GLOBAL IDENTIFIER
            ;
    
  • 相关阅读:
    如何利用 JConsole观察分析Java程序的运行,进行排错调优
    【解决】网站运行一段时间后就无法访问,重启Tomcat才能恢复
    不允许一个用户使用一个以上用户名与一个服务器或共享
    SVN升级到1.8后 Upgrade working copy
    Windows Server 2012 R2 创建AD域
    JTA 深度历险
    svn merge error must be ancestrally related to,trunk merge branch报错
    OutputStream-InputStream-FileOutputStream-FileInputStream-BufferedOutputStream-BufferedInputStream-四种复制方式-单层文件夹复制
    SVN提交时响应很慢,我是这样解决的。
    docker学习6-docker-compose容器集群编排
  • 原文地址:https://www.cnblogs.com/stdpain/p/10524065.html
Copyright © 2020-2023  润新知