Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GoでParserを書く

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 GoでParserを書く

Avatar for karupanerura

karupanerura

May 17, 2024
Tweet

More Decks by karupanerura

Other Decks in Programming

Transcript

  1. @karupanerura • Perl / Go / Java / TypeScript /

    etc.. • Software Engineer @ DeNA, Co,. LTD. • ୅දཧࣄ @ Japan Perl Association • GoCon͸ؾ෇͍ͨΒCfPऴΘͬͯͨ
  2. Parserྺ • ͦͦ͜͜Parserॻ͍ͨ͜ͱ͋Δ • Perl (JSON5, TOML::Parser, Text::MustacheTemplate) • C

    (c-geohex3, MySQL::Dump::Parser::XS, etc..) • Go (gqlparser, google-cloud-work fl ow-emulator) • But ମܥతʹֶΜͩ͜ͱ͸ͳ͍ • ΋͠ͳΜ͔͓͔͠ͳ͜ͱݴͬͯͨΒποίϛ΄͍͠Ͱ͢
  3. ߏจΛղੳ͢ΔҰൠతͳखॱ • (Tokenize) ςΩετΛҙຯͷ͋Δ୯Ґʹ·ͱΊΔ • ྫ: "123+456" -> "123", "+",

    "456" • ͜ΕΛ΍Δ΍ͭ͸LexerɺTokenizerɺScannerͳͲͱݺ͹ΕΔ • (Parse) (্هͷ·ͱ·ΓΛ΋ͱʹ)ͦͷҙຯΛදݱ͢Δߏ଄ʹม׵͢Δ • ྫ: "123", "+", "456" -> Plus{Left: 123, Right: 456} • ڱٛͷParserͱͯ͠Parserͱݴ͍ͭͭ͜Ε͚ͩΛࢦ͢͜ͱ΋͋Δ
  4. ͦͷଞɺසग़୯ޠ • AST (Abstract Syntax Tree) ͋Δ͍͸ ந৅ߏจ໦ • ςΩετΛ͋Δߏจͱͯ͠ղऍͨ͠ͱ͖ͷҙຯΛߏ଄ͱͯ͠දݱ

    • લड़ͷParserͷ݁Ռͱͯ͠͸େ఍͜ΕΛ࡞Δ • BNF • ߏจͷߏ଄Λهड़͢ΔͨΊͷߏจ • ABNFͳͲ೿ੜܗ΋͋Δ
  5. 1+2

  6. Binary{ OP: '+', L: Binary{ OP: '+', L: Integer(1), R:

    Binary{ OP: '*', L: Binary{OP: '-', L: Integer(2), R: Integer(1)}, R: Integer(2), }, }, R: Integer(3), }
  7. ୊ࡐ: GQL Parser • GraphQLͰ͸ͳ͘Google Cloudʹ͋ΔಠࣗͷSQLతͳݴޠ • Cloud Firestore datastore

    mode (Cloud Datastore) ͷΫΤϦݴޠ • https://cloud.google.com/datastore/docs/reference/gql_reference • goyaccʹΑΔ࣮૷͸طग़ • https://github.com/nshmura/dsio/blob/master/gql/parser.go.y
  8. GQLͷྫ • SELECT * FROM foo • SELECT __key__ FROM

    foo • SELECT DISTINCT f1, f2 FROM foo • SELECT DISTINCT ON (f1, f2) f1, f2, f3 FROM foo • SELECT * FROM foo WHERE f1 = 1 AND (f2 = 2 OR f3 = 3)
  9. tokenAcceptor type tokenAcceptor interface { accept(tokenReader) error } type tokenReader

    interface { Next() bool Read() (Token, error) } // ҎԼ͞·͟·ͳtokenAcceptorͷ࣮૷
  10. tokenAcceptor࢖༻ྫ func acceptQuery(query *Query) tokenAcceptor { return tokenAcceptors{ skipWhitespaceToken, acceptKeyword("SELECT"),

    acceptWhitespaceToken, acceptSelectQueryBody(query), } } func acceptSelectQueryBody(query *Query) tokenAcceptor { return tokenAcceptors{ &conditionalTokenAcceptor{ ifAccept: acceptKeyword("DISTINCT"), andThen: acceptDistinctBody(query), orElse: nopAcceptor, }, ...
  11. ·ͱΊ • ParserΛॻ͘ͷ͸೉͍͠ • Parser Generatorͱ͔࢖ͬͨ΄͏͕ݡ͍ • جຊతʹखॻ͖͸Ἒͷಓ • ParserΛॻ͘ͷ͸ָ͍͠

    • ීஈWeb։ൃͰॻ͔ͳ͍Α͏ͳίʔυ͕ॻ͚Δ • ؾ෼స׵ʹͽͬͨΓͳͷͰ͓͢͢Ί