aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AST.cpp23
-rw-r--r--AST.h287
-rw-r--r--BaseTypes.h22
-rw-r--r--Parser.cpp180
-rw-r--r--Parser.h64
-rw-r--r--Scanner.cpp42
-rw-r--r--Scanner.h18
-rw-r--r--Token.h35
-rw-r--r--grammar.txt32
9 files changed, 675 insertions, 28 deletions
diff --git a/AST.cpp b/AST.cpp
new file mode 100644
index 00000000..ba50b7c6
--- /dev/null
+++ b/AST.cpp
@@ -0,0 +1,23 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity abstract syntax tree.
+ */
+
+#include <libsolidity/AST.h>
diff --git a/AST.h b/AST.h
new file mode 100644
index 00000000..f71b5b34
--- /dev/null
+++ b/AST.h
@@ -0,0 +1,287 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity abstract syntax tree.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <memory>
+
+#include <libsolidity/BaseTypes.h>
+#include <libsolidity/Token.h>
+
+namespace dev {
+namespace solidity {
+
+template <class T>
+using ptr = std::shared_ptr<T>;
+template <class T>
+using vecptr = std::vector<ptr<T>>;
+
+class VariableDeclaration;
+class StructDefinition;
+class FunctionDefinition;
+class TypeName;
+class Block;
+class Expression;
+
+class ASTNode
+{
+public:
+ explicit ASTNode(const Location& _location)
+ : m_location(_location)
+ {}
+private:
+ Location m_location;
+};
+
+class ContractDefinition : public ASTNode
+{
+public:
+ ContractDefinition(const Location& _location,
+ const std::string& _name,
+ const vecptr<StructDefinition>& _definedStructs,
+ const vecptr<VariableDeclaration>& _stateVariables,
+ const vecptr<FunctionDefinition>& _definedFunctions)
+ : ASTNode(_location),
+ m_name(_name),
+ m_definedStructs(_definedStructs),
+ m_stateVariables(_stateVariables),
+ m_definedFunctions(_definedFunctions)
+ {}
+
+private:
+ std::string m_name;
+ vecptr<StructDefinition> m_definedStructs;
+ vecptr<VariableDeclaration> m_stateVariables;
+ vecptr<FunctionDefinition> m_definedFunctions;
+};
+
+class StructDefinition : public ASTNode
+{
+private:
+ std::string m_name;
+ vecptr<VariableDeclaration> m_members;
+};
+
+class FunctionDefinition : public ASTNode
+{
+private:
+ std::string m_name;
+ vecptr<VariableDeclaration> m_arguments;
+ bool m_isDeclaredConst;
+ vecptr<VariableDeclaration> m_returns;
+ ptr<Block> m_body;
+};
+
+class VariableDeclaration : public ASTNode
+{
+public:
+ VariableDeclaration(const Location& _location,
+ const ptr<TypeName>& _type,
+ const std::string& _name)
+ : ASTNode(_location),
+ m_type(_type),
+ m_name(_name)
+ {}
+private:
+ ptr<TypeName> m_type; ///<s can be empty ("var")
+ std::string m_name;
+};
+
+/// types
+/// @{
+
+class TypeName : public ASTNode
+{
+public:
+ explicit TypeName(const Location& _location)
+ : ASTNode(_location)
+ {}
+};
+
+/// any pre-defined type that is not a mapping
+class ElementaryTypeName : public TypeName
+{
+public:
+ explicit ElementaryTypeName(const Location& _location, Token::Value _type)
+ : TypeName(_location), m_type(_type)
+ {}
+private:
+ Token::Value m_type;
+};
+
+class UserDefinedTypeName : public TypeName
+{
+public:
+ UserDefinedTypeName(const Location& _location, const std::string& _name)
+ : TypeName(_location), m_name(_name)
+ {}
+private:
+ std::string m_name;
+};
+
+class MappingTypeName : public TypeName
+{
+public:
+ explicit MappingTypeName(const Location& _location)
+ : TypeName(_location)
+ {}
+private:
+ ptr<ElementaryTypeName> m_keyType;
+ ptr<TypeName> m_valueType;
+};
+
+/// @}
+
+/// Statements
+/// @{
+
+class Statement : public ASTNode
+{
+};
+
+class Block : public Statement
+{
+private:
+ vecptr<Statement> m_statements;
+};
+
+class IfStatement : public Statement
+{
+
+private:
+ ptr<Expression> m_condition;
+ ptr<Statement> m_trueBody;
+ ptr<Statement> m_falseBody;
+};
+
+class BreakableStatement : public Statement
+{
+
+};
+
+class WhileStatement : public BreakableStatement
+{
+private:
+ ptr<Expression> m_condition;
+ ptr<Statement> m_body;
+};
+
+class Continue : public Statement
+{
+
+};
+
+class Break : public Statement
+{
+
+};
+
+class Return : public Statement
+{
+private:
+ ptr<Expression> m_expression;
+};
+
+class VariableAssignment : public Statement
+{
+private:
+ ptr<VariableDeclaration> m_variable;
+ Token::Value m_assigmentOperator;
+ ptr<Expression> m_rightHandSide; ///< can be missing
+};
+
+class Expression : public Statement
+{
+private:
+};
+
+/// @}
+
+/// Expressions
+/// @{
+
+class Assignment : public Expression
+{
+private:
+ ptr<Expression> m_leftHandSide;
+ Token::Value m_assigmentOperator;
+ ptr<Expression> m_rightHandSide;
+};
+
+class UnaryOperation : public Expression
+{
+private:
+ Token::Value m_operator;
+ ptr<Expression> m_subExpression;
+ bool isPrefix;
+};
+
+class BinaryOperation : public Expression
+{
+private:
+ ptr<Expression> m_left;
+ ptr<Expression> m_right;
+ Token::Value m_operator;
+};
+
+class FunctionCall : public Expression
+{
+private:
+ std::string m_functionName; // TODO only calls to fixed, named functions for now
+ vecptr<Expression> m_arguments;
+};
+
+class MemberAccess : public Expression
+{
+private:
+ ptr<Expression> m_expression;
+ std::string m_memberName;
+};
+
+class IndexAccess : public Expression
+{
+ ptr<Expression> m_base;
+ ptr<Expression> m_index;
+};
+
+class PrimaryExpression : public Expression
+{
+};
+
+class Identifier : public PrimaryExpression
+{
+private:
+ std::string m_name;
+};
+
+class Literal : public PrimaryExpression
+{
+private:
+ std::string m_value;
+};
+
+/// @}
+
+
+} }
diff --git a/BaseTypes.h b/BaseTypes.h
new file mode 100644
index 00000000..0cc7f853
--- /dev/null
+++ b/BaseTypes.h
@@ -0,0 +1,22 @@
+#pragma once
+
+
+namespace dev {
+namespace solidity {
+
+// Representation of an interval of source positions.
+struct Location {
+ Location(int b, int e) : beg_pos(b), end_pos(e) { }
+ Location() : beg_pos(0), end_pos(0) { }
+
+ bool IsValid() const {
+ return beg_pos >= 0 && end_pos >= beg_pos;
+ }
+
+ static Location invalid() { return Location(-1, -1); }
+
+ int beg_pos;
+ int end_pos;
+};
+
+} }
diff --git a/Parser.cpp b/Parser.cpp
new file mode 100644
index 00000000..09ea8604
--- /dev/null
+++ b/Parser.cpp
@@ -0,0 +1,180 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity parser.
+ */
+
+#include "libsolidity/BaseTypes.h"
+#include "libsolidity/Parser.h"
+#include "libsolidity/Scanner.h"
+
+namespace dev {
+namespace solidity {
+
+ptr<ASTNode> Parser::parse(Scanner& _scanner)
+{
+ m_scanner = &_scanner;
+
+ return parseContractDefinition();
+}
+
+
+/// AST node factory that also tracks the begin and end position of an AST node
+/// while it is being parsed
+class Parser::ASTNodeFactory
+{
+public:
+ ASTNodeFactory(const Parser& _parser)
+ : m_parser(_parser),
+ m_location(_parser.getPosition(), -1)
+ {}
+
+ void markEndPosition()
+ {
+ m_location.end_pos = m_parser.getEndPosition();
+ }
+
+ /// @todo: check that this actually uses perfect forwarding
+ template <class NodeType, typename... Args>
+ ptr<NodeType> createNode(Args&&... _args)
+ {
+ if (m_location.end_pos < 0) markEndPosition();
+ return std::make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
+ }
+
+private:
+ const Parser& m_parser;
+ Location m_location;
+};
+
+int Parser::getPosition() const
+{
+ return m_scanner->getCurrentLocation().beg_pos;
+}
+
+int Parser::getEndPosition() const
+{
+ return m_scanner->getCurrentLocation().end_pos;
+}
+
+
+ptr<ContractDefinition> Parser::parseContractDefinition()
+{
+ ASTNodeFactory nodeFactory(*this);
+
+ expectToken(Token::CONTRACT);
+ std::string name = expectIdentifier();
+ expectToken(Token::LBRACE);
+
+ vecptr<StructDefinition> structs;
+ vecptr<VariableDeclaration> stateVariables;
+ vecptr<FunctionDefinition> functions;
+ bool visibilityIsPublic = true;
+ while (true) {
+ Token::Value currentToken = m_scanner->getCurrentToken();
+ if (currentToken == Token::RBRACE) {
+ break;
+ } else if (currentToken == Token::PUBLIC || currentToken == Token::PRIVATE) {
+ visibilityIsPublic = (m_scanner->getCurrentToken() == Token::PUBLIC);
+ m_scanner->next();
+ expectToken(Token::COLON);
+ } else if (currentToken == Token::FUNCTION) {
+ functions.push_back(parseFunctionDefinition(visibilityIsPublic));
+ } else if (currentToken == Token::STRUCT) {
+ structs.push_back(parseStructDefinition());
+ expectToken(Token::SEMICOLON);
+ } else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING ||
+ Token::IsElementaryTypeName(currentToken)) {
+ stateVariables.push_back(parseVariableDeclaration());
+ expectToken(Token::SEMICOLON);
+ } else {
+ throwExpectationError("Function, variable or struct declaration expected.");
+ }
+ }
+ nodeFactory.markEndPosition();
+
+ m_scanner->next();
+ expectToken(Token::EOS);
+
+ return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions);
+}
+
+ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
+{
+ (void) _isPublic;
+ throwExpectationError("Function parsing is not yet implemented.");
+}
+
+ptr<StructDefinition> Parser::parseStructDefinition()
+{
+ throwExpectationError("Struct definition parsing is not yet implemented.");
+}
+
+ptr<VariableDeclaration> Parser::parseVariableDeclaration()
+{
+ ASTNodeFactory nodeFactory(*this);
+
+ ptr<TypeName> type;
+ Token::Value token = m_scanner->getCurrentToken();
+ if (Token::IsElementaryTypeName(token)) {
+ type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token);
+ m_scanner->next();
+ } else if (token == Token::VAR) {
+ type = ASTNodeFactory(*this).createNode<TypeName>();
+ m_scanner->next();
+ } else if (token == Token::MAPPING) {
+ // TODO
+ throwExpectationError("mappings are not yet implemented");
+ } else if (token == Token::IDENTIFIER) {
+ type = ASTNodeFactory(*this).createNode<UserDefinedTypeName>(m_scanner->getCurrentLiteral());
+ m_scanner->next();
+ } else {
+ throwExpectationError("Expected variable declaration");
+ }
+ nodeFactory.markEndPosition();
+ std::string name = expectIdentifier();
+ return nodeFactory.createNode<VariableDeclaration>(type, name);
+}
+
+void Parser::expectToken(Token::Value _value)
+{
+ if (m_scanner->getCurrentToken() != _value)
+ throwExpectationError(std::string("Expected token ") + std::string(Token::Name(_value)));
+ m_scanner->next();
+}
+
+std::string Parser::expectIdentifier()
+{
+ if (m_scanner->getCurrentToken() != Token::IDENTIFIER)
+ throwExpectationError("Expected identifier");
+
+ std::string literal = m_scanner->getCurrentLiteral();
+ m_scanner->next();
+ return literal;
+}
+
+void Parser::throwExpectationError(const std::string& _description)
+{
+ (void) _description;
+ /// @todo make a proper exception hierarchy
+ throw std::exception();//_description);
+}
+
+
+} }
diff --git a/Parser.h b/Parser.h
new file mode 100644
index 00000000..4a48dace
--- /dev/null
+++ b/Parser.h
@@ -0,0 +1,64 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity parser.
+ */
+
+#pragma once
+
+#include "libsolidity/AST.h"
+
+namespace dev {
+namespace solidity {
+
+class Scanner;
+
+class Parser
+{
+public:
+ ptr<ASTNode> parse(Scanner& _scanner);
+
+private:
+ class ASTNodeFactory;
+
+ /// Start position of the current token
+ int getPosition() const;
+ /// End position of the current token
+ int getEndPosition() const;
+
+ /// Parsing functions for the AST nodes
+ /// @{
+ ptr<ContractDefinition> parseContractDefinition();
+ ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
+ ptr<StructDefinition> parseStructDefinition();
+ ptr<VariableDeclaration> parseVariableDeclaration();
+ /// @}
+
+ /// Helper functions
+ /// @{
+ /// If current token value is not _value, throw exception otherwise advance token.
+ void expectToken(Token::Value _value);
+ std::string expectIdentifier();
+ void throwExpectationError(const std::string& _description);
+ /// @}
+
+ Scanner* m_scanner;
+};
+
+} }
diff --git a/Scanner.cpp b/Scanner.cpp
index 101b4a1a..a936e24f 100644
--- a/Scanner.cpp
+++ b/Scanner.cpp
@@ -82,16 +82,10 @@ void Scanner::reset(const CharStream& _source)
{
m_source = _source;
- // Initialize current_ to not refer to a literal.
- m_current_token.token = Token::ILLEGAL;
- m_current_token.literal.clear();
-
- m_hasLineTerminatorBeforeNext = true;
- m_hasMultilineCommentBeforeNext = false;
-
m_char = m_source.get();
skipWhitespace();
scanToken();
+ next();
}
@@ -466,7 +460,7 @@ Token::Value Scanner::scanString()
literal.Complete();
advance(); // consume quote
- return Token::STRING;
+ return Token::STRING_LITERAL;
}
@@ -551,13 +545,17 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
// Keyword Matcher
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
+ KEYWORD_GROUP('a') \
+ KEYWORD("address", Token::BREAK) \
KEYWORD_GROUP('b') \
KEYWORD("break", Token::BREAK) \
+ KEYWORD("bool", Token::BOOL) \
KEYWORD_GROUP('c') \
KEYWORD("case", Token::CASE) \
KEYWORD("catch", Token::CATCH) \
KEYWORD("const", Token::CONST) \
KEYWORD("continue", Token::CONTINUE) \
+ KEYWORD("contract", Token::CONTRACT) \
KEYWORD_GROUP('d') \
KEYWORD("debugger", Token::DEBUGGER) \
KEYWORD("default", Token::DEFAULT) \
@@ -571,31 +569,55 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
KEYWORD("finally", Token::FINALLY) \
KEYWORD("for", Token::FOR) \
KEYWORD("function", Token::FUNCTION) \
+ KEYWORD_GROUP('h') \
+ KEYWORD("hash", Token::HASH) \
+ KEYWORD("hash32", Token::HASH32) \
+ KEYWORD("hash64", Token::HASH64) \
+ KEYWORD("hash128", Token::HASH128) \
+ KEYWORD("hash256", Token::HASH256) \
KEYWORD_GROUP('i') \
KEYWORD("if", Token::IF) \
KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("in", Token::IN) \
KEYWORD("instanceof", Token::INSTANCEOF) \
+ KEYWORD("int", Token::INT) \
+ KEYWORD("int32", Token::INT32) \
+ KEYWORD("int64", Token::INT64) \
+ KEYWORD("int128", Token::INT128) \
+ KEYWORD("int256", Token::INT256) \
KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('l') \
+ KEYWORD_GROUP('m') \
KEYWORD_GROUP('n') \
+ KEYWORD("mapping", Token::MAPPING) \
KEYWORD("new", Token::NEW) \
KEYWORD("null", Token::NULL_LITERAL) \
KEYWORD_GROUP('p') \
KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("private", Token::PRIVATE) \
KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("public", Token::PUBLIC) \
KEYWORD_GROUP('r') \
+ KEYWORD("real", Token::REAL) \
KEYWORD("return", Token::RETURN) \
KEYWORD_GROUP('s') \
+ KEYWORD("string", Token::STRING_TYPE) \
+ KEYWORD("struct", Token::STRUCT) \
KEYWORD("switch", Token::SWITCH) \
KEYWORD_GROUP('t') \
+ KEYWORD("text", Token::TEXT) \
KEYWORD("this", Token::THIS) \
KEYWORD("throw", Token::THROW) \
KEYWORD("true", Token::TRUE_LITERAL) \
KEYWORD("try", Token::TRY) \
KEYWORD("typeof", Token::TYPEOF) \
+ KEYWORD_GROUP('u') \
+ KEYWORD("uint", Token::UINT) \
+ KEYWORD("uint32", Token::UINT32) \
+ KEYWORD("uint64", Token::UINT64) \
+ KEYWORD("uint128", Token::UINT128) \
+ KEYWORD("uint256", Token::UINT256) \
+ KEYWORD("ureal", Token::UREAL) \
KEYWORD_GROUP('v') \
KEYWORD("var", Token::VAR) \
KEYWORD("void", Token::VOID) \
diff --git a/Scanner.h b/Scanner.h
index 3cf52fbc..d2dcad29 100644
--- a/Scanner.h
+++ b/Scanner.h
@@ -47,6 +47,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libdevcore/CommonData.h>
+#include <libsolidity/BaseTypes.h>
#include <libsolidity/Token.h>
namespace dev {
@@ -111,21 +112,6 @@ public:
bool complete_;
};
- // Representation of an interval of source positions.
- struct Location {
- Location(int b, int e) : beg_pos(b), end_pos(e) { }
- Location() : beg_pos(0), end_pos(0) { }
-
- bool IsValid() const {
- return beg_pos >= 0 && end_pos >= beg_pos;
- }
-
- static Location invalid() { return Location(-1, -1); }
-
- int beg_pos;
- int end_pos;
- };
-
explicit Scanner(const CharStream& _source);
// Resets the scanner as if newly constructed with _input as input.
@@ -163,8 +149,6 @@ private:
std::string literal;
};
- static const int kCharacterLookaheadBufferSize = 1;
-
// Literal buffer support
inline void startNewLiteral() {
m_next_token.literal.clear();
diff --git a/Token.h b/Token.h
index 4f5ec194..7a39b989 100644
--- a/Token.h
+++ b/Token.h
@@ -152,6 +152,7 @@ namespace solidity {
K(CASE, "case", 0) \
K(CATCH, "catch", 0) \
K(CONTINUE, "continue", 0) \
+ K(CONTRACT, "contract", 0) \
K(DEBUGGER, "debugger", 0) \
K(DEFAULT, "default", 0) \
/* DELETE */ \
@@ -163,8 +164,12 @@ namespace solidity {
K(IF, "if", 0) \
/* IN */ \
/* INSTANCEOF */ \
+ K(MAPPING, "mapping", 0) \
K(NEW, "new", 0) \
+ K(PUBLIC, "public", 0) \
+ K(PRIVATE, "private", 0) \
K(RETURN, "return", 0) \
+ K(STRUCT, "struct", 0) \
K(SWITCH, "switch", 0) \
K(THIS, "this", 0) \
K(THROW, "throw", 0) \
@@ -175,12 +180,36 @@ namespace solidity {
K(WHILE, "while", 0) \
K(WITH, "with", 0) \
\
+ /* type keywords, keep them in this order, keep int as first keyword TODO more to be added */ \
+ K(INT, "int", 0) \
+ K(INT32, "int32", 0) \
+ K(INT64, "int64", 0) \
+ K(INT128, "int128", 0) \
+ K(INT256, "int256", 0) \
+ K(UINT, "uint", 0) \
+ K(UINT32, "uint32", 0) \
+ K(UINT64, "uint64", 0) \
+ K(UINT128, "uint128", 0) \
+ K(UINT256, "uint256", 0) \
+ K(HASH, "hash", 0) \
+ K(HASH32, "hash32", 0) \
+ K(HASH64, "hash64", 0) \
+ K(HASH128, "hash128", 0) \
+ K(HASH256, "hash256", 0) \
+ K(ADDRESS, "address", 0) \
+ K(BOOL, "bool", 0) \
+ K(STRING_TYPE, "string", 0) \
+ K(TEXT, "text", 0) \
+ K(REAL, "real", 0) \
+ K(UREAL, "ureal", 0) \
+ T(TYPES_END, NULL, 0) /* used as type enum end marker */ \
+ \
/* Literals (ECMA-262, section 7.8, page 16). */ \
K(NULL_LITERAL, "null", 0) \
K(TRUE_LITERAL, "true", 0) \
K(FALSE_LITERAL, "false", 0) \
T(NUMBER, NULL, 0) \
- T(STRING, NULL, 0) \
+ T(STRING_LITERAL, NULL, 0) \
\
/* Identifiers (not keywords or future reserved words). */ \
T(IDENTIFIER, NULL, 0) \
@@ -231,6 +260,10 @@ class Token {
return tok == IDENTIFIER;
}
+ static bool IsElementaryTypeName(Value tok) {
+ return INT <= tok && tok < TYPES_END;
+ }
+
static bool IsAssignmentOp(Value tok) {
return INIT_VAR <= tok && tok <= ASSIGN_MOD;
}
diff --git a/grammar.txt b/grammar.txt
new file mode 100644
index 00000000..aec02489
--- /dev/null
+++ b/grammar.txt
@@ -0,0 +1,32 @@
+ContractDefinition = 'contract' Identifier '{' ContractPart* '}'
+ContractPart = VariableDeclaration ';' | StructDefinition ';' |
+ FunctionDefinition ';' | 'public:' | 'private:'
+
+StructDefinition = 'struct' Identifier '{'
+ ( VariableDeclaration (';' VariableDeclaration)* )? '}
+
+FunctionDefinition = 'function' Identifier ArgumentList 'const'?
+ 'returns' ArgumentList Block
+ArgumentList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')'
+// semantic restriction: mappings and structs (recursively) containing mappings
+// are not allowed in argument lists
+VariableDeclaration = TypeName Identifier
+TypeName = PredefinedType | Identifier | MappingType
+MappingType = 'mapping' '(' SimplePredefinedType '=>' TypeName ')'
+
+Block = '{' Statement* '}'
+Statement = IfStatement | WhileStatement | Continue | Break | Return | VariableAssignment | Expression ';' | Block
+
+IfStatement = 'if' '(' Expression ')' Statement ( 'else' Statement )?
+WhileStatement = 'while' '(' Expression ')' Statement
+Continue = 'continue' ';'
+Break = 'break' ';'
+Return = 'return' Expression? ';'
+VariableAssignment = VariableDeclaration ( AssignmentOp Expression )? ';'
+
+Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | IndexAccess | MemberAccess | PrimaryExpression
+Assignment = Expression (AssignmentOp Expression)
+FunctionCall = Identifier '(' ( Expression ( ',' Expression )* ) ')'
+MemberAccess = Expression '.' Identifier
+IndexAccess = Expression '[' Expresison ']'
+PrimaryExpression = Identifier | NumberLiteral | StringLiteral | '(' Expression ')'