2021-12-17 01:05:38 -05:00
# include "Parser.h"
2021-07-07 18:03:41 -04:00
2021-12-12 03:41:54 -05:00
# include <fstream>
# include <sstream>
# include <iostream>
2022-05-10 02:42:12 -04:00
# include <regex>
# include <utility>
2021-12-12 22:20:28 -05:00
# include <stdexcept>
2021-12-12 03:41:54 -05:00
2021-12-12 22:20:28 -05:00
# include "Environment.h"
2021-12-12 03:41:54 -05:00
namespace {
struct ParseGroup {
std : : string accept ;
2021-12-12 22:20:28 -05:00
operator std : : string ( ) const {
return accept ;
}
2021-12-13 00:05:31 -05:00
bool operator = = ( const std : : string & other ) const {
2021-12-12 22:20:28 -05:00
return accept = = other ;
}
2021-12-12 03:41:54 -05:00
} ;
struct Match {
std : : string accept ;
2021-12-17 01:05:38 -05:00
2021-12-13 14:04:12 -05:00
operator char ( ) const {
2021-12-17 01:05:38 -05:00
if ( accept . length ( ) = = 1 )
return accept [ 0 ] ;
else {
std : : cerr < < " Cannot demote Match " < < accept < < " to char " < < std : : endl ;
return ' \0 ' ;
}
2021-12-12 03:41:54 -05:00
}
2021-12-13 00:05:31 -05:00
bool operator = = ( const std : : string & other ) const {
2021-12-12 03:41:54 -05:00
return accept = = other ;
2021-05-16 12:59:18 -04:00
}
2021-12-12 03:41:54 -05:00
} ;
const ParseGroup NUMERIC = { " 1234567890 " } ;
const Match DECIMAL_DOT = { " . " } ;
2021-12-17 01:05:38 -05:00
const Match NEGATIVE = { " - " } ;
2021-12-13 14:04:12 -05:00
const ParseGroup ALPHA = { " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz " } ;
2021-12-12 03:41:54 -05:00
const Match ARRAY_OPEN = { " [ " } ;
const Match ARRAY_CLOSE = { " ] " } ;
const Match ARRAY_DELIM = { " , " } ;
const Match GROUP_OPEN = { " ( " } ;
const Match GROUP_CLOSE = { " ) " } ;
const Match QUOTE = { " \" " } ;
const Match COMMENT_BEGIN = { " // " } ;
const Match DIALOGUE_OPEN = { " <<- " } ;
const Match DIALOGUE_CLOSE = { " ->> " } ;
const Match BEGIN = { " BEGIN " } ;
const Match END = { " END " } ;
2021-12-17 01:05:38 -05:00
const ParseGroup SYMBOL = { ALPHA . accept + NUMERIC . accept + " _ " } ;
const Match SPECIAL_SYMBOLS [ ] = {
{ " + " } ,
{ " - " } ,
{ " * " } ,
{ " / " } ,
{ " =? " } ,
{ " >? " } ,
{ " <? " } ,
{ " <=? " } ,
{ " >=? " }
} ;
2021-12-12 03:41:54 -05:00
const ParseGroup WS = { " \t \v \f \r \n " } ;
const ParseGroup SEPARATOR = {
2021-12-12 22:20:28 -05:00
WS . accept +
char ( ARRAY_OPEN ) +
char ( ARRAY_CLOSE ) +
char ( GROUP_OPEN ) +
char ( GROUP_CLOSE ) +
char ( ARRAY_DELIM ) +
2021-12-17 01:05:38 -05:00
COMMENT_BEGIN . accept [ 0 ]
2021-12-12 03:41:54 -05:00
} ;
const Match NEWLINE = { " \n " } ;
const ParseGroup ESCAPED = { " \\ \" " } ;
2021-12-13 14:04:12 -05:00
const Match ESCAPE = { " \\ " } ;
// Dialogue mode matches
const Match MARKUP_OPEN = { " [ " } ;
const Match MARKUP_CLOSE = { " ] " } ;
const Match SPEAKER_OPEN = { " [ " } ;
const Match SPEAKER_CLOSE = { " ] " } ;
const Match MARKUP_TEXT_OPEN = { " { " } ;
const Match MARKUP_TEXT_CLOSE = { " } " } ;
const Match TEMPLATE_IND = { " $ " } ;
const Match TEMPLATE_OPEN = { " { " } ;
const Match TEMPLATE_CLOSE = { " } " } ;
const Match COMMAND_ESCAPE = { " *! " } ;
const ParseGroup DIALOGUE_ESCAPED_SINGLE = {
ESCAPE . accept +
char ( MARKUP_OPEN ) +
char ( MARKUP_CLOSE ) +
char ( MARKUP_TEXT_OPEN ) +
char ( MARKUP_TEXT_CLOSE ) +
// char(SPEAKER_OPEN) +
// char(SPEAKER_CLOSE) +
char ( TEMPLATE_IND )
// char(TEMPLATE_OPEN) +
// char(TEMPLATE_CLOSE)
} ;
2021-12-12 03:41:54 -05:00
std : : string read_file_to_string ( const std : : string & path ) {
std : : ifstream f ( path ) ;
2021-12-12 23:36:55 -05:00
{ // Some apps on Windows adds this signature in front of UTF-8 files when saving
char a , b , c ;
2021-12-13 14:04:12 -05:00
a = f . get ( ) ; b = f . get ( ) ; c = f . get ( ) ;
if ( a ! = ( char ) 0xEF | | b ! = ( char ) 0xBB | | c ! = ( char ) 0xBF )
2021-12-12 23:36:55 -05:00
f . seekg ( 0 ) ;
2021-12-13 14:04:12 -05:00
else
2021-12-12 23:36:55 -05:00
std : : cerr < < " Warning: Windows UTF-8 BOM skipped " < < std : : endl ;
}
2021-12-12 03:41:54 -05:00
std : : stringstream buffer ;
buffer < < f . rdbuf ( ) ;
return buffer . str ( ) ;
}
std : : vector < std : : string > split_string_by_lines ( const std : : string & str ) {
std : : vector < std : : string > lines ;
int pos = 0 ;
int prev = 0 ;
2021-12-12 22:20:28 -05:00
while ( ( pos = str . find ( NEWLINE , prev ) ) ! = std : : string : : npos ) {
2021-12-12 03:41:54 -05:00
lines . push_back ( str . substr ( prev , pos - prev ) ) ;
prev = pos + 1 ;
2021-05-16 12:59:18 -04:00
}
2021-12-12 03:41:54 -05:00
lines . push_back ( str . substr ( prev ) ) ;
return lines ;
}
inline bool IsNumeric ( const std : : string & str ) {
2021-12-17 01:05:38 -05:00
bool negative = str [ 0 ] = = NEGATIVE ;
2021-12-12 03:41:54 -05:00
bool had_dot = false ;
2021-12-17 01:05:38 -05:00
for ( auto & c : negative ? str . substr ( 1 ) : str ) {
2021-12-12 03:41:54 -05:00
if ( NUMERIC . accept . find ( c ) = = std : : string : : npos ) {
if ( c = = DECIMAL_DOT . accept [ 0 ] ) {
if ( had_dot )
return false ;
else
had_dot = true ;
}
else
return false ;
}
2021-05-19 17:02:57 -04:00
}
2021-12-17 01:05:38 -05:00
if ( had_dot + negative = = str . length ( ) )
return false ;
2021-12-12 03:41:54 -05:00
return true ;
}
2021-12-17 01:05:38 -05:00
inline bool ContainsOnlyWS ( const std : : string & s ) {
for ( auto & c : s ) {
if ( WS . accept . find ( c ) = = std : : string : : npos )
return false ;
2021-12-12 03:41:54 -05:00
}
2021-12-17 01:05:38 -05:00
return true ;
}
2021-12-13 14:04:12 -05:00
2021-12-12 03:41:54 -05:00
void SkipWS ( const std : : string & f , size_t & pos ) {
while ( WS . accept . find ( f [ pos ] ) ! = std : : string : : npos )
pos + + ;
2021-05-19 17:02:57 -04:00
}
2021-12-12 03:41:54 -05:00
void SkipToNextLine ( const std : : string & f , size_t & pos ) {
while ( f [ pos ] ! = NEWLINE . accept [ 0 ] )
pos + + ;
pos + + ;
2021-07-07 18:03:41 -04:00
}
2021-05-15 17:48:37 -04:00
2021-12-12 03:41:54 -05:00
void SkipComments ( const std : : string & f , size_t & pos ) {
SkipWS ( f , pos ) ;
while ( f . substr ( pos , 2 ) = = COMMENT_BEGIN . accept ) {
SkipToNextLine ( f , pos ) ;
SkipWS ( f , pos ) ;
}
}
2021-12-12 22:20:28 -05:00
void SkipOverFirstChar ( const std : : string & f , size_t & pos ) {
SkipWS ( f , pos ) ;
pos + + ;
}
2021-12-12 03:41:54 -05:00
std : : string GetToken ( const std : : string & f , size_t & pos ) {
SkipWS ( f , pos ) ;
auto start = pos ;
while ( + + pos ) {
if ( SEPARATOR . accept . find ( f [ pos ] ) ! = std : : string : : npos )
2021-07-07 18:03:41 -04:00
break ;
2021-12-17 01:05:38 -05:00
}
2021-12-12 03:41:54 -05:00
return f . substr ( start , pos - start ) ;
}
std : : string PeekToken ( const std : : string & f , size_t pos ) {
SkipWS ( f , pos ) ;
auto start = pos ;
while ( + + pos ) {
if ( SEPARATOR . accept . find ( f [ pos ] ) ! = std : : string : : npos )
2021-07-16 20:27:25 -04:00
break ;
2021-12-17 01:05:38 -05:00
}
2021-12-12 03:41:54 -05:00
return f . substr ( start , pos - start ) ;
}
2021-12-12 22:20:28 -05:00
bool IsLegalSymbolName ( const std : : string & token ) {
2021-12-17 01:05:38 -05:00
for ( const auto & x : SPECIAL_SYMBOLS ) {
if ( token = = x . accept )
return true ;
}
2021-12-12 03:41:54 -05:00
if ( ALPHA . accept . find ( token [ 0 ] ) = = std : : string : : npos )
return false ;
for ( auto & i : token )
if ( SYMBOL . accept . find ( i ) = = std : : string : : npos )
return false ;
return true ;
}
2021-12-17 01:05:38 -05:00
NVL : : Parse : : Object ParseExpression ( const std : : string & f , size_t & pos ) ;
NVL : : Parse : : Object ParseArray ( const std : : string & f , size_t & pos , int layer ) {
2021-12-12 22:20:28 -05:00
SkipComments ( f , pos ) ;
2021-12-12 03:41:54 -05:00
2021-12-17 01:05:38 -05:00
std : : vector < NVL : : Parse : : Object > array { } ;
2021-12-12 22:20:28 -05:00
array . push_back ( ParseExpression ( f , pos ) ) ;
while ( PeekToken ( f , pos ) [ 0 ] ! = ARRAY_CLOSE ) {
if ( PeekToken ( f , pos ) [ 0 ] = = ARRAY_DELIM )
SkipOverFirstChar ( f , pos ) ;
else
throw std : : runtime_error ( " Invalid array member " ) ;
array . push_back ( ParseExpression ( f , pos ) ) ;
2021-12-12 03:41:54 -05:00
}
2021-12-17 01:05:38 -05:00
return { NVL : : Parse : : Type : : Array , array } ;
2021-12-12 03:41:54 -05:00
}
2021-12-12 22:20:28 -05:00
std : : string ParseString ( const std : : string & f , size_t & pos ) {
SkipComments ( f , pos ) ;
2021-12-12 03:41:54 -05:00
std : : vector < int > discards { } ;
auto start = + + pos ; // skip opening quote
do {
2021-12-12 22:20:28 -05:00
if ( f [ pos ] = = QUOTE ) {
2021-07-07 18:03:41 -04:00
break ;
2021-05-14 20:44:09 -04:00
}
2021-12-12 22:20:28 -05:00
else if ( f [ pos ] = = ESCAPE ) {
2021-12-12 03:41:54 -05:00
if ( ESCAPED . accept . find ( f [ pos ] ) ! = std : : string : : npos ) {
discards . push_back ( pos + + ) ;
}
else
throw std : : runtime_error ( " Unrecognized escape sequence " ) ;
}
2021-12-12 22:20:28 -05:00
else if ( f [ pos ] = = NEWLINE ) {
2021-12-12 03:41:54 -05:00
throw std : : runtime_error ( " Unclosed String " ) ;
}
} while ( pos + + ) ;
auto str = f . substr ( start , pos + + - start ) ;
for ( int i = 0 ; i < discards . size ( ) ; i + + ) {
str . erase ( discards [ i ] - start - i , 1 ) ;
2021-07-07 18:03:41 -04:00
}
2021-12-12 03:41:54 -05:00
return str ;
2021-07-07 18:03:41 -04:00
}
2021-12-12 22:20:28 -05:00
unsigned GetProcedureArity ( const std : : string & key ) {
2021-12-17 01:05:38 -05:00
return NVL : : Environment : : ENVIRONMENT . get ( key ) . length ;
2021-12-12 22:20:28 -05:00
}
2021-05-14 23:17:55 -04:00
2021-12-17 01:05:38 -05:00
NVL : : Parse : : Command ParseCommand ( const std : : string & f , size_t & pos ) {
2021-12-12 22:20:28 -05:00
SkipComments ( f , pos ) ;
2021-07-07 18:03:41 -04:00
2021-12-12 03:41:54 -05:00
auto proc = GetToken ( f , pos ) ;
2021-12-12 22:20:28 -05:00
if ( ! IsLegalSymbolName ( proc ) ) throw std : : runtime_error ( " Illegal Procedure name " ) ;
2021-12-17 01:05:38 -05:00
NVL : : Parse : : Command c { NVL : : Parse : : Object { NVL : : Parse : : Type : : Symbol , proc } } ;
2021-12-12 22:20:28 -05:00
for ( int i = 0 ; i < GetProcedureArity ( proc ) ; i + + ) {
c . push_back ( ParseExpression ( f , pos ) ) ;
} ;
2021-12-12 23:29:53 -05:00
SkipComments ( f , pos ) ;
2021-12-12 22:20:28 -05:00
return c ;
}
2021-12-17 01:05:38 -05:00
NVL : : Parse : : Object ParseExpression ( const std : : string & f , size_t & pos ) {
2021-12-12 22:20:28 -05:00
SkipComments ( f , pos ) ;
auto t = PeekToken ( f , pos ) ;
if ( t [ 0 ] = = ARRAY_OPEN ) {
SkipOverFirstChar ( f , pos ) ;
auto c = ParseArray ( f , pos , 0 ) ;
if ( PeekToken ( f , pos ) [ 0 ] ! = ARRAY_CLOSE )
throw std : : runtime_error ( " Cannot match closing Array " ) ;
else
SkipOverFirstChar ( f , pos ) ;
return c ;
}
else if ( t [ 0 ] = = GROUP_OPEN ) {
SkipOverFirstChar ( f , pos ) ;
auto c = ParseCommand ( f , pos ) ;
if ( PeekToken ( f , pos ) [ 0 ] ! = GROUP_CLOSE )
throw std : : runtime_error ( " Cannot match closing subexpression " ) ;
else
SkipOverFirstChar ( f , pos ) ;
2021-12-17 01:05:38 -05:00
return NVL : : Parse : : Object { NVL : : Parse : : Type : : Subexpression , c } ;
2021-05-14 20:44:09 -04:00
}
2021-12-12 22:20:28 -05:00
else if ( t [ 0 ] = = GROUP_CLOSE )
throw std : : runtime_error ( " Cannot match closing subexpression, likely too few arguments " ) ;
else if ( t [ 0 ] = = QUOTE )
2021-12-17 01:05:38 -05:00
return { NVL : : Parse : : Type : : String , ParseString ( f , pos ) } ;
2021-12-12 22:20:28 -05:00
else if ( t [ 0 ] = = ARRAY_CLOSE )
throw std : : runtime_error ( " Cannot match closing array " ) ;
else {
auto token = GetToken ( f , pos ) ;
if ( IsNumeric ( token ) )
2021-12-17 01:05:38 -05:00
return { NVL : : Parse : : Type : : Number , std : : stof ( token ) } ;
2021-12-12 22:20:28 -05:00
else if ( IsLegalSymbolName ( token ) )
2021-12-17 01:05:38 -05:00
return { NVL : : Parse : : Type : : Symbol , token } ;
2021-12-12 22:20:28 -05:00
else
throw std : : runtime_error ( " Illegal symbol " ) ;
}
}
2021-12-12 03:41:54 -05:00
2022-05-10 02:42:12 -04:00
/*
* NVL Markup Parsetree
*
* * - Vec : 2 - Num : Markup begin
* | |
* | - Num : Markup end
* |
* - Vec : 2 - Str : T of Markup
* |
* OR
* |
* - Vec : 2 - Str : T of Markup
* |
* - Vec : Params
*/
NVL : : Parse : : Object MatchMarkup ( std : : string & s ) {
static const std : : regex typer ( R " ((?:^|[^ \\ ]) \ [([^ \ ]]+) \ ] \ s* \ {([^ \ }]+) \ }) " ) ; // G1 -> Specifiers, G2 -> Contents
static const std : : regex effect ( R " ( \ s*(?:([^, \ ( \ )]+?) \ s* \ ( \ s*([^ \ ( \ )]+?) \ s* \ )|([^, \ ( \ )]+?)) \ s*(?:, \ s*|$)) " ) ; // G1 & G2 -> Func, G3 -> Attr
static const std : : regex param ( R " (([^,]+?) \ s*(?:, \ s*|$)) " ) ; // Comma split of func args
std : : vector < NVL : : Parse : : Object > tags ;
std : : smatch tags_match ;
std : : smatch effects_match ;
std : : smatch params_match ;
std : : string reconstruction { } ;
size_t running_offset = 0 ; // to account for characters removed
bool has_markup { } ;
std : : string : : const_iterator tags_start ( s . cbegin ( ) ) ;
while ( std : : regex_search ( tags_start , s . cend ( ) , tags_match , typer ) ) {
has_markup = true ;
NVL : : Parse : : Object m { NVL : : Parse : : Type : : Array , std : : vector < NVL : : Parse : : Object > { } } ;
reconstruction . append ( tags_match . prefix ( ) . first , std : : next ( tags_match [ 0 ] . first , 1 ) ) ;
reconstruction . append ( tags_match [ 2 ] . first , tags_match [ 2 ] . second ) ;
running_offset + = tags_match [ 2 ] . first - std : : next ( tags_match [ 0 ] . first , 1 ) ;
NVL : : Parse : : Object range { NVL : : Parse : : Type : : Array , { std : : vector < NVL : : Parse : : Object > {
{ NVL : : Parse : : Type : : Number , static_cast < NVL : : Number > ( tags_match [ 2 ] . first - s . cbegin ( ) - running_offset ) } ,
{ NVL : : Parse : : Type : : Number , static_cast < NVL : : Number > ( tags_match [ 2 ] . second - s . cbegin ( ) - running_offset ) }
}
} } ;
NVL : : Parse : : Object effects_obj { NVL : : Parse : : Type : : Array , std : : vector < NVL : : Parse : : Object > { } } ;
std : : vector < NVL : : Parse : : Object > & effects = std : : get < std : : vector < NVL : : Parse : : Object > > ( effects_obj . value ) ;
std : : string : : const_iterator effects_start ( tags_match [ 1 ] . first ) ;
while ( std : : regex_search ( effects_start , tags_match [ 1 ] . second , effects_match , effect ) ) {
if ( effects_match [ 3 ] . matched ) {
effects . push_back ( { NVL : : Parse : : Type : : String , effects_match [ 3 ] . str ( ) } ) ;
}
else {
NVL : : Parse : : Object args { NVL : : Parse : : Type : : Array , std : : vector < NVL : : Parse : : Object > { } } ;
std : : string : : const_iterator params_start ( effects_match [ 2 ] . first ) ;
while ( std : : regex_search ( params_start , effects_match [ 2 ] . second , params_match , param ) ) {
size_t temp = 0 ;
std : : get < std : : vector < NVL : : Parse : : Object > > ( args . value ) . push_back ( ParseExpression ( params_match [ 1 ] . str ( ) + SEPARATOR . accept [ 0 ] , temp ) ) ; // PeekToken will freak out if I don't do this
params_start = params_match . suffix ( ) . first ;
}
effects . push_back ( { NVL : : Parse : : Type : : Array , std : : vector < NVL : : Parse : : Object > { { NVL : : Parse : : Type : : String , effects_match [ 1 ] . str ( ) } , args } } ) ;
}
effects_start = effects_match . suffix ( ) . first ;
}
running_offset + = tags_match [ 0 ] . second - tags_match [ 2 ] . second ;
tags_start = tags_match . suffix ( ) . first ;
tags . push_back ( { NVL : : Parse : : Type : : Array , std : : vector < NVL : : Parse : : Object > { range , effects_obj } } ) ;
}
if ( has_markup ) {
reconstruction . append ( tags_match . suffix ( ) . first , tags_match . suffix ( ) . second ) ;
s = reconstruction ;
return { NVL : : Parse : : Type : : Array , tags } ;
}
else {
return { NVL : : Parse : : Type : : Array , std : : vector < NVL : : Parse : : Object > { } } ;
}
}
2021-12-17 01:05:38 -05:00
NVL : : Parse : : Command ParseDialogue ( const std : : string & s ) {
2021-12-13 14:04:12 -05:00
if ( s . substr ( 0 , 2 ) = = COMMAND_ESCAPE . accept ) {
size_t dummy = 0 ;
2021-12-17 01:05:38 -05:00
// Pad a space towards the end, the helpers do not expect strings to immediately terminate
return ParseCommand ( s . substr ( 2 ) + " " , dummy ) ;
2021-12-13 14:04:12 -05:00
}
2021-12-17 01:05:38 -05:00
// assume SwitchSpeaker and Say are unary for now
2021-12-13 14:04:12 -05:00
if ( s . back ( ) = = SPEAKER_CLOSE ) {
if ( s . front ( ) = = SPEAKER_OPEN ) {
auto name = s . substr ( 1 , s . length ( ) - 2 ) ;
if ( IsLegalSymbolName ( name ) )
2021-12-17 01:05:38 -05:00
return { { NVL : : Parse : : Type : : Symbol , " SwitchSpeaker " } , { NVL : : Parse : : Type : : String , name } } ;
2021-12-13 14:04:12 -05:00
}
else
throw std : : runtime_error ( " Malformed speaker command " ) ;
}
2022-05-10 02:42:12 -04:00
std : : string copy { s } ;
NVL : : Parse : : Object tags = MatchMarkup ( copy ) ; // THIS WILL MODIFY COPY
return { { NVL : : Parse : : Type : : Symbol , " Say " } , { NVL : : Parse : : Type : : String , copy } , tags } ;
2021-05-14 11:47:54 -04:00
}
2021-05-15 17:48:37 -04:00
2021-12-17 01:05:38 -05:00
NVL : : Parse : : Scene ParseScene ( const std : : string & f , size_t & pos ) {
2021-12-12 03:41:54 -05:00
SkipComments ( f , pos ) ;
if ( ! ( GetToken ( f , pos ) = = BEGIN . accept ) )
throw std : : runtime_error ( " Could not match accept at root " ) ;
auto scene_name = GetToken ( f , pos ) ;
2021-12-12 22:20:28 -05:00
if ( ! IsLegalSymbolName ( scene_name ) ) throw std : : runtime_error ( " Illegal Scene name " ) ;
2021-12-17 01:05:38 -05:00
NVL : : Parse : : Scene s { scene_name } ;
2021-12-12 03:41:54 -05:00
2021-12-12 22:20:28 -05:00
bool dialogue_mode = false ;
2021-12-12 03:41:54 -05:00
while ( PeekToken ( f , pos ) ! = END . accept ) {
2021-12-12 22:20:28 -05:00
if ( ! dialogue_mode )
if ( PeekToken ( f , pos ) = = DIALOGUE_OPEN . accept ) {
dialogue_mode = true ;
GetToken ( f , pos ) ; // skip DIALOGUE_OPEN
SkipComments ( f , pos ) ;
}
else
s . append ( ParseCommand ( f , pos ) ) ;
else {
auto end = f . find ( NEWLINE . accept + DIALOGUE_CLOSE . accept , pos ) ;
if ( end = = std : : string : : npos )
throw std : : runtime_error ( " Dialogue does not terminate " ) ;
auto lines = split_string_by_lines ( f . substr ( pos , end - pos ) ) ;
for ( auto & l : lines ) {
2021-12-17 01:05:38 -05:00
if ( ! l . empty ( ) & & ! ContainsOnlyWS ( l ) )
s . append ( ParseDialogue ( l ) ) ;
2021-12-12 22:20:28 -05:00
}
dialogue_mode = false ;
pos = end ;
GetToken ( f , pos ) ; // skip DIALOGUE_CLOSE
SkipComments ( f , pos ) ;
}
2021-07-16 20:27:25 -04:00
}
2021-05-14 16:51:04 -04:00
2021-12-12 22:20:28 -05:00
if ( dialogue_mode )
throw std : : runtime_error ( " Illegal Scene end " ) ;
2021-12-12 03:41:54 -05:00
GetToken ( f , pos ) ; // skip END
2021-05-14 16:51:04 -04:00
2021-12-17 01:05:38 -05:00
SkipComments ( f , pos ) ;
2021-12-12 22:20:28 -05:00
return s ;
2021-12-12 03:41:54 -05:00
}
2022-05-10 02:42:12 -04:00
2021-12-12 03:41:54 -05:00
}
2021-05-15 17:48:37 -04:00
2021-12-17 01:05:38 -05:00
namespace NVL : : Parse {
std : : vector < Scene > ParseFile ( const std : : string & path ) {
2021-12-12 03:41:54 -05:00
std : : string f = read_file_to_string ( path ) ;
2021-05-14 11:47:54 -04:00
2021-12-12 03:41:54 -05:00
std : : vector < Scene > list { } ; // Vector of scenes which each contain a vector of Parses
for ( size_t i = 0 ; i < f . length ( ) ; i + + ) {
2021-12-12 22:20:28 -05:00
list . push_back ( ParseScene ( f , i ) ) ;
2021-05-14 16:51:04 -04:00
}
2021-07-16 20:27:25 -04:00
2021-12-17 01:05:38 -05:00
return list ;
2021-07-16 20:27:25 -04:00
}
2021-05-14 17:21:10 -04:00
}
2021-12-12 03:41:54 -05:00