【问题标题】:Building a parser in prolog在 prolog 中构建解析器
【发布时间】:2016-03-28 20:08:40
【问题描述】:

我正在尝试构建一个解析器,但我似乎无法理解它是如何工作的。我需要有人指引我正确的方向,这样我才能从那里捡起它。

所以我有一个分词器和一个词法分析器。

分词器输出:

[int,add,(,int,a,,,int,b,),=,a,+,b,int,letin,(,int,a,),=,let,b,=, 10,in,add,(,a,,,b,),int,equal,(,int,a,,,int,b,),=,if,a,==,b,then,letin,( ,a,),else,1,int,main,(,int,input,),=,equal,(,input,,,2,)]

词法分析器输出:

[TYPE_INT,IDENTIFIER,OPEN_P,TYPE_INT,IDENTIFIER,COMMA,TYPE_INT,IDENTIFIER,CLOSE_P,ASSIGN,IDENTIFIER,ARITH_ADD,IDENTIFIER,TYPE_INT,IDENTIFIER,OPEN_P,TYPE_INT,IDENTIFIER,CLOSE_P,ASSIGN,LET,IDENTIFIER,ASSIGN, IDENTIFIER,LET_IN,IDENTIFIER,OPEN_P,IDENTIFIER,COMMA,IDENTIFIER,CLOSE_P,TYPE_INT,IDENTIFIER,OPEN_P,TYPE_INT,IDENTIFIER,COMMA,TYPE_INT,IDENTIFIER,CLOSE_P,ASSIGN,COND_IF,IDENTIFIER,LOGIC_EQ,IDENTIFIER,COND_THEN,IDENTIFIER,OPEN_P, IDENTIFIER,CLOSE_P,COND_ELSE,INTEGER,TYPE_INT,IDENTIFIER,OPEN_P,TYPE_INT,IDENTIFIER,CLOSE_P,ASSIGN,IDENTIFIER,OPEN_P,IDENTIFIER,COMMA,INTEGER,CLOSE_P]

现在我必须构建一个解析器。我不知道如何开始以及如何包含参数化构造。

我的规则是这样的。

program --> functionList.
functionList --> function,functionListCollection.
functionListCollection --> functionList | [].
function --> typeID(typeIdList),[=],expression.
typeID --> [int],[id] | [bool],[id].
typeIdList --> typeID,typeIdListCollection.
typeIdListCollection --> [,], typeIdList | [].
expression --> [if], comparison, [then], value, [else], value.
expression --> [let],[id],[=], value, [in], expression.
expression --> value, extraExpression.
extraExpression --> arithmetic | [].
arithmetic --> [+], value | [-], value.
comparison --> value, comparisonRight.
comparisonRight --> [=],[=],value.
comparisonRight --> [!], [=], value.
comparisonRight --> [>], value.
comparisonRight --> [>], [=], value.
value --> [number].
value --> [id], valueParameters.
valueParameters --> [(],parameters,[)]. | [].
parameters --> value, parametersList.
parametersList --> [,], parameters | [].

我正在寻找构建一个谓词,该谓词采用词法列表并将列表从解析器中取出。然后,我将通过查看令牌列表来替换数字和标识符。一些关于如何开始的帮助将不胜感激。谢谢。

【问题讨论】:

    标签: prolog dcg


    【解决方案1】:

    您的“Lexer 输出”似乎不仅无用,而且实际上很危险。它(任意?)重命名已经是解析器一部分的重要符号(如int)(顺便说一句,标记器和词法分析器是同义词 afaik)。因此,只需使用分词器输出输入您的 DCG(已更正后,请参见下文):

    tokens_test :-
        Tokens = [
            int,add,=,a,+,33
            % ...more source code to test - but please use writeq to show it  ...
            %,int,let,in,'(',int,a,')',=,let,b,=,10
            %,in,add,'(',a,',',b,')',int,equal,'(',int,a,',',int,b,')',=
            %,if,a,==,b,then,let,in,'(',a,')',else,1
            %,int,main,'(',int,input,')',=,equal,'(',input,',',2,')'
        ], phrase(program, Tokens).
    
    ?- tokens_test.
    true 
    

    我改变了你的 DCG,因为你有 [id] 和 [number] 作为终端:

    id --> [I], {atom(I)}.
    number --> [N], {number(N)}.
    
    program --> functionList.
    functionList --> function,functionListCollection.
    functionListCollection --> functionList | [].
    function --> typeID,[=],expression.
    typeID --> [int],id | [bool],id.
    typeIdList --> typeID,typeIdListCollection.
    typeIdListCollection --> [,], typeIdList | [].
    expression --> [if], comparison, [then], value, [else], value.
    expression --> [let], id, [=], value, [in], expression.
    expression --> value, extraExpression.
    extraExpression --> arithmetic | [].
    arithmetic --> [+], value | [-], value.
    comparison --> value, comparisonRight.
    comparisonRight --> [=],[=],value.
    comparisonRight --> [!], [=], value.
    comparisonRight --> [>], value.
    comparisonRight --> [>], [=], value.
    value --> number.
    value --> id, valueParameters.
    valueParameters --> ['('],parameters,[')'] | [].
    parameters --> value, parametersList.
    parametersList --> [,], parameters | [].
    

    如果你有一个分隔符(逗号,下面),你可以避免像

    这样的服务谓词
    typeIdList --> typeID,typeIdListCollection.
    typeIdListCollection --> [,], typeIdList | [].
    

    可能是

    typeIdList --> typeID, ( [,], typeIdList | [] ).
    

    但这种“简化”的便利性可能取决于其他因素。

    如何包含参数化结构

    id//0 和 number//0 是非终结符,应该“取回”它们的值:它们变成 id//1 和 number//1,通常,我们用非终结符“标记”值终端(所以我们备用符号:-)

    id(id(I)) --> [I],   % better to filter out keywords here...
      {atom(I), \+memberchk(I,[let, etc etc])}.
    number(number(N,integer)) --> [N], {integer(N)}.
    number(number(N,float)) --> [N], {float(N)}.
    

    现在调用它们的位置,我们必须更改为

    ...
    typeID --> [int],id(_) | [bool],id(_).
    ...
    

    很明显 typeID//0 现在应该“取回”值(所谓的语义属性),否则它们会丢失:

    ...
    typeID(typeID(T,I)) --> [int],id(I),{T=int} | [bool],id(I),{T=bool}.
    ...
    

    这显示了编写 typeID//1 的更好方法。可能是

    typeID(typeID(T,I)) --> type(T),id(I).
    
    type(int) --> [int].
    type(bool) --> [bool].
    

    希望你得到图片:-)

    【讨论】:

      【解决方案2】:

      让你的词法分析器 (*) 为你输出,而不是数据为

      [type(int), id(add), open_p, type(int), id(a), .....
      

      所以你的规则中有完整的信息,比如

      ....
      typeID(T,A) --> [type(T)], { memberchk(T, [int,bool]) }, [id(A)],
      ....
      

      测试:

      32 ?- phrase( typeID(X,Y), [type(int), id(i)], []).
      X = int,
      Y = i.
      
      33 ?- phrase( typeID(X,Y), [type(bool), id(i)], []).
      X = bool,
      Y = i.
      
      34 ?- phrase( typeID(X,Y), [type(float), id(i)], []).
      false.
      

      (*) 或者您可以将您的标记和您当前的词法分析器输出组合起来以获取组合数据,maplist

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多