Initial grammar
This commit is contained in:
commit
7789e28631
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build
|
||||||
|
.vscode
|
24
CMakeLists.txt
Normal file
24
CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
|
project(dpro)
|
||||||
|
|
||||||
|
set(THIRD_PARTY_INCLUDE_DIRS third_party)
|
||||||
|
set(SRC_DIRS src)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
file(GLOB SRCS ${SRC_DIRS}/*.cpp ${SRC_DIRS}/*.h)
|
||||||
|
|
||||||
|
add_executable(${CMAKE_PROJECT_NAME} ${SRCS})
|
||||||
|
|
||||||
|
# find_package(GLEW REQUIRED)
|
||||||
|
# find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
|
find_package(Threads)
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
set(add_link_deps Threads::Threads)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories(${THIRD_PARTY_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(${CMAKE_PROJECT_NAME} ${add_link_deps})
|
25
default.nix
Normal file
25
default.nix
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{ pkgs ? import <nixpkgs> { } }:
|
||||||
|
pkgs.stdenv.mkDerivation rec {
|
||||||
|
pname = "dpro";
|
||||||
|
version = "0.1.0";
|
||||||
|
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.cmake
|
||||||
|
pkgs.gdb
|
||||||
|
];
|
||||||
|
|
||||||
|
configurePhase = ''
|
||||||
|
cmake .
|
||||||
|
'';
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
make
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
mv dpro $out/bin
|
||||||
|
'';
|
||||||
|
}
|
319
src/grammar.peg
Normal file
319
src/grammar.peg
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
Root <- skip Statement* eof
|
||||||
|
|
||||||
|
Fn <- KEYWORD_fn LPAREN ParamDeclList RPAREN Block
|
||||||
|
|
||||||
|
VarDecl <- IDENTIFIER (EQUAL Expr)? SEMICOLON
|
||||||
|
|
||||||
|
# *** Block Level ***
|
||||||
|
Statement
|
||||||
|
<- VarDecl
|
||||||
|
/ IfStatement
|
||||||
|
/ LabeledStatement
|
||||||
|
/ AssignExpr SEMICOLON
|
||||||
|
|
||||||
|
IfStatement
|
||||||
|
<- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
|
||||||
|
/ IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
|
||||||
|
|
||||||
|
LabeledStatement <- BlockLabel? (Block / LoopStatement)
|
||||||
|
|
||||||
|
LoopStatement <- ForStatement / WhileStatement
|
||||||
|
|
||||||
|
ForStatement
|
||||||
|
<- ForPrefix BlockExpr ( KEYWORD_else Statement )?
|
||||||
|
/ ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
|
||||||
|
|
||||||
|
WhileStatement
|
||||||
|
<- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
|
||||||
|
/ WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
|
||||||
|
|
||||||
|
BlockExpr <- BlockLabel? Block
|
||||||
|
|
||||||
|
# *** Expression Level ***
|
||||||
|
AssignExpr <- Expr (AssignOp Expr)?
|
||||||
|
|
||||||
|
Expr <- BoolOrExpr
|
||||||
|
|
||||||
|
BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
|
||||||
|
|
||||||
|
BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
|
||||||
|
|
||||||
|
CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
|
||||||
|
|
||||||
|
BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
|
||||||
|
|
||||||
|
BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
|
||||||
|
|
||||||
|
AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
|
||||||
|
|
||||||
|
MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
|
||||||
|
|
||||||
|
PrefixExpr <- PrefixOp* PrimaryExpr
|
||||||
|
|
||||||
|
PrimaryExpr
|
||||||
|
<- IfExpr
|
||||||
|
/ KEYWORD_break BreakLabel? Expr?
|
||||||
|
/ KEYWORD_continue BreakLabel?
|
||||||
|
/ KEYWORD_return Expr?
|
||||||
|
/ BlockLabel? LoopExpr
|
||||||
|
/ Block
|
||||||
|
/ SuffixExpr
|
||||||
|
|
||||||
|
IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
|
||||||
|
|
||||||
|
Block <- LBRACE Statement* RBRACE
|
||||||
|
|
||||||
|
LoopExpr <- ForExpr / WhileExpr
|
||||||
|
|
||||||
|
ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?
|
||||||
|
|
||||||
|
WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
|
||||||
|
|
||||||
|
SuffixExpr
|
||||||
|
<- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
|
||||||
|
|
||||||
|
PrimaryTypeExpr
|
||||||
|
<- BUILTINIDENTIFIER FnCallArguments
|
||||||
|
/ CHAR_LITERAL
|
||||||
|
/ DOT IDENTIFIER
|
||||||
|
/ FLOAT
|
||||||
|
/ Fn
|
||||||
|
/ GroupedExpr
|
||||||
|
/ IDENTIFIER
|
||||||
|
/ INTEGER
|
||||||
|
/ KEYWORD_false
|
||||||
|
/ KEYWORD_nil
|
||||||
|
/ KEYWORD_true
|
||||||
|
/ STRINGLITERAL
|
||||||
|
|
||||||
|
GroupedExpr <- LPAREN Expr RPAREN
|
||||||
|
|
||||||
|
# *** Helper grammar ***
|
||||||
|
BreakLabel <- COLON IDENTIFIER
|
||||||
|
|
||||||
|
BlockLabel <- IDENTIFIER COLON
|
||||||
|
|
||||||
|
WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
|
||||||
|
|
||||||
|
# Control flow prefixes
|
||||||
|
IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
|
||||||
|
|
||||||
|
WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
|
||||||
|
|
||||||
|
ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
|
||||||
|
|
||||||
|
# Payloads
|
||||||
|
Payload <- PIPE IDENTIFIER PIPE
|
||||||
|
|
||||||
|
PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
|
||||||
|
|
||||||
|
PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
|
||||||
|
|
||||||
|
# Operators
|
||||||
|
AssignOp
|
||||||
|
<- ASTERISKEQUAL
|
||||||
|
/ PERCENTEQUAL
|
||||||
|
/ PLUSEQUAL
|
||||||
|
/ MINUSEQUAL
|
||||||
|
/ AMPERSANDEQUAL
|
||||||
|
/ CARETEQUAL
|
||||||
|
/ PIPEEQUAL
|
||||||
|
/ ASTERISKPERCENTEQUAL
|
||||||
|
/ EQUAL
|
||||||
|
|
||||||
|
CompareOp
|
||||||
|
<- EQUALEQUAL
|
||||||
|
/ EXCLAMATIONMARKEQUAL
|
||||||
|
/ LARROW
|
||||||
|
/ RARROW
|
||||||
|
/ LARROWEQUAL
|
||||||
|
/ RARROWEQUAL
|
||||||
|
|
||||||
|
BitwiseOp
|
||||||
|
<- AMPERSAND
|
||||||
|
/ CARET
|
||||||
|
/ PIPE
|
||||||
|
|
||||||
|
BitShiftOp
|
||||||
|
<- LARROW2
|
||||||
|
/ RARROW2
|
||||||
|
|
||||||
|
AdditionOp
|
||||||
|
<- PLUS
|
||||||
|
/ MINUS
|
||||||
|
/ PLUS2
|
||||||
|
|
||||||
|
MultiplyOp
|
||||||
|
<- ASTERISK
|
||||||
|
/ SLASH
|
||||||
|
/ PERCENT
|
||||||
|
/ ASTERISK2
|
||||||
|
/ ASTERISKPERCENT
|
||||||
|
|
||||||
|
PrefixOp
|
||||||
|
<- EXCLAMATIONMARK
|
||||||
|
/ MINUS
|
||||||
|
/ AMPERSAND
|
||||||
|
|
||||||
|
SuffixOp
|
||||||
|
<- LBRACKET Expr RBRACKET
|
||||||
|
/ DOT IDENTIFIER
|
||||||
|
|
||||||
|
FnCallArguments <- LPAREN ExprList RPAREN
|
||||||
|
|
||||||
|
# Lists
|
||||||
|
ExprList <- (Expr COMMA)* Expr?
|
||||||
|
|
||||||
|
ParamDeclList <- (IDENTIFIER COMMA)* IDENTIFIER?
|
||||||
|
|
||||||
|
# *** Tokens ***
|
||||||
|
INTEGER
|
||||||
|
<- "0b" bin_int skip
|
||||||
|
/ "0o" oct_int skip
|
||||||
|
/ "0x" hex_int skip
|
||||||
|
/ dec_int skip
|
||||||
|
|
||||||
|
IDENTIFIER
|
||||||
|
<- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
|
||||||
|
/ "@\"" string_char* "\"" skip
|
||||||
|
BUILTINIDENTIFIER <- "@"[A-Za-z_][A-Za-z0-9_]* skip
|
||||||
|
|
||||||
|
CHAR_LITERAL <- "'" char_char "'" skip
|
||||||
|
FLOAT
|
||||||
|
<- "0x" hex_int "." hex_int ([pP] [-+]? dec_int)? skip
|
||||||
|
/ dec_int "." dec_int ([eE] [-+]? dec_int)? skip
|
||||||
|
/ "0x" hex_int "."? [pP] [-+]? dec_int skip
|
||||||
|
/ dec_int "."? [eE] [-+]? dec_int skip
|
||||||
|
|
||||||
|
STRINGLITERAL
|
||||||
|
<- STRINGLITERALSINGLE
|
||||||
|
/ (line_string skip)+
|
||||||
|
STRINGLITERALSINGLE <- "\"" string_char* "\"" skip
|
||||||
|
|
||||||
|
eof <- !.
|
||||||
|
bin <- [01]
|
||||||
|
bin_ <- '_'? bin
|
||||||
|
oct <- [0-7]
|
||||||
|
oct_ <- '_'? oct
|
||||||
|
hex <- [0-9a-fA-F]
|
||||||
|
hex_ <- '_'? hex
|
||||||
|
dec <- [0-9]
|
||||||
|
dec_ <- '_'? dec
|
||||||
|
|
||||||
|
bin_int <- bin bin_*
|
||||||
|
oct_int <- oct oct_*
|
||||||
|
dec_int <- dec dec_*
|
||||||
|
hex_int <- hex hex_*
|
||||||
|
|
||||||
|
ox80_oxBF <- [\200-\277]
|
||||||
|
oxF4 <- '\364'
|
||||||
|
ox80_ox8F <- [\200-\217]
|
||||||
|
oxF1_oxF3 <- [\361-\363]
|
||||||
|
oxF0 <- '\360'
|
||||||
|
ox90_0xBF <- [\220-\277]
|
||||||
|
oxEE_oxEF <- [\356-\357]
|
||||||
|
oxED <- '\355'
|
||||||
|
ox80_ox9F <- [\200-\237]
|
||||||
|
oxE1_oxEC <- [\341-\354]
|
||||||
|
oxE0 <- '\340'
|
||||||
|
oxA0_oxBF <- [\240-\277]
|
||||||
|
oxC2_oxDF <- [\302-\337]
|
||||||
|
|
||||||
|
# From https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/
|
||||||
|
|
||||||
|
mb_utf8_literal <-
|
||||||
|
oxF4 ox80_ox8F ox80_oxBF ox80_oxBF
|
||||||
|
/ oxF1_oxF3 ox80_oxBF ox80_oxBF ox80_oxBF
|
||||||
|
/ oxF0 ox90_0xBF ox80_oxBF ox80_oxBF
|
||||||
|
/ oxEE_oxEF ox80_oxBF ox80_oxBF
|
||||||
|
/ oxED ox80_ox9F ox80_oxBF
|
||||||
|
/ oxE1_oxEC ox80_oxBF ox80_oxBF
|
||||||
|
/ oxE0 oxA0_oxBF ox80_oxBF
|
||||||
|
/ oxC2_oxDF ox80_oxBF
|
||||||
|
|
||||||
|
ascii_char_not_nl_slash_squote <- [\000-\011\013-\046-\050-\133\135-\177]
|
||||||
|
|
||||||
|
char_escape
|
||||||
|
<- "\\x" hex hex
|
||||||
|
/ "\\u{" hex+ "}"
|
||||||
|
/ "\\" [nr\\t'"]
|
||||||
|
char_char
|
||||||
|
<- mb_utf8_literal
|
||||||
|
/ char_escape
|
||||||
|
/ ascii_char_not_nl_slash_squote
|
||||||
|
|
||||||
|
string_char
|
||||||
|
<- char_escape
|
||||||
|
/ [^\\"\n]
|
||||||
|
|
||||||
|
line_comment <- '//' ![!/][^\n]* / '////' [^\n]*
|
||||||
|
line_string <- ("\\\\" [^\n]* [ \n]*)+
|
||||||
|
skip <- ([ \n] / line_comment)*
|
||||||
|
|
||||||
|
|
||||||
|
AMPERSAND <- '&' ![=] skip
|
||||||
|
AMPERSANDEQUAL <- '&=' skip
|
||||||
|
ASTERISK <- '*' ![*%=] skip
|
||||||
|
ASTERISK2 <- '**' skip
|
||||||
|
ASTERISKEQUAL <- '*=' skip
|
||||||
|
ASTERISKPERCENT <- '*%' ![=] skip
|
||||||
|
ASTERISKPERCENTEQUAL <- '*%=' skip
|
||||||
|
CARET <- '^' ![=] skip
|
||||||
|
CARETEQUAL <- '^=' skip
|
||||||
|
COLON <- ':' skip
|
||||||
|
COMMA <- ',' skip
|
||||||
|
DOT <- '.' ![*.?] skip
|
||||||
|
EQUAL <- '=' ![>=] skip
|
||||||
|
EQUALEQUAL <- '==' skip
|
||||||
|
EXCLAMATIONMARK <- '!' ![=] skip
|
||||||
|
EXCLAMATIONMARKEQUAL <- '!=' skip
|
||||||
|
LARROW <- '<' ![<=] skip
|
||||||
|
LARROW2 <- '<<' skip
|
||||||
|
LARROWEQUAL <- '<=' skip
|
||||||
|
LBRACE <- '{' skip
|
||||||
|
LBRACKET <- '[' skip
|
||||||
|
LPAREN <- '(' skip
|
||||||
|
MINUS <- '-' ![=>] skip
|
||||||
|
MINUSEQUAL <- '-=' skip
|
||||||
|
PERCENT <- '%' ![=] skip
|
||||||
|
PERCENTEQUAL <- '%=' skip
|
||||||
|
PIPE <- '|' ![|=] skip
|
||||||
|
PIPEEQUAL <- '|=' skip
|
||||||
|
PLUS <- '+' ![+=] skip
|
||||||
|
PLUS2 <- '++' skip
|
||||||
|
PLUSEQUAL <- '+=' skip
|
||||||
|
RARROW <- '>' skip
|
||||||
|
RARROW2 <- '>>' skip
|
||||||
|
RARROWEQUAL <- '>=' skip
|
||||||
|
RBRACE <- '}' skip
|
||||||
|
RBRACKET <- ']' skip
|
||||||
|
RPAREN <- ')' skip
|
||||||
|
SEMICOLON <- ';' skip
|
||||||
|
SLASH <- '/' ![=] skip
|
||||||
|
|
||||||
|
end_of_word <- ![a-zA-Z0-9_] skip
|
||||||
|
KEYWORD_and <- 'and' end_of_word
|
||||||
|
KEYWORD_break <- 'break' end_of_word
|
||||||
|
KEYWORD_continue <- 'continue' end_of_word
|
||||||
|
KEYWORD_else <- 'else' end_of_word
|
||||||
|
KEYWORD_export <- 'export' end_of_word
|
||||||
|
KEYWORD_false <- 'false' end_of_word
|
||||||
|
KEYWORD_fn <- 'fn' end_of_word
|
||||||
|
KEYWORD_for <- 'for' end_of_word
|
||||||
|
KEYWORD_if <- 'if' end_of_word
|
||||||
|
KEYWORD_nil <- 'nil' end_of_word
|
||||||
|
KEYWORD_or <- 'or' end_of_word
|
||||||
|
KEYWORD_return <- 'return' end_of_word
|
||||||
|
KEYWORD_test <- 'test' end_of_word
|
||||||
|
KEYWORD_true <- 'true' end_of_word
|
||||||
|
KEYWORD_while <- 'while' end_of_word
|
||||||
|
|
||||||
|
keyword <- KEYWORD_and
|
||||||
|
/ KEYWORD_break
|
||||||
|
/ KEYWORD_continue / KEYWORD_else
|
||||||
|
/ KEYWORD_export
|
||||||
|
/ KEYWORD_false / KEYWORD_fn / KEYWORD_for / KEYWORD_if
|
||||||
|
/ KEYWORD_nil / KEYWORD_or
|
||||||
|
/ KEYWORD_return
|
||||||
|
/ KEYWORD_test / KEYWORD_true
|
||||||
|
/ KEYWORD_while
|
53
src/main.cpp
Normal file
53
src/main.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include <cpp-peglib/peglib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace peg;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// (2) Make a parser
|
||||||
|
parser parser(R"(
|
||||||
|
# Grammar for Calculator...
|
||||||
|
Additive <- Multitive '+' Additive / Multitive
|
||||||
|
Multitive <- Primary '*' Multitive / Primary
|
||||||
|
Primary <- '(' Additive ')' / Number
|
||||||
|
Number <- < [0-9]+ >
|
||||||
|
%whitespace <- [ \t]*
|
||||||
|
)");
|
||||||
|
|
||||||
|
assert(static_cast<bool>(parser) == true);
|
||||||
|
|
||||||
|
// (3) Setup actions
|
||||||
|
parser["Additive"] = [](const SemanticValues &vs) {
|
||||||
|
switch (vs.choice()) {
|
||||||
|
case 0: // "Multitive '+' Additive"
|
||||||
|
return any_cast<int>(vs[0]) + any_cast<int>(vs[1]);
|
||||||
|
default: // "Multitive"
|
||||||
|
return any_cast<int>(vs[0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["Multitive"] = [](const SemanticValues &vs) {
|
||||||
|
switch (vs.choice()) {
|
||||||
|
case 0: // "Primary '*' Multitive"
|
||||||
|
return any_cast<int>(vs[0]) * any_cast<int>(vs[1]);
|
||||||
|
default: // "Primary"
|
||||||
|
return any_cast<int>(vs[0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["Number"] = [](const SemanticValues &vs) {
|
||||||
|
return vs.token_to_number<int>();
|
||||||
|
};
|
||||||
|
|
||||||
|
// (4) Parse
|
||||||
|
parser.enable_packrat_parsing(); // Enable packrat parsing.
|
||||||
|
|
||||||
|
int val;
|
||||||
|
parser.parse(" (1 + 2) * 3 ", val);
|
||||||
|
|
||||||
|
assert(val == 9);
|
||||||
|
|
||||||
|
std::cout << "hello" << std::endl;
|
||||||
|
}
|
1
third_party/cpp-peglib
vendored
Submodule
1
third_party/cpp-peglib
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4109480a0cb2d6067c8b123b09da6e277a11599d
|
Loading…
x
Reference in New Issue
Block a user