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

GoでParserを書く

 GoでParserを書く

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։ൃͰॻ͔ͳ͍Α͏ͳίʔυ͕ॻ͚Δ • ؾ෼స׵ʹͽͬͨΓͳͷͰ͓͢͢Ί