2016-11-10 36 views
2

我正在解析同時具有<<<的語言。在我的亞歷克斯定義我已經得到的東西,它包含類似在Happy和Alex中推回令牌

tokens :- 

"<"    { token Lt } 
"<<"   { token (BinOp Shl) } 

所以每當我遇到<<,是被符號化的左移和以低於的。這通常是一件好事,因爲我最終在標記後拋出空白,並且想區分1 < < 21 << 2。不過,還有其他的時候我希望<<已經被讀爲兩個<。例如,我有事情喜歡

<<A>::B> 

,我想讀到這樣

< <A> :: B > 

很顯然,我可以嘗試調整我的快樂的語法規則,以適應額外的案件,但它可以擴展得厲害。在其他命令式解析器生成器中,我可能會嘗試執行某些操作,比如推回令牌的「部分」(如push_back("<"),當我遇到<<但我只需要<時)。

有沒有其他人有這樣的問題,如果是的話,你是如何處理它的?在快樂中有沒有「推回」令牌的方法?我是否應該試着保留一個空白符號(我實際上傾向於最後一種選擇 - 儘管這是一個非常頭痛的問題,但它會讓我通過確保兩個<之間沒有空格來處理<<)。

回答

0

當我最初與@ Jon的答案一起使用時,我最終遇到了各種與優先級相關的問題(認爲優先級大約爲expr < expr vs expr << expr),這使我很頭疼。我最近(成功)回到<<作爲一個令牌。該解決方案是雙重的:

  1. 我忍辱負重,增加了額外的規則<<(而以前我只用了規則<)。對於這個問題的例子(<<A>::B>)我的規則從出事像

    ty_qual_path 
        : '<' ty_sum '>' '::' ident 
    

    ty_qual_path 
        : '<' ty_sum '>' '::' ident 
        | '<<' ty_sum '>' '::' ident '>' '::' ident 
    

    (實際的規則實際上是有點更復雜,但是這是不是這個答案)。

  2. 我找到了一個巧妙的方法來處理與>開始令牌(這會導致周圍的事物問題,如vector<i32,vector<i32>>其中最後>>是一個令牌):使用threaded lexer (section 2.5.2),開拓{%% ... } RHS的規則,它可以讓你重新考慮向前令牌,並添加一個pushToken設施到我的分析器monad(this turned out to be quite simple - here is exactly what I did)。然後我添加了一個虛擬的規則 - 像

    gt :: {() } 
        : {- empty -} {%% \tok -> 
         case tok of 
         Tok ">>" -> pushToken (Tok ">") *> pushToken (Tok ">") 
         Tok ">=" -> pushToken (Tok "=") *> pushToken (Tok ">") 
         Tok ">>=" -> pushToken (Tok ">=") *> pushToken (Tok ">") 
         _   -> pushToken tok 
        } 
    

    而在其他一些規則,每次我預期>但也可能是任何其他標記開始>,我會先於>令牌gt。這有望展望下一個令牌,其可以以>而不是>開始,並嘗試將該令牌轉換爲一個>令牌以及用於初始令牌的「休息」的另一個令牌。

2

我不知道如何在Happy中表達這個,但是你不需要單獨的「空白」標記。當輸入中緊接着一個運算符符號時,您可以將<>解析爲不同的「尖括號」標記,而不需要中間空白。

然後,當您想要解析一個運算符時,您將一系列角度和運算符合併到一個令牌中。當你想把它們當作括號時,你只需像往常一樣單獨處理它們。

所以a << b將被標記化如:

identifier "a" 
left angle  -- joined with following operator 
operator "<" 
identifier "b" 

當解析操作,您連接角令牌具有以下運算符標記,產生一個單一的operator "<<"令牌。

<<A>::B>將被標記化如下:

left angle 
operator "<" -- accepted as bracket 
identifier "A" 
right angle 
operator "::" 
identifier "B" 
operator ">" -- accepted as bracket 

當解析尖括號中的條款,您同時接受角度令牌和</>運營商。

這依賴於你的語法不含糊不清。你是否應該解析一個操作符名稱或括號內的事物。

+0

聰明的主意!雖然我還沒有設法找到Alex獲得兩個代幣的方法,但我可以看到這將如何工作。謝謝! – Alec

+0

@Alec:是的,我只在Parsec中使用過這種技術,你可以向前看(比如'try(運算符<$> char'<'<* notFollowedBy symbol)<|> LeftAngle <$> char'<'')看起來不可能直接在Alex中表達。不知怎的,你大概可以對它進行編碼。 –