-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Decided to introduce a new class for better functional encapsulation and clear distribution of duties. First step is to handle comments in the preprocessor since that's where they are actually stripped out which results in some slightly different behaviour of tokenisation (added tests to capture this). On the road to #13
- Loading branch information
Showing
18 changed files
with
282 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,27 @@ | ||
#pragma once | ||
#include "src/preprocessor/preprocessor.h" | ||
#include "src/lexer/token.h" | ||
#include "src/lexer/lexical_error.h" | ||
#include <string> | ||
#include <istream> | ||
|
||
class Lexer | ||
{ | ||
// Reference member, stream has no copy constructor and lexer doesn't care what kind of stream it is (file or string) | ||
std::istream &stream_; | ||
// Reference member, no need to copy the supplied preprocessor | ||
Preprocessor &preproc_; | ||
|
||
char current_char_; | ||
// Current position lexer has reached in the text | ||
// Used to give a position to errors | ||
int lineno_ = 1; | ||
int column_ = 1; | ||
PosChar current_char_; | ||
|
||
void error(Token, std::string); | ||
char peek(); | ||
void advance(); | ||
void skipWhitespace(); | ||
void skipComment(); | ||
Token _id(); | ||
Token number(); | ||
Token string(); | ||
Token makeToken(TokenType, std::string); | ||
|
||
public: | ||
Lexer(std::istream&); | ||
Lexer(Preprocessor&); | ||
Token nextToken(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
cc_library( | ||
name = "sqf-preprocessor", | ||
srcs = ["preprocessor.cpp"], | ||
hdrs = ["pos_char.h", "preprocessing_error.h", "preprocessor.h"], | ||
visibility = ["//src/lexer:__pkg__"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#pragma once | ||
|
||
// Character with an associated file position (may not correspond to physical position because of macros) | ||
struct PosChar | ||
{ | ||
char c = '\0'; | ||
int line = 1; | ||
int column = 1; | ||
|
||
// Convenience conversion operator | ||
operator char() const { return c; } | ||
}; | ||
|
||
// Using a typedef prevents naming clashes in global name space | ||
typedef PosChar PosChar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#pragma once | ||
#include <string> | ||
#include <stdexcept> | ||
|
||
class PreprocessingError : public std::runtime_error | ||
{ | ||
public: | ||
PreprocessingError(int line, int col, std::string msg) : std::runtime_error(std::to_string(line) + ":" + std::to_string(col) + " PreprocessingError: " + msg) {} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#include "src/preprocessor/preprocessor.h" | ||
#include <string> | ||
#include <istream> | ||
#include <algorithm> | ||
#include <cctype> | ||
|
||
Preprocessor::Preprocessor(std::istream &to_read) : stream_(to_read) | ||
{ | ||
// Immediately read in the first character | ||
advance(); | ||
} | ||
|
||
void Preprocessor::error(PosChar p, std::string msg) | ||
{ | ||
throw PreprocessingError(p.line, p.column, msg); | ||
} | ||
|
||
void Preprocessor::advance() | ||
{ | ||
// Increment the line whenever a newline is passed | ||
if (current_char_ == '\n') | ||
{ | ||
lineno_++; | ||
column_ = 0; | ||
line_start_ = true; | ||
} | ||
else if (line_start_ && !std::isspace(current_char_)) | ||
{ | ||
line_start_ = false; | ||
} | ||
|
||
stream_.get(current_char_); | ||
|
||
// When end of stream is reached return EOF character | ||
if (stream_.eof()) | ||
{ | ||
current_char_ = '\0'; | ||
} | ||
else | ||
{ | ||
column_++; | ||
} | ||
} | ||
|
||
void Preprocessor::skipComment() | ||
{ | ||
if (stream_.peek() == '/') | ||
{ | ||
// Intentionally don't skip the newline at the end (acts as a delimiter) | ||
while (current_char_ != '\0' && current_char_ != '\n') | ||
{ | ||
advance(); | ||
} | ||
} | ||
else if (stream_.peek() == '*') | ||
{ | ||
while (current_char_ != '\0' && !(current_char_ == '*' && peek() == '/')) | ||
{ | ||
advance(); | ||
} | ||
|
||
// Skip past the block end: */ | ||
advance(); | ||
advance(); | ||
} | ||
} | ||
|
||
PosChar Preprocessor::get() | ||
{ | ||
// Comments are irrelevant (block and line) | ||
if (current_char_ == '/' && (stream_.peek() == '/' || stream_.peek() == '*')) | ||
{ | ||
skipComment(); | ||
} | ||
|
||
PosChar c; | ||
c.line = lineno_; | ||
c.column = column_; | ||
c.c = current_char_; | ||
|
||
// Remember to actually progress through the input | ||
advance(); | ||
|
||
return c; | ||
} | ||
|
||
// Preview the next character in order to differentiate tokens that start the same | ||
char Preprocessor::peek() | ||
{ | ||
return stream_.peek(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#pragma once | ||
#include "src/preprocessor/pos_char.h" | ||
#include "src/preprocessor/preprocessing_error.h" | ||
#include <string> | ||
#include <istream> | ||
|
||
class Preprocessor | ||
{ | ||
// Reference member for polymorphism | ||
std::istream &stream_; | ||
|
||
char current_char_ = '\0'; | ||
// Current physical position preprocessor has reached | ||
// Used to give a position to errors and macros | ||
int lineno_ = 1; | ||
int column_ = 1; | ||
|
||
// Preprocessor directives must appear at a line start (ignoring whitespace) | ||
bool line_start_ = true; | ||
|
||
void error(PosChar, std::string); | ||
void advance(); | ||
void skipComment(); | ||
|
||
public: | ||
Preprocessor(std::istream&); | ||
PosChar get(); | ||
char peek(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.