mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-04 14:01:25 +12:00
Started the scanner.
This commit is contained in:
parent
bcbca461de
commit
8ae7b48188
5 changed files with 358 additions and 4 deletions
10
document.cpp
10
document.cpp
|
@ -1,6 +1,7 @@
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "scanner.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
|
@ -30,10 +31,11 @@ namespace YAML
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
std::ifstream fin(fileName.c_str());
|
std::ifstream fin(fileName.c_str());
|
||||||
Parser parser(fin);
|
Scanner scanner(fin);
|
||||||
if(!parser)
|
scanner.Scan();
|
||||||
return;
|
// if(!scanner)
|
||||||
|
// return;
|
||||||
|
|
||||||
m_pRoot = parser.ReadNextNode();
|
// m_pRoot = parser.ReadNextNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
275
scanner.cpp
Normal file
275
scanner.cpp
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
Scanner::Scanner(std::istream& in)
|
||||||
|
: INPUT(in), m_startedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0), m_column(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Scanner::~Scanner()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Misc. helpers
|
||||||
|
|
||||||
|
// GetChar
|
||||||
|
// . Extracts a character from the stream and updates our position
|
||||||
|
char Scanner::GetChar()
|
||||||
|
{
|
||||||
|
m_column++;
|
||||||
|
return INPUT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLineBreak
|
||||||
|
// . Eats with no checking
|
||||||
|
void Scanner::EatLineBreak()
|
||||||
|
{
|
||||||
|
m_column = 0;
|
||||||
|
INPUT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// EatDocumentStart
|
||||||
|
// . Eats with no checking
|
||||||
|
void Scanner::EatDocumentStart()
|
||||||
|
{
|
||||||
|
INPUT.get();
|
||||||
|
INPUT.get();
|
||||||
|
INPUT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// EatDocumentEnd
|
||||||
|
// . Eats with no checking
|
||||||
|
void Scanner::EatDocumentEnd()
|
||||||
|
{
|
||||||
|
INPUT.get();
|
||||||
|
INPUT.get();
|
||||||
|
INPUT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWhitespaceToBeEaten
|
||||||
|
// . We can eat whitespace if:
|
||||||
|
// 1. It's a space
|
||||||
|
// 2. It's a tab, and we're either:
|
||||||
|
// a. In the flow context
|
||||||
|
// b. In the block context but not where a simple key could be allowed
|
||||||
|
// (i.e., not at the beginning of a line, or following '-', '?', or ':')
|
||||||
|
bool Scanner::IsWhitespaceToBeEaten()
|
||||||
|
{
|
||||||
|
char ch = INPUT.peek();
|
||||||
|
|
||||||
|
if(ch == ' ')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsLineBreak
|
||||||
|
bool Scanner::IsLineBreak()
|
||||||
|
{
|
||||||
|
char ch = INPUT.peek();
|
||||||
|
return ch == '\n'; // TODO: More types of line breaks
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBlank
|
||||||
|
bool Scanner::IsBlank()
|
||||||
|
{
|
||||||
|
char ch = INPUT.peek();
|
||||||
|
return IsLineBreak() || ch == ' ' || ch == '\t' || ch == EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDocumentStart
|
||||||
|
bool Scanner::IsDocumentStart()
|
||||||
|
{
|
||||||
|
// needs to be at the start of a new line
|
||||||
|
if(m_column != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// then needs '---'
|
||||||
|
for(int i=0;i<3;i++) {
|
||||||
|
if(INPUT.peek() != '-') {
|
||||||
|
// first put 'em back
|
||||||
|
for(int j=0;j<i;j++)
|
||||||
|
INPUT.putback('-');
|
||||||
|
|
||||||
|
// and return
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
INPUT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// then needs a blank character (or eof)
|
||||||
|
if(!IsBlank()) {
|
||||||
|
// put 'em back
|
||||||
|
for(int i=0;i<3;i++)
|
||||||
|
INPUT.putback('-');
|
||||||
|
|
||||||
|
// and return
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, put 'em back and go
|
||||||
|
for(int i=0;i<3;i++)
|
||||||
|
INPUT.putback('-');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDocumentEnd
|
||||||
|
bool Scanner::IsDocumentEnd()
|
||||||
|
{
|
||||||
|
// needs to be at the start of a new line
|
||||||
|
if(m_column != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// then needs '...'
|
||||||
|
for(int i=0;i<3;i++) {
|
||||||
|
if(INPUT.peek() != '.') {
|
||||||
|
// first put 'em back
|
||||||
|
for(int j=0;j<i;j++)
|
||||||
|
INPUT.putback('.');
|
||||||
|
|
||||||
|
// and return
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
INPUT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// then needs a blank character (or eof)
|
||||||
|
if(!IsBlank()) {
|
||||||
|
// put 'em back
|
||||||
|
for(int i=0;i<3;i++)
|
||||||
|
INPUT.putback('.');
|
||||||
|
|
||||||
|
// and return
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, put 'em back and go
|
||||||
|
for(int i=0;i<3;i++)
|
||||||
|
INPUT.putback('-');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Specialization for scanning specific tokens
|
||||||
|
|
||||||
|
// StreamStartToken
|
||||||
|
template <> StreamStartToken *Scanner::ScanToken(StreamStartToken *pToken)
|
||||||
|
{
|
||||||
|
m_startedStream = true;
|
||||||
|
m_simpleKeyAllowed = true;
|
||||||
|
m_indents.push(-1);
|
||||||
|
|
||||||
|
return pToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// StreamEndToken
|
||||||
|
template <> StreamEndToken *Scanner::ScanToken(StreamEndToken *pToken)
|
||||||
|
{
|
||||||
|
// force newline
|
||||||
|
if(m_column > 0)
|
||||||
|
m_column = 0;
|
||||||
|
|
||||||
|
// TODO: unroll indentation
|
||||||
|
// TODO: "reset simple keys"
|
||||||
|
|
||||||
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
|
return pToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocumentStartToken
|
||||||
|
template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken)
|
||||||
|
{
|
||||||
|
// TODO: unroll indentation
|
||||||
|
// TODO: reset simple keys
|
||||||
|
|
||||||
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
|
// eat it
|
||||||
|
EatDocumentStart();
|
||||||
|
|
||||||
|
return pToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocumentEndToken
|
||||||
|
template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken)
|
||||||
|
{
|
||||||
|
// TODO: unroll indentation
|
||||||
|
// TODO: reset simple keys
|
||||||
|
|
||||||
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
|
// eat it
|
||||||
|
EatDocumentEnd();
|
||||||
|
|
||||||
|
return pToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// The main scanning function
|
||||||
|
|
||||||
|
Token *Scanner::ScanNextToken()
|
||||||
|
{
|
||||||
|
if(!m_startedStream)
|
||||||
|
return ScanToken(new StreamStartToken);
|
||||||
|
|
||||||
|
ScanToNextToken();
|
||||||
|
// TODO: remove "obsolete potential simple keys"
|
||||||
|
// TODO: unroll indent
|
||||||
|
|
||||||
|
if(INPUT.peek() == EOF)
|
||||||
|
return ScanToken(new StreamEndToken);
|
||||||
|
|
||||||
|
if(IsDocumentStart())
|
||||||
|
return ScanToken(new DocumentStartToken);
|
||||||
|
|
||||||
|
if(IsDocumentEnd())
|
||||||
|
return ScanToken(new DocumentEndToken);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScanToNextToken
|
||||||
|
// . Eats input until we reach the next token-like thing.
|
||||||
|
void Scanner::ScanToNextToken()
|
||||||
|
{
|
||||||
|
while(1) {
|
||||||
|
// first eat whitespace
|
||||||
|
while(IsWhitespaceToBeEaten())
|
||||||
|
INPUT.get();
|
||||||
|
|
||||||
|
// then eat a comment
|
||||||
|
if(INPUT.peek() == Keys::Comment) {
|
||||||
|
// eat until line break
|
||||||
|
while(INPUT && !IsLineBreak())
|
||||||
|
INPUT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's NOT a line break, then we're done!
|
||||||
|
if(!IsLineBreak())
|
||||||
|
break;
|
||||||
|
|
||||||
|
// otherwise, let's eat the line break and keep going
|
||||||
|
EatLineBreak();
|
||||||
|
|
||||||
|
// new line - we may be able to accept a simple key now
|
||||||
|
if(m_flowLevel == 0)
|
||||||
|
m_simpleKeyAllowed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// temporary function for testing
|
||||||
|
void Scanner::Scan()
|
||||||
|
{
|
||||||
|
while(Token *pToken = ScanNextToken())
|
||||||
|
delete pToken;
|
||||||
|
}
|
||||||
|
}
|
55
scanner.h
Normal file
55
scanner.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ios>
|
||||||
|
#include <string>
|
||||||
|
#include <queue>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
class Token;
|
||||||
|
|
||||||
|
namespace Keys
|
||||||
|
{
|
||||||
|
const char Comment = '#';
|
||||||
|
}
|
||||||
|
|
||||||
|
class Scanner
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Scanner(std::istream& in);
|
||||||
|
~Scanner();
|
||||||
|
|
||||||
|
Token *ScanNextToken();
|
||||||
|
void ScanToNextToken();
|
||||||
|
|
||||||
|
void Scan();
|
||||||
|
|
||||||
|
private:
|
||||||
|
char GetChar();
|
||||||
|
void EatLineBreak();
|
||||||
|
void EatDocumentStart();
|
||||||
|
void EatDocumentEnd();
|
||||||
|
|
||||||
|
bool IsWhitespaceToBeEaten();
|
||||||
|
bool IsLineBreak();
|
||||||
|
bool IsBlank();
|
||||||
|
bool IsDocumentStart();
|
||||||
|
bool IsDocumentEnd();
|
||||||
|
template <typename T> T *ScanToken(T *pToken);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// the stream
|
||||||
|
std::istream& INPUT;
|
||||||
|
int m_column;
|
||||||
|
|
||||||
|
// the output (tokens)
|
||||||
|
std::queue <Token *> m_tokens;
|
||||||
|
|
||||||
|
// state info
|
||||||
|
bool m_startedStream;
|
||||||
|
bool m_simpleKeyAllowed;
|
||||||
|
int m_flowLevel; // number of unclosed '[' and '{' indicators
|
||||||
|
std::stack <int> m_indents;
|
||||||
|
};
|
||||||
|
}
|
10
token.h
Normal file
10
token.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
class Token {};
|
||||||
|
class StreamStartToken: public Token {};
|
||||||
|
class StreamEndToken: public Token {};
|
||||||
|
class DocumentStartToken: public Token {};
|
||||||
|
class DocumentEndToken: public Token {};
|
||||||
|
}
|
|
@ -189,6 +189,10 @@
|
||||||
RelativePath=".\scalar.cpp"
|
RelativePath=".\scalar.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\scanner.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\sequence.cpp"
|
RelativePath=".\sequence.cpp"
|
||||||
>
|
>
|
||||||
|
@ -223,10 +227,18 @@
|
||||||
RelativePath=".\scalar.h"
|
RelativePath=".\scalar.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\scanner.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\sequence.h"
|
RelativePath=".\sequence.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\token.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Resource Files"
|
Name="Resource Files"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue