質問
私はC--(実際のC--言語ではない)と呼ばれる架空のプログラミング言語のパーサーを構築しています。言語の文法をPyparsingが受け入れられるものに翻訳する必要がある段階に到達しました。残念ながら、入力文字列を解析するようになったとき(これは正しく、Pyparsingでエラーが発生しないはずです)、正しく解析されていません。これは文法の誤りによるものではないかと心配していますが、初めてPyparsingを開始しているので、どこが間違っているのかわかりません。
翻訳する文法をこちらからアップロードしました。読んでください。
編集:ポールのアドバイスで更新。
これは私が現在持っているグラマーです(構文定義の2つの最上行は、私が知っている私にとってひどく悪いです):
# Lexical structure definition
ifS = Keyword('if')
elseS = Keyword('else')
whileS = Keyword('while')
returnS = Keyword('return')
intVar = Keyword('int')
voidKeyword = Keyword('void')
sumdiff = Literal('+') | Literal('-')
prodquot = Literal('*') | Literal('/')
relation = Literal('<=') | Literal('<') | Literal('==') | \
Literal('!=') | Literal('>') | Literal('=>')
lbrace = Literal('{')
rbrace = Literal('}')
lparn = Literal('(')
rparn = Literal(')')
semi = Literal(';')
comma = Literal(',')
number = Word(nums)
identifier = Word(alphas, alphanums)
# Syntax definition
term = ''
statement = ''
variable = intVar + identifier + semi
locals = ZeroOrMore(variable)
expr = term | OneOrMore(Group(sumdiff + term))
args = ZeroOrMore(OneOrMore(Group(expr + comma)) | expr)
funccall = Group(identifier + lparn + args + rparn)
factor = Group(lparn + expr + rparn) | identifier | funccall | number
term = factor | OneOrMore(prodquot + factor)
cond = Group(lparn + expr + relation + expr + rparn)
returnState = Group(returnS + semi) | Combine(returnS + expr + semi)
assignment = Group(identifier + '=' + expr + semi)
proccall = Group(identifier + lparn + args + rparn + semi)
block = Group(lbrace + locals + statement + rbrace)
iteration = Group(whileS + cond + block)
selection = Group(ifS + cond + block) | Group(ifS + cond + block + elseS + block)
statement = OneOrMore(proccall | assignment | selection | iteration | returnState)
param = Group(intVar + identifier)
paramlist = OneOrMore(Combine(param + comma)) | param
params = paramlist | voidKeyword
procedure = Group(voidKeyword + identifier + lparn + params + rparn + block)
function = Group(intVar + identifier + lparn + params + rparn + block)
declaration = variable | function | procedure
program = OneOrMore(declaration)
文法を翻訳する際にミスがあったかどうか、また、与えられた文法を順守しながら単純化するためにどのような改善ができるかを知りたいです。
編集2:新しいエラーを含めるように更新しました。
これは、解析中の入力文字列です。
int larger ( int first , int second ) {
if ( first > second ) {
return first ;
} else {
return second ;
}
}
void main ( void ) {
int count ;
int sum ;
int max ;
int x ;
x = input ( ) ;
max = x ;
sum = 0 ;
count = 0 ;
while ( x != 0 ) {
count = count + 1 ;
sum = sum + x ;
max = larger ( max , x ) ;
x = input ( ) ;
}
output ( count ) ;
output ( sum ) ;
output ( max ) ;
}
これは、ターミナルからプログラムを実行するときに表示されるエラーメッセージです。
/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1156: SyntaxWarning: null string passed to Literal; use Empty() instead
other = Literal( other )
/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1258: SyntaxWarning: null string passed to Literal; use Empty() instead
other = Literal( other )
Expected ")" (at char 30), (line:6, col:26)
None
解決
1)先頭の<!> quot; if <!> quot;と一致しないように、Literal("if")
をKeyword("if")
に変更します(以下同様に、Literal("void")
まで)。 "ifactor"
という名前の変数の。
2)nums
、alphas
、およびalphanums
は式ではなく、文字列であり、Wordクラスで使用して、<!> quot; words <! > quot; <!> quot;数字はnums <!> quot;または<!> quot;で構成される単語です。識別子は、アルファで始まり、その後に0個以上の英数字が続く単語です。<!> quot;代わりに:
number = nums
identifier = alphas + OneOrMore(alphanums)
欲しい
number = Word(nums)
identifier = Word(alphas, alphanums)
3)Combine
の代わりに、Group
が必要だと思います。一致するトークンを空白を入れずに連続させたい場合は"3.14"
を使用し、トークンを連結して単一の文字列として返します。 ['3', '.', '14']
は、次のような場合によく使用されます。
realnum = Combine(Word(nums) + "." + Word(nums))
'3.14'
なしで、3.14
を解析すると文字列のリスト'The answer is 3. 10 is too much.'
が返されるため、"3. 10"
を追加して、realnumの解析結果が"int x;"
になるようにします(解析アクションに渡すことができます)実際の浮動値に変換します"int x ;"
)。 Word
sの間に空白を挿入しないことにより、誤ってLiteral
を解析し、''
が実数を表していると考えることを防ぎます。
4)これはエラーの原因にはなりませんが、入力文字列には余分なスペースがたくさんあります。文法が機能するようになれば、<<
と同様に()
も解析できるはずです。
これらのヒントのいくつかがあなたを導くことを願っています。オンラインpyparsingの記事やチュートリアルを読んだことがありますか?オンラインの例をご覧ください。 <=>、<=>、<=>などが個々の解析タスクを実行する方法を十分に把握する必要があります。
5)用語およびステートメントの再帰的な定義を誤って実装しました。それらに<=>を割り当てる代わりに、次のように記述します。
term = Forward()
statement = Forward()
次に、再帰定義で実際に定義する場合は、<=>演算子を使用します(RHSは必ず<=>で囲みます)。
term << (... term definition ...)
statement << (... statement definition ...)
再帰的パーサーの例は、こちら、および基本的なpyparsingの使用法に関するプレゼンテーションこちら-セクションを参照<!> quot; Parsing Lists <!> quot;再帰の処理方法を段階的に説明しています。