:- use_module(library(dcg/basics)).
:- set_prolog_flag(double_quotes, chars).
/*
Stroustroup, B. The C++ Programming Language 2nd Ed. 1993.
Appendix A: Grammar Summary (p. 614)
*/
% 1 or more whitespace characters, including newline.
ws --> blank, blanks.
% Because it just looks weird having a lot of quoted commas in a
% comma-separated list.
comma --> ",".
/* Symbols that are operators: */
% Equality
greater --> ">".
greater_or_equal --> ">=".
less --> "<".
less_or_equal --> "<=".
equal --> "==".
not_equal --> "!=".
% Bit shift
shift_left --> "<<".
shift_right --> ">>".
% Arithmetic
addition --> "+".
subtraction --> "-".
mulitplication --> "*".
division --> "/".
exponentiation --> "^".
modulo --> "%".
/*
r.17.1 Keywords
*/
class_name(N) --> identifier(N).
enum_name(N) --> identifier(N).
typedef_name(N) --> identifier(N).
keyword(K) --> blank, string(K).
% TODO: "Note that a typedef-name naming a class is also a class-name"
% (p. 615).
/*
r.17.2 Expressions
*/
expression([E|Exps]) --> blanks, assignment_expression([E|Exps]), blanks.
expression([E1, E2]) --> expression(E1),
blanks, comma, blanks,
assignment_expression(E2), blanks.
assignment_expression([E|Exps]) --> conditional_expression([E|Exps]).
assignment_expression([E1, Operator, E2]) --> unary_expression(E1),
assignment_operator(Operator),
assignment_expression(E2).
conditional_expression([E|Exps]) --> logical_or_expression([E|Exps]).
conditional_expression([E1, E2, E3]) --> logical_or_expression(E1),
expression(E2),
conditional_expression(E3).
% DCG rules given here for logical/inclusive and/or expressions from
% p. 615 are more literal than what's in the book.
logical_and_expression([E1, E2]) --> expression(E1), "&&", expression(E2).
logical_or_expression([E1, E2]) --> expression(E1), "||", expression(E2).
inclusive_or_expression([E1, E2]) --> expression(E1), "|", expression(E2).
inclusive_and_expression([E1, E2]) --> expression(E1), "&", expression(E2).
equality_expression([E|Exps]) --> relational_expression([E|Exps]).
equality_expression([E1, E2]) -->
equality_expression(E1), ("==" | "!="), relational_expression(E2).
relational_expression([E|Exps]) --> shift_expression([E|Exps]).
relational_expression([E1, E2]) -->
relational_expression(E1),
("<" | ">" | "<=" | ">=" ),
shift_expression.
shift_expression([E|Exps]) --> additive_expression([E|Exps]).
shift_expression([E1, E2]) -->
shift_expression(E1), ("<<" | ">>"), additive_expression(E2).
additive_expression([E|Exps]) --> multiplicative_expression([E|Exps]).
additive_expression([E1, E2]) -->
additive_expression(E1), ("+" | "-"), multiplicative_expression(E2).
multiplicative_expression([E|Exps]) --> pm_expression([E|Exps]).
multiplicative_expression([E1, E2]) -->
multiplicative_expression(E1), ("*" | "/" | "%"), pm_expression(E2).
% What the fudge is a "pm_expression"? (p. 616). The 'm' probably
% stands for "member".
pm_expression([E|Exps]) --> cast_expression([E|Exps]).
pm_expression([E1, E2]) -->
pm_expression(E1), (".*" | "->*"), cast_expression(E2).
cast_expression([E|Exps]) --> unary_expression([E|Exps]).
cast_expression([E1, E2]) --> type_name(E1), cast_expression(E2).
sizeof([E|Exps]) --> "sizeof", ws, unary_expression([E|Exps]).
sizeof([E|Exps]) -->
"sizeof", blanks, "(", type_name([E|Exps]), ")".
unary_expression([E|Exps]) --> postfix_expression([E|Exps]).
unary_expression([E|Exps]) --> ("++" | "--"), unary_expression([E|Exps]).
unary_expression([E|Exps]) --> "sizeof", unary_expression([E|Exps]).
unary_expression([E|Exps]) --> sizeof([E|Exps]).
unary_expression([E1, E2]) --> unary_operator(E1), cast_expression(E2).
unary_expression([E|Exps]) -->
( allocation_expression([E|Exps]) | deallocation_expression([E|Exps]) ).
unary_operator --> ("*" | "&" | "+" | "-" | "!" | "~").
allocation_expression_([E1,E2,E3]) -->
"new", ws, placement(E1), new_type_name(E2), new_initializer(E3).
allocation_expression_([E1,E2,E3]) -->"new", ws, placement(E1),
blanks, "(" blanks,
type_name(E2),
blanks, ")" blanks,
new_initializer(E3).
allocation_expression_([E1,E2]) -->
"new", ws, new_type_name(E1), new_initializer(E2).
allocation_expression_([E1,E2,E3]) --> "new", ws,
"(", type_name(E1), ")".
new_initializer(E2).
allocation_expression([E|Exps]) --> "::", allocation_expression_([E|Exps]).
allocation_expression([E|Exps]) --> allocation_expression_([E|Exps]).
placement([E|Exps]) --> blanks, "(", expression_list([E|Exps]), ")".
% TODO: new_declarator (was skipped).
new_initializer([E|Exps]) --> blanks, "(", initializer_list([E|Exps]), ")".
new_initializer([E|Exps]) --> blanks, "(", blanks, ")".
deallocation_expression_([E|Exps]) --> ws, "delete", ws, cast_expression([E|Exps]).
deallocation_expression_([E|Exps]) -->
ws, "delete", blanks, "[", blanks, "]", ws, cast_expression([E|Exps]).
deallocation_expression([E|Exps]) --> deallocation_expression_([E|Exps]).
deallocation_expression([E|Exps]) --> "::", deallocation_expression_([E|Exps]).
postfix_expression([E|Exps]) --> primary_expression([E|Exps]).
postfix_expression([E|Exps]) --> postfix_expression([E|Exps]), ("++" | "--").
postfix_expression([E1, E2]) -->
postfix_expression(E1), blanks, "[", expression(E2), "]".
postfix_expression([E1, E2]) -->
postfix_expression(E1), blanks, "(", expression_list(E2), ")".
postfix_expression([E1, E2]) -->
simple_type_name(E1), blanks, "(", expression_list(E2), ")".
postfix_expression([E1, E2]) --> postfix_expression(E1), ("." | "->"), name(E2).
expression_list([E|Exps]) --> assignment_expression([E|Exps]).
expression_list([E1, E2]) -->
expression_list(E1), blanks, comma, blanks, assignment_expression(E2).
primary_expression([]) --> "this".
primary_expression([E]) --> literal([E]).
primary_expression([E|Exps]) --> "::", identifier([E|Exps]).
primary_expression([E|Exps]) --> "::", operator_function_name([E|Exps]).
primary_expression([E|Exps]) --> "::", qualified_name([E|Exps]).
primary_expression([E|Exps]) -->
"(", blanks, expression([E|Exps]), blanks, ")".
primary_expression([E|Exps]) --> name([E|Exps]).
name([E|Exps]) --> identifier([E|Exps]).
name([E|Exps]) --> operator_function_name([E|Exps]).
name([E|Exps]) --> conversion_function_name([E|Exps]).
name([E|Exps]) --> "~", class_name([E|Exps]).
name([E|Exps]) --> qualified_name([E|Exps]).
qualified_name([E1, E2]) --> qualified_class_name(E1), "::", name(E2).
literal([X]) --> integer_constant([X]).
literal([X]) --> character_constant([X]).
literal([X]) --> floating_constant([X]).
literal([X]) --> string_literal([X]).
/*
r.17.3 Declarations (p. 618)
*/
declaration([E|Exps]) --> decl_specifiers([E|Exps]), blanks, ";".
declaration([E|Exps]) --> declarator_list([E|Exps]), blanks, ";".
declaration([E1, E2]) -->
decl_specifiers(E1), blanks, declarator_list(E2), blanks, ";".
declaration([E|Exps]) --> asm_declaration([E|Exps]).
declaration([E|Exps]) --> template_declaration([E|Exps]).
declaration([E|Exps]) --> linkage_declaration([E|Exps]).
auto --> "auto", ws.
register --> "register", ws.
static --> "static", ws.
extern --> "extern", ws.
friend --> "friend", ws.
typedef --> "typedef", ws.
inline --> "inline", ws.
virtual --> "virtual", ws.
const --> "const", ws.
volatile --> "volatile", ws.
decl_specifier([E|Exps]) --> storage_class_specifier([E|Exps]).
decl_specifier([E|Exps]) --> type_specifier([E|Exps]).
decl_specifier([E|Exps]) --> fct_specifier([E|Exps]).
decl_specifier(["friend"]) --> friend
decl_specifier(["typedef"]) --> typedef.
decl_specifiers([E|Exps]) --> decl_specifier([E|Exps]).
storage_class_specifier(["auto"]) --> auto.
storage_class_specifier(["register"]) --> register.
storage_class_specifier(["static"]) --> static
storage_class_specifier(["extern"]) --> extern
fct_specifier(["inline"]) --> inline.
fct_specifier(["virtual"]) --> virtual.
type_specifier([E|Exps]) --> simple_type_name([E|Exps]).
type_specifier([E|Exps]) --> class_specifier([E|Exps]).
type_specifier([E|Exps]) --> enum_specifier([E|Exps]).
type_specifier([E|Exps]) --> elaborated_type_specifier([E|Exps]).
type_specifier(["const"]) --> const.
type_specifier(["volatile"]) --> volatile.
simple_type_name --> [].