各位大大,编译中 parser 如何能够构建出自己的 抽象语法? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
black11black
V2EX    问与答

各位大大,编译中 parser 如何能够构建出自己的 抽象语法?

  •  
  •   black11black 2020-02-17 15:13:49 +08:00 1769 次点击
    这是一个创建于 2064 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大家好,最近想做一个可编程化的类似 cicd 那种流程控制项目

    我个人比较菜,想先做个简单的 demo,想要实现如下这样的效果:

    def task1(file): ffmpeg -i file -o file.mp4 # etc. def task2(file): # do something else def workflow(folder): foreach file in folder: task1(file) task2(file) 

    ↑ 想要实现的是比如往程序里输入这样一个配置文件( python 语法抽象比较简洁,姑且先用类似的语法了)然后程序就会按照我设定好的这一套工作流程,按顺序执行所有设定好的工作。

    要让程序理解输入的工作流程描述文件,需要进行简单的词法和文法分析,然后抽象成 ast,因为只是个简单的 demo,里面没有什么复杂的东西,只要能实现定义与循环执行就可以了,甚至不需要表达式计算的功能

    按我理解,我的算法流程应该是这样的 1、先是词法分析(这个已经搞定了), 2、然后把代码分成一段一段的(比如类似 python 这种按照缩进分段,或者用{}表示,还没想好) 3、然后我需要抽象出一种当前语言的元语法

    #比如 stmt : stmt expr expr : (expr) expr : NODE 

    这种感觉的,(就是编译原理课上教的那种) 4、再然后实现一个 LL1 算法,对每段分别处理,就能 parse 出抽象语法树了。

    现在的一个犯难是并不知道怎么抽象出这种元语法(甚至在这种只有定义和调用、以及循环的简单情况下) 当初编译原理上的课都还给老师了,唉 现在还记得比如如果单纯要写一个描述运算表达式的元语法是很简单的,大概类似这样:

    expr : (expr) expr : expr + expr expr : expr * expr expr : expr - expr expr : expr / expr expr : NODE expr : -NODE 

    这种感觉,然后实际操作的时候类似一个简单的栈虚拟机就能搞定表达式运算,这个很简单。 但是这种有定义有调用的元语法该怎么写啊,老师当初也没讲过例子啊,啊啊啊啊啊啊啊啊啊啊啊啊

    10 条回复    2020-12-06 03:38:56 +08:00
    scalaer
        1
    scalaer  
       2020-02-17 15:20:58 +08:00
    先定个小目标, 实现个能跑的 dsl,dsl 多了, 再进一步抽象呗
    black11black
        2
    black11black  
    OP
       2020-02-17 15:24:33 +08:00
    @scalaer

    我现在在做的就算 dsl 吧...我觉得我这个目标定的也不大啊

    关于 parse,如果不抽象语法树的话,最土的做法是写很多条件判断,比如在 def 后面找一个 name token,然后再找括号,再找......找不到就报错之类的

    这么写的话感觉就很 low 啊。。
    scalaer
        3
    scalaer  
       2020-02-17 15:44:14 +08:00   1
    你看看 antlr, 没必要自己写 parser
    crella
        4
    crella  
       2020-02-17 16:17:54 +08:00 via Android
    ……隔壁 ruby 做这个感觉还算简单啊,不清楚 python 技术链

    反正我在代码里动态 eval 新的函数是没什么问题
    secondwtq
        5
    secondwtq  
       2020-02-17 17:04:26 +08:00
    随便找个栗子就行: https://www.lua.org/manual/5.3/manual.html
    翻到最底下
    black11black
        6
    black11black  
    OP
       2020-02-17 17:30:32 +08:00
    @secondwtq

    ORZ 好长,翻跪了

    program -> { [ def | statement ] EOL }
    def -> "def" IDENTIFIER "(" IDENTIFIER ")" : block
    block -> "{" statement { EOL statement } "}"
    statement -> "foreach" STRING "in" IDENTIFIER ":" block | simple
    simple -> { IDENTIFIER } | IDENTIFIER '(' IDENTIFIER ')' | IDENTIFIER '=' STRING

    ↑ 所以现在我感觉我设计的语法应该可以抽象成这样
    只有 define,循环 , 执行三个功能,没有 expr 计算。

    然后问题是,这东西咋搞成 LL1parser 啊,看了看感觉全是左循环左因子

    网上看了个例子,简单的 expr 运算拆成 LL1 就要写这么长了:

    s->e
    e->te'
    e'->+te'
    e'->-te'
    e'->空
    t->ft'
    t'->*ft'
    t'->/ft'
    t'->空
    f->NUMBER
    f->'('e')'

    感觉上面的要改的话要写死自己啊。。
    ai277014717
        7
    ai277014717  
       2020-02-17 17:37:01 +08:00
    lex/yacc 或者 antlr 然后直接处理回调就好了。
    momocraft
        8
    momocraft  
       2020-02-17 17:38:44 +08:00
    自己撸一整套本来就是是不小的工程

    如果你面向实用,要用户学你发明的语言也有成本

    要不要考虑用已有的语言+已有的 parser/interpreter
    secondwtq
        9
    secondwtq  
       2020-02-17 17:50:53 +08:00
    @black11black 你为啥非要死抠 LL(1) 呢
    thautwarm
        10
    thautwarm  
       2020-12-06 03:38:56 +08:00 via Android
    还需要帮忙吗?在下可以带给你新世界
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5468 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 01:25 PVG 09:25 LAX 18:25 JFK 21:25
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86