summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/lexer.cxx3
-rw-r--r--cli/lexer.hxx2
-rw-r--r--cli/parser.cxx136
-rw-r--r--cli/parser.hxx3
-rw-r--r--cli/token.hxx1
5 files changed, 141 insertions, 4 deletions
diff --git a/cli/lexer.cxx b/cli/lexer.cxx
index bf16ce5..02be745 100644
--- a/cli/lexer.cxx
+++ b/cli/lexer.cxx
@@ -22,6 +22,7 @@ lexer (istream& is, string const& id)
buf_ (0, 0, 0),
unget_ (false)
{
+ keyword_map_["source"] = token::k_source;
keyword_map_["include"] = token::k_include;
keyword_map_["namespace"] = token::k_namespace;
keyword_map_["class"] = token::k_class;
@@ -340,7 +341,7 @@ identifier (xchar c)
if (i != keyword_map_.end ())
{
- if (i->second == token::k_include)
+ if (i->second == token::k_include || i->second == token::k_source)
include_ = true;
return token (i->second, ln, cl);
diff --git a/cli/lexer.hxx b/cli/lexer.hxx
index 710090d..830860c 100644
--- a/cli/lexer.hxx
+++ b/cli/lexer.hxx
@@ -131,7 +131,7 @@ private:
keyword_map keyword_map_;
bool eos_;
- bool include_;
+ bool include_; // Literal in include or source.
bool valid_;
xchar buf_;
diff --git a/cli/parser.cxx b/cli/parser.cxx
index b10cb0e..ba20ab1 100644
--- a/cli/parser.cxx
+++ b/cli/parser.cxx
@@ -197,11 +197,17 @@ def_unit ()
// include-decl-seq
//
- while (t.keyword () == token::k_include)
+ for (token::keyword_type k (t.keyword ());
+ k == token::k_include || k == token::k_source;
+ k = t.keyword ())
{
try
{
- include_decl ();
+ if (k == token::k_include)
+ include_decl ();
+ else
+ source_decl ();
+
t = lexer_->next ();
}
catch (error const&)
@@ -219,6 +225,22 @@ def_unit ()
{
try
{
+ if (t.keyword () == token::k_source)
+ {
+ try
+ {
+ source_decl ();
+ t = lexer_->next ();
+ }
+ catch (error const&)
+ {
+ valid_ = false;
+ recover (t);
+ }
+
+ continue;
+ }
+
if (decl (t))
{
t = lexer_->next ();
@@ -239,6 +261,116 @@ def_unit ()
}
void parser::
+source_decl ()
+{
+ token t (lexer_->next ());
+
+ if (t.type () != token::t_cli_path_lit)
+ {
+ cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: "
+ << "expected cli path literal instead of " << t << endl;
+ throw error ();
+ }
+
+ string const& l (t.literal ());
+ bool q (l[0] == '"'); // Quote or braket include?
+
+ path f;
+ try
+ {
+ f = path (string (l, 1, l.size () - 2));
+ }
+ catch (const invalid_path& e)
+ {
+ cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: "
+ << "'" << e.path () << "' is not a valid filesystem path" << endl;
+ valid_ = false;
+ }
+
+ if (valid_)
+ {
+ path p;
+
+ // If this is a quote include, then include relative to the current
+ // file.
+ //
+ if (q)
+ {
+ p = path_->directory () / f;
+ p.normalize ();
+ }
+ // Otherwise search the include directories (-I).
+ //
+ else
+ {
+ struct stat s;
+ for (paths::const_iterator i (include_paths_.begin ());
+ i != include_paths_.end (); ++i)
+ {
+ p = *i / f;
+ p.normalize ();
+
+ // Check that the file exist without checking for permissions, etc.
+ //
+ if (stat (p.string ().c_str (), &s) == 0 && S_ISREG (s.st_mode))
+ break;
+
+ p.clear ();
+ }
+
+ if (p.empty ())
+ {
+ cerr << *path_ << ':' << t.line () << ':' << t.column () << ": "
+ << "error: file '" << f << "' not found in any of the "
+ << "include search directories (-I)" << endl;
+ valid_ = false;
+ }
+ }
+
+ if (valid_)
+ {
+ auto_restore<path const> new_path (path_, &p);
+
+ ifstream ifs (p.string ().c_str ());
+ if (ifs.is_open ())
+ {
+ ifs.exceptions (ifstream::failbit | ifstream::badbit);
+
+ try
+ {
+ lexer l (ifs, p.string ());
+ auto_restore<lexer> new_lexer (lexer_, &l);
+
+ def_unit ();
+
+ if (!l.valid ())
+ valid_ = false;
+ }
+ catch (std::ios_base::failure const&)
+ {
+ cerr << p << ": error: read failure" << endl;
+ valid_ = false;
+ }
+ }
+ else
+ {
+ cerr << p << ": error: unable to open in read mode" << endl;
+ valid_ = false;
+ }
+ }
+ }
+
+ t = lexer_->next ();
+
+ if (t.punctuation () != token::p_semi)
+ {
+ cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: "
+ << "expected ';' instead of " << t << endl;
+ throw error ();
+ }
+}
+
+void parser::
include_decl ()
{
token t (lexer_->next ());
diff --git a/cli/parser.hxx b/cli/parser.hxx
index 733921a..767b8da 100644
--- a/cli/parser.hxx
+++ b/cli/parser.hxx
@@ -38,6 +38,9 @@ private:
def_unit ();
void
+ source_decl ();
+
+ void
include_decl ();
bool
diff --git a/cli/token.hxx b/cli/token.hxx
index 22679d3..d04ee7a 100644
--- a/cli/token.hxx
+++ b/cli/token.hxx
@@ -43,6 +43,7 @@ public:
public:
enum keyword_type
{
+ k_source,
k_include,
k_namespace,
k_class,