From 436a9dda79020ad6eeec50253b14c8b36c1c4d88 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 9 Mar 2021 20:46:52 -0800 Subject: [PATCH] [executable semantics] Minimal cxx parser (#363) Makes a minimal transition to using C++ in the parser. --- executable_semantics/syntax/lexer.lpp | 62 +++++----- executable_semantics/syntax/parse.cpp | 3 +- .../syntax/parse_and_lex_context.cpp | 2 +- .../syntax/parse_and_lex_context.h | 7 +- executable_semantics/syntax/parser.ypp | 109 +++++++++--------- 5 files changed, 91 insertions(+), 92 deletions(-) diff --git a/executable_semantics/syntax/lexer.lpp b/executable_semantics/syntax/lexer.lpp index 50f62f9e7b75..66dacec0a1bb 100644 --- a/executable_semantics/syntax/lexer.lpp +++ b/executable_semantics/syntax/lexer.lpp @@ -50,43 +50,43 @@ integer_literal [0-9]+ %% -{AND} { return AND; } -{ARROW} { return ARROW; } -{AUTO} { return AUTO; } -{BOOL} { return BOOL; } -{BREAK} { return BREAK; } -{CASE} { return CASE; } -{CHOICE} { return CHOICE; } +{AND} { return yy::parser::token::AND; } +{ARROW} { return yy::parser::token::ARROW; } +{AUTO} { return yy::parser::token::AUTO; } +{BOOL} { return yy::parser::token::BOOL; } +{BREAK} { return yy::parser::token::BREAK; } +{CASE} { return yy::parser::token::CASE; } +{CHOICE} { return yy::parser::token::CHOICE; } {COMMENT} ; -{CONTINUE} { return CONTINUE; } -{DBLARROW} { return DBLARROW; } -{DEFAULT} { return DEFAULT; } -{ELSE} { return ELSE; } -{EQUAL} { return EQUAL; } -{FALSE} { return FALSE; } -{FN} { return FN; } -{FNTY} { return FNTY; } -{IF} { return IF; } -{INT} { return INT; } -{MATCH} { return MATCH; } -{NOT} { return NOT; } -{OR} { return OR; } -{RETURN} { return RETURN; } -{STRUCT} { return STRUCT; } -{TRUE} { return TRUE; } -{TYPE} { return TYPE; } -{VAR} { return VAR; } -{WHILE} { return WHILE; } +{CONTINUE} { return yy::parser::token::CONTINUE; } +{DBLARROW} { return yy::parser::token::DBLARROW; } +{DEFAULT} { return yy::parser::token::DEFAULT; } +{ELSE} { return yy::parser::token::ELSE; } +{EQUAL} { return yy::parser::token::EQUAL; } +{FALSE} { return yy::parser::token::FALSE; } +{FN} { return yy::parser::token::FN; } +{FNTY} { return yy::parser::token::FNTY; } +{IF} { return yy::parser::token::IF; } +{INT} { return yy::parser::token::INT; } +{MATCH} { return yy::parser::token::MATCH; } +{NOT} { return yy::parser::token::NOT; } +{OR} { return yy::parser::token::OR; } +{RETURN} { return yy::parser::token::RETURN; } +{STRUCT} { return yy::parser::token::STRUCT; } +{TRUE} { return yy::parser::token::TRUE; } +{TYPE} { return yy::parser::token::TYPE; } +{VAR} { return yy::parser::token::VAR; } +{WHILE} { return yy::parser::token::WHILE; } {identifier} { int n = strlen(yytext); - yylval.str = reinterpret_cast(malloc((n + 1) * sizeof(char))); - strncpy(yylval.str, yytext, n + 1); - return identifier; + yylval->identifier = reinterpret_cast(malloc((n + 1) * sizeof(char))); + strncpy(yylval->identifier, yytext, n + 1); + return yy::parser::token::identifier; } {integer_literal} { - yylval.num = atof(yytext); - return integer_literal; + yylval->integer_literal = atof(yytext); + return yy::parser::token::integer_literal; } [ \t\n]+ ; diff --git a/executable_semantics/syntax/parse.cpp b/executable_semantics/syntax/parse.cpp index 6bdd9e4a4540..61a12064b126 100644 --- a/executable_semantics/syntax/parse.cpp +++ b/executable_semantics/syntax/parse.cpp @@ -7,6 +7,7 @@ #include #include "executable_semantics/syntax/parse_and_lex_context.h" +#include "executable_semantics/syntax/parser.h" #include "executable_semantics/tracing_flag.h" extern FILE* yyin; @@ -28,7 +29,7 @@ auto parse(const std::string& inputFileName) std::optional parsedInput = std::nullopt; ParseAndLexContext context(inputFileName); - auto syntaxErrorCode = yyparse(parsedInput, context); + auto syntaxErrorCode = yy::parser(parsedInput, context)(); if (syntaxErrorCode != 0) { return syntaxErrorCode; } diff --git a/executable_semantics/syntax/parse_and_lex_context.cpp b/executable_semantics/syntax/parse_and_lex_context.cpp index eb39b12a5780..99d5a086352f 100644 --- a/executable_semantics/syntax/parse_and_lex_context.cpp +++ b/executable_semantics/syntax/parse_and_lex_context.cpp @@ -11,7 +11,7 @@ // Writes a syntax error diagnostic, containing message, for the input file at // the given line, to standard error. -auto Carbon::ParseAndLexContext::PrintDiagnostic(const char* message, +auto Carbon::ParseAndLexContext::PrintDiagnostic(const std::string& message, int line_num) -> void { std::cerr << inputFileName << ":" << line_num << ": " << message << std::endl; exit(-1); // TODO: do we really want this here? It makes the comment and the diff --git a/executable_semantics/syntax/parse_and_lex_context.h b/executable_semantics/syntax/parse_and_lex_context.h index ec81c3f025a4..71bcc8839621 100644 --- a/executable_semantics/syntax/parse_and_lex_context.h +++ b/executable_semantics/syntax/parse_and_lex_context.h @@ -21,7 +21,7 @@ class ParseAndLexContext { // Writes a syntax error diagnostic, containing message, for the input file at // the given line, to standard error. - auto PrintDiagnostic(const char* message, int lineNumber) -> void; + auto PrintDiagnostic(const std::string& message, int lineNumber) -> void; private: // A path to the file processed, relative to the current working directory @@ -32,7 +32,10 @@ class ParseAndLexContext { } // namespace Carbon // Gives flex the yylex prototype we want. -#define YY_DECL int yylex(Carbon::ParseAndLexContext& context) +#define YY_DECL \ + int yylex(yy::parser::semantic_type* yylval, \ + yy::parser::location_type* sourceLocation, \ + Carbon::ParseAndLexContext& context) // Declares yylex for the parser's sake. YY_DECL; diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index 6c83b92bb977..89257937b4df 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -2,6 +2,30 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// ----------------------------------------------------------------------------- +// Bison Configuration +// ----------------------------------------------------------------------------- + +%require "3.2" +%language "c++" + +// We don't need a separate header for Bison locations yet. +%define api.location.file none + +// +// Parameters to the parser and lexer +// +// Parameters to the parser are stored therein as protected data members, and +// thus available to its methods. + +// "out" parameter passed to the parser, where the AST is written. +%parse-param {std::optional& parsedProgram} + +// "inout" parameter passed to both the parser and the lexer. +%param {Carbon::ParseAndLexContext& context} + +// ----------------------------------------------------------------------------- + %code top { #include #include @@ -32,68 +56,39 @@ class ParseAndLexContext; extern int yylineno; -void yyerror( - std::optional const& /* parsedProgram */, - Carbon::ParseAndLexContext& context, - char* message -) { +void yy::parser::error( + const location_type&, const std::string& message) +{ context.PrintDiagnostic(message, yylineno); } + } -// -// Parameters to yyparse and yylex. -// +%define api.value.type union -// "out" parameter passed to the parser, where the AST is written. -%parse-param {std::optional& parsedProgram} - -// "inout" parameter passed to both the parser and the lexer. -%param {Carbon::ParseAndLexContext& context} - -%union { - char* str; - int num; - Carbon::Expression* expression; - std::list>* field_types; - Carbon::Statement* statement; - Carbon::Statement* statement_list; - Carbon::FunctionDefinition* function_definition; - Carbon::Declaration* declaration; - std::list* declaration_list; - Carbon::Member* member; - std::list* member_list; - Carbon::FieldList* field_list; - std::pair* alternative; - std::list>* alternative_list; - std::pair* clause; - std::list>* clause_list; - Carbon::Expression* fun_type; -}; - -%token integer_literal -%token identifier -%type designator -%type declaration -%type function_declaration -%type function_definition -%type declaration_list -%type statement -%type optional_else -%type statement_list -%type expression -%type pattern -%type return_type -%type paren_expression -%type tuple -%type member -%type member_list -%type field -%type field_list -%type alternative -%type alternative_list -%type clause -%type clause_list +%token integer_literal +%token identifier +%type designator +%type declaration +%type function_declaration +%type function_definition +%type *> declaration_list +%type statement +%type optional_else +%type statement_list +%type expression +%type pattern +%type return_type +%type paren_expression +%type tuple +%type member +%type *> member_list +%type field +%type field_list +%type *> alternative +%type >*> alternative_list +%type *> clause +%type >*> clause_list %token AND %token OR %token NOT