@ -4,7 +4,6 @@
# include <filesystem>
# include <fstream>
# include <iostream>
# include <sstream>
# include <stack>
# include <string>
# include <variant>
@ -19,120 +18,169 @@ int main(int argc, char** argv) {
argc - - ;
}
n">std : : stack < compile_element > compile_stack ;
k">try {
for ( auto elem : arguments ) {
if ( elem = = " generate " ) {
if ( std : : holds_alternative < std : : string > ( compile_stack . top ( ) ) ) {
auto filename = std : : get < std : : string > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
if ( std : : holds_alternative < molasses : : generate_context > ( compile_stack . top ( ) ) ) {
auto generator = std : : get < molasses : : generate_context > ( compile_stack . top ( ) ) ;
std : : stack < compile_element > compile_stack ;
for ( auto elem : arguments ) {
if ( elem = = " generate " ) {
if ( std : : holds_alternative < std : : string > ( compile_stack . top ( ) ) ) {
auto filename = std : : get < std : : string > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
auto assembler = molasses : : generate ( generator ) ;
std : : ofstream output ( filename + " .s " ) ;
for ( const auto & line : assembler ) {
output < < line ;
}
compile_stack . emplace ( filename ) ;
} else throw std : : runtime_error ( " generate expects a parsed output " ) ;
} else throw std : : runtime_error ( " generate expects a filename " ) ;
} else if ( elem = = " parse " ) {
molasses : : parser_context ctx ;
ctx = molasses : : register_integers ( ctx ) ;
ctx = molasses : : register_i32_operations ( ctx ) ;
if ( std : : holds_alternative < molasses : : generate_context > ( compile_stack . top ( ) ) ) {
auto generator = std : : get < molasses : : generate_context > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
auto assembler = molasses : : generate ( generator ) ;
std : : ofstream output ( filename + " .s " ) ;
for ( const auto & line : assembler ) {
output < < line ;
}
compile_stack . emplace ( filename ) ;
} else
throw std : : runtime_error ( " generate expects a parsed output " ) ;
} else
throw std : : runtime_error ( " generate expects a filename " ) ;
} else if ( elem = = " parse " ) {
molasses : : parser_context ctx ;
ctx = molasses : : register_integers ( ctx ) ;
ctx = molasses : : register_i32_operations ( ctx ) ;
if ( std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
auto generator = molasses : : parse ( ctx , lexer ) ;
compile_stack . emplace ( generator ) ;
} else throw std : : runtime_error ( " parse expects a lexed output " ) ;
} else if ( elem = = " lex " ) {
if ( std : : holds_alternative < std : : string > ( compile_stack . top ( ) ) ) {
auto filename = std : : get < std : : string > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
if ( not std : : filesystem : : exists ( filename ) ) throw std : : runtime_error ( " file " + filename + " does not exist " ) ;
std : : ifstream t ( filename ) ;
std : : stringstream buffer ;
buffer < < t . rdbuf ( ) ;
auto lexed = molasses : : lex ( buffer . str ( ) ) ;
compile_stack . emplace ( lexed ) ;
} else throw std : : runtime_error ( " lex expects a filename " ) ;
} else if ( elem = = " merge " ) {
if ( std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer_1 = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
if ( std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer_2 = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
auto lexer = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
compile_stack . emplace ( molasses : : concatenate ( lexer_1 , lexer_2 ) ) ;
} else throw std : : runtime_error ( " merge expects 2 lexed outputs " ) ;
} else throw std : : runtime_error ( " merge expects 2 lexed outputs " ) ;
} else if ( elem = = " assemble " ) {
if ( std : : holds_alternative < std : : string > ( compile_stack . top ( ) ) ) {
auto filename = std : : get < std : : string > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
std : : stringstream compile ; compile < < " clang -c " < < filename < < " .s -o " < < filename < < " .o " ;
std : : stringstream link ; link < < " ld -e _start " < < filename < < " .o -o " < < filename ;
std : : cout < < compile . str ( ) < < std : : endl ;
system ( compile . str ( ) . c_str ( ) ) ;
std : : cout < < link . str ( ) < < std : : endl ;
system ( link . str ( ) . c_str ( ) ) ;
} else throw std : : runtime_error ( " assemble expects an assembly file " ) ;
} else if ( elem = = " help " or elem = = " --help " ) {
std : : cout < < " # Sugar \n \n " ;
std : : cout < < " ## Commands \n \n " ;
std : : cout < < " lex : string ➔ lexed_output \n " ;
std : : cout < < " > takes a filename to a file that must be compiled \n \n " ;
std : : cout < < " merge : lexed_output lexed_output ➔ lexed_output \n " ;
std : : cout < < " > merges two lexed modules together \n \n " ;
std : : cout < < " parse : lexed_output ➔ parsed_output \n " ;
std : : cout < < " > prepares code for generation \n \n " ;
std : : cout < < " generate : parsed_output string ➔ string \n " ;
std : : cout < < " > takes a root filename, it will be appended with \" .s \" and that will be the generated assembly file, \n " ;
std : : cout < < " > the filename will not be consumed \n \n " ;
std : : cout < < " assemble : string ➔ _ \n " ;
std : : cout < < " > takes a root filename, it will be appended with \" .s \" and that file will be compiled, \n " ;
std : : cout < < " > the compiled output will be the given filename \n \n " ;
std : : cout < < " help : _ ➔ _ \n " ;
std : : cout < < " > prints this help \n \n " ;
std : : cout < < " ## Examples \n \n " ;
std : : cout < < " - compile the file \" example.mol \" into the \" potato.s \" assembly file \n " ;
std : : cout < < " > `$ sugar example.mol lex parse potato generate` \n " ;
std : : cout < < " \n " ;
std : : cout < < " - compile the file \" example.mol \" into the \" potato \" executable \n " ;
std : : cout < < " > `$ sugar example.mol lex parse potato generate assemble` \n " ;
std : : cout < < " \n " ;
std : : cout < < " - compile the file \" example.mol \" and \" 2.mol \" into the \" potato \" executable \n " ;
std : : cout < < " > `$ sugar example.mol lex 2.mol lex merge parse potato generate assemble` \n " ;
} else compile_stack . emplace ( elem ) ;
}
if ( compile_stack . size ( ) > 1 ) throw std : : runtime_error ( " build left unfinished operations " ) ;
if ( not compile_stack . empty ( ) ) {
if ( std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
for ( auto elem : lexer . symbols ) {
std : : cout < < elem < < " " ;
}
std : : cout < < " \n \n " ;
for ( auto [ id , name ] : lexer . dictionary ) {
std : : cout < < id < < " : " < < name < < " \n " ;
}
} else if ( std : : holds_alternative < molasses : : generate_context > ( compile_stack . top ( ) ) ) {
auto generator = std : : get < molasses : : generate_context > ( compile_stack . top ( ) ) ;
for ( const auto & elem : generator . procedures ) {
std : : cout < < elem - > _name < < " : " ;
for ( const auto & args : elem - > _args ) {
std : : cout < < args < < " " ;
auto generator = molasses : : parse ( ctx , lexer ) ;
compile_stack . emplace ( generator ) ;
} else
throw std : : runtime_error ( " parse expects a lexed output " ) ;
} else if ( elem = = " lex " ) {
if ( std : : holds_alternative < std : : string > ( compile_stack . top ( ) ) ) {
auto filename = std : : get < std : : string > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
if ( not std : : filesystem : : exists ( filename ) )
throw std : : runtime_error ( " file " + filename + " does not exist " ) ;
std : : ifstream t ( filename ) ;
std : : stringstream buffer ;
buffer < < t . rdbuf ( ) ;
auto lexed = molasses : : lex ( filename , buffer . str ( ) ) ;
compile_stack . emplace ( lexed ) ;
} else
throw std : : runtime_error ( " lex expects a filename " ) ;
} else if ( elem = = " lex-all " ) {
std : : vector < molasses : : lexed_output > lexed_list ;
while ( not compile_stack . empty ( ) and std : : holds_alternative < std : : string > ( compile_stack . top ( ) ) ) {
auto filename = std : : get < std : : string > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
if ( not std : : filesystem : : exists ( filename ) )
throw std : : runtime_error ( " file " + filename + " does not exist " ) ;
std : : ifstream t ( filename ) ;
std : : stringstream buffer ;
buffer < < t . rdbuf ( ) ;
auto lexed = molasses : : lex ( filename , buffer . str ( ) ) ;
lexed_list . emplace_back ( lexed ) ;
}
std : : cout < < " -> " ;
for ( const auto & rets : elem - > _rets ) {
std : : cout < < " " < < rets ;
for ( auto & lexed : lexed_list ) {
compile_stack . emplace ( std : : move ( lexed ) ) ;
}
} else if ( elem = = " merge " ) {
if ( std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer_1 = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
if ( std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer_2 = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
compile_stack . emplace ( molasses : : concatenate ( lexer_1 , lexer_2 ) ) ;
} else
throw std : : runtime_error ( " merge expects 2 lexed outputs " ) ;
} else
throw std : : runtime_error ( " merge expects 2 lexed outputs " ) ;
} else if ( elem = = " merge-all " ) {
if ( std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer_1 = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
while ( not compile_stack . empty ( ) and std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer_2 = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
lexer_1 = molasses : : concatenate ( lexer_1 , lexer_2 ) ;
}
compile_stack . emplace ( lexer_1 ) ;
} else
throw std : : runtime_error ( " merge-all expects at least 1 lexed outputs " ) ;
} else if ( elem = = " assemble " ) {
if ( std : : holds_alternative < std : : string > ( compile_stack . top ( ) ) ) {
auto filename = std : : get < std : : string > ( compile_stack . top ( ) ) ;
compile_stack . pop ( ) ;
std : : stringstream compile ;
compile < < " clang -c " < < filename < < " .s -o " < < filename < < " .o " ;
std : : stringstream link ;
link < < " ld -e _start " < < filename < < " .o -o " < < filename ;
std : : cout < < compile . str ( ) < < std : : endl ;
system ( compile . str ( ) . c_str ( ) ) ;
std : : cout < < link . str ( ) < < std : : endl ;
system ( link . str ( ) . c_str ( ) ) ;
} else
throw std : : runtime_error ( " assemble expects an assembly file " ) ;
} else if ( elem = = " help " or elem = = " --help " ) {
std : : cout < < " # Sugar \n \n " ;
std : : cout < < " ## Commands \n \n " ;
std : : cout < < " lex : string ➔ lexed_output \n " ;
std : : cout < < " > takes a filename to a file that must be compiled \n \n " ;
std : : cout < < " lex-all : string* ➔ lexed_output* \n " ;
std : : cout < < " > takes as many filenames to files that must be compiled as can be read and passes them through the lexed \n \n " ;
std : : cout < < " merge : lexed_output lexed_output ➔ lexed_output \n " ;
std : : cout < < " > merges two lexed modules together \n \n " ;
std : : cout < < " merge-all : lexed_output* ➔ lexed_output \n " ;
std : : cout < < " > merges as many lexed modules together as present on the top of the stack \n \n " ;
std : : cout < < " parse : lexed_output ➔ parsed_output \n " ;
std : : cout < < " > prepares code for generation \n \n " ;
std : : cout < < " generate : parsed_output string ➔ string \n " ;
std : : cout < < " > takes a root filename, it will be appended with \" .s \" and that will be the generated assembly file, \n " ;
std : : cout < < " > the filename will not be consumed \n \n " ;
std : : cout < < " assemble : string ➔ _ \n " ;
std : : cout
< < " > takes a root filename, it will be appended with \" .s \" and that file will be compiled, \n " ;
std : : cout < < " > the compiled output will be the given filename \n \n " ;
std : : cout < < " help : _ ➔ _ \n " ;
std : : cout < < " > prints this help \n \n " ;
std : : cout < < " ## Examples \n \n " ;
std : : cout < < " - compile the file \" example.mol \" into the \" potato.s \" assembly file \n " ;
std : : cout < < " > `$ sugar example.mol lex parse potato generate` \n " ;
std : : cout < < " \n " ;
std : : cout < < " - compile the file \" example.mol \" into the \" potato \" executable \n " ;
std : : cout < < " > `$ sugar example.mol lex parse potato generate assemble` \n " ;
std : : cout < < " \n " ;
std : : cout < < " - compile the file \" example.mol \" and \" 2.mol \" into the \" potato \" executable \n " ;
std : : cout < < " > `$ sugar example.mol lex 2.mol lex merge parse potato generate assemble` \n " ;
} else
compile_stack . emplace ( elem ) ;
}
if ( compile_stack . size ( ) > 1 ) throw std : : runtime_error ( " build left unfinished operations " ) ;
if ( not compile_stack . empty ( ) ) {
if ( std : : holds_alternative < molasses : : lexed_output > ( compile_stack . top ( ) ) ) {
auto lexer = std : : get < molasses : : lexed_output > ( compile_stack . top ( ) ) ;
for ( auto elem : lexer . symbols ) {
std : : cout < < elem < < " " ;
}
std : : cout < < " \n \n " ;
for ( auto [ id , name ] : lexer . dictionary ) {
std : : cout < < id < < " : " < < name < < " \n " ;
}
} else if ( std : : holds_alternative < molasses : : generate_context > ( compile_stack . top ( ) ) ) {
auto generator = std : : get < molasses : : generate_context > ( compile_stack . top ( ) ) ;
for ( const auto & elem : generator . procedures ) {
std : : cout < < elem - > _name < < " : " ;
for ( const auto & args : elem - > _args ) {
std : : cout < < args < < " " ;
}
std : : cout < < " -> " ;
for ( const auto & rets : elem - > _rets ) {
std : : cout < < " " < < rets ;
}
std : : cout < < " \n " ;
}
}
}
} catch ( molasses : : parser_error & error ) {
std : : cerr < < error . what ( ) ;
}
}