Skip to content

Commit

Permalink
add proper argparsing; fix small bug when using multiple uses
Browse files Browse the repository at this point in the history
  • Loading branch information
kevlu8 committed May 29, 2023
1 parent e8cda32 commit 64b35f3
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 62 deletions.
10 changes: 8 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.10)

project(CPCC VERSION 0.1.0)
project(CPCC VERSION 0.2.0)

add_definitions("-DCPCC_VER=\"${PROJECT_VERSION}\"")
add_definitions("-DCPCC_INCLUDE_DIR=\"/usr/local/include/cpcc/\"")
Expand All @@ -9,5 +9,11 @@ add_executable(cpcc src/main.cpp src/warn.cpp)

target_compile_options(cpcc PRIVATE -O3 -std=c++20)

find_package(Boost 1.75.0 REQUIRED COMPONENTS system)
target_link_libraries(cpcc PRIVATE Boost::system
-lboost_system
-lboost_program_options
)

install(TARGETS cpcc DESTINATION bin)
install(DIRECTORY src/cpcc/ DESTINATION /usr/local/include/cpcc)
install(DIRECTORY src/cpcc/ DESTINATION /usr/local/include/cpcc)
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ We are mainly looking for contributions to utility parts of CPCC - they should b

## Guidelines

1. Code inside of the files should not be offensive - they should not contain offensive language, variable names, etc.
2. Parts of the code where the user is welcome to modify should be commented as such: e.g. `// subtract 1 if index is 1-indexed`
3. Before writing your code, take a look at `src/crucial/base/` to see the base code: you can use the macros provided there to make your code more readable
1. Code inside of the files should not contain offensive language.
2. Parts of the code where the user is welcome to modify should be commented as such: e.g. `// subtract 1 if it is 1-indexed`.
3. Before writing your code, take a look at `src/crucial/base/` to see the base code: you can use the macros provided there to make your code more readable.

Check out the [todo](https://github.com/kevlu8/CPCC/blob/master/todo) for a list of things that need to be done.
Check out the [todo](https://github.com/kevlu8/CPCC/blob/master/todo) for a list of things that need to be done.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The competitive programmer's C++ translator.
`use`s must be before all other code in CP files:

```cpp
use macros;
use factorial;

int main() {
Expand All @@ -20,6 +21,7 @@ will work, but

```cpp
#include <iostream>
use macros;
use factorial;

int main() {
Expand All @@ -33,13 +35,15 @@ CPC is virtually identical to C++, except for having `use` libraries.

To use a library, simply put `use <libname>;` at the beginning of your code.

To compile your CP program, run `cpcc file.cpc`.
To compile your CPC program, run `cpcc file.cpc`.

If you would not like the credits comments at the beginning of your code, simplify run `cpcc --nocredits file.cpc`.

If you would not like warnings to be printed, simply run `cpcc --Wnone file.cpc`.

### Installing

As CPCC depends on its libraries, it is **highly recommended** that you build from source as opposed to installing a prebuilt version.
As CPCC depends on its libraries, it is **highly recommended** that you build from source as opposed to installing a prebuilt version. You may need to install Boost for CPCC to work.

1. Clone the repository:

Expand Down Expand Up @@ -73,4 +77,4 @@ make -j4
sudo make install
```

You can now use CPCC! Run `cpcc --version` to check if it is installed properly.
You can now use CPCC! Run `cpcc --version` to check if it is installed properly.
4 changes: 2 additions & 2 deletions src/cpcc/utils/macros
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
#define debug(x) cout << #x << " = " << x << endl;
#define indexed_set tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update>
#define fastio() cin.tie(0)->sync_with_stdio(0)
#define printx(x) { cout << (x) << '\n'; exit(0); }
#define inputvector(x, n) x.resize(n); forj(n) { cin >> x[j]; }
#define printx(x) do { cout << (x) << '\n'; exit(0); } while (0)
#define inputvector(x, n) x.resize(n); forj(n) cin >> x[j]
#define hashtable gp_hash_table
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
Expand Down
99 changes: 55 additions & 44 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
#include <ctime>
#include <deque>
#include <fstream>
#include <filesystem>
#include <iostream>
#include <string>
#include <cstring>
#include <ctime>

#include <boost/program_options.hpp>

#include "warn.hpp"

#ifndef CPCC_VER // Should only happen if compiled improperly
#define CPCC_VER "ERR"
#define CPCC_INCLUDE_DIR "ERR"
#endif

void ffprint(std::string path, std::ofstream *out) {
std::ifstream f(path);
if (!f.is_open()) {
Expand All @@ -21,62 +27,64 @@ void ffprint(std::string path, std::ofstream *out) {
f.close();
}

bool handle_args(char *arg) {
bool credit = true;
if (strcmp(arg, "version") == 0) {
std::cout << "CPCC version " << CPCC_VER << std::endl;
exit(0);
int main(int argc, char *argv[]) {
boost::program_options::options_description desc("CPCC usage");
desc.add_options()
("help", "Prints this message")
("version", "Prints the version of CPCC you are using")
("libs", "Prints available CPCC libraries")
("nocredit", "Compiles the file without the credits at the beginning")
("Wnone", "Disables all warnings")
("o", boost::program_options::value<std::string>(), "The output file (out.cpp by default)")
("file", boost::program_options::value<std::string>(), "The file to compile (using --file is optional)");

boost::program_options::positional_options_description p;
p.add("file", -1);

boost::program_options::variables_map vm;
boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
boost::program_options::notify(vm);

if (vm.count("help") || argc < 2) {
std::cout << desc << std::endl;
return argc < 2;
}
else if (strcmp(arg, "libs") == 0) {
if (vm.count("version")) {
std::cout << "CPCC version " << CPCC_VER << " with include directory " << CPCC_INCLUDE_DIR << std::endl;
return 0;
}
if (vm.count("libs")) {
std::cout << "Available libraries: ";
for (const auto &entry : std::filesystem::directory_iterator(std::string(CPCC_INCLUDE_DIR) + "utils")) {
std::string file = entry.path().filename().string();
if (file[0] == '.') continue;
std::cout << file << ' ';
}
std::cout << std::endl;
exit(0);
}
else if (strcmp(arg, "nocredit") == 0) {
credit = false;
}
else {
std::cerr << "Invalid argument " << arg << " supplied!" << std::endl;
exit(1);
return 0;
}
return credit;
}

int main(int argc, char *argv[]) {
if (argc < 2 || strcmp(argv[1], "--help") == 0) {
std::cout << "usage: " << argv[0] << " [--help] [--version] [--libs] [--nocredit] <filename>\n"
<< "arguments:\n"
<< " --help Prints this message\n"
<< " --version Prints the version of CPCC you are using\n"
<< " --libs Prints available CPCC libraries\n"
<< " --nocredit Compiles the file without the credits at the beginning\n"
<< std::flush;

if (argc < 2)
return 1;
else
return 0;
std::string outfile = "out.cpp";
if (vm.count("o")) {
outfile = vm["o"].as<std::string>();
}

long long timer = clock();

bool credit = true;
if (vm.count("nocredit")) {
credit = false;
}

if (strncmp(argv[1], "--", 2) == 0)
credit = handle_args(argv[1]+2);
std::string infile = vm["file"].as<std::string>();

long long timer = clock();

std::ifstream in(argv[argc-1]);
std::ifstream in(infile);
if (!in.is_open()) {
std::cerr << "Invalid file " << argv[argc-1] << " supplied!" << std::endl;
std::cerr << "Invalid file " << infile << " supplied!" << std::endl;
return 1;
}

std::ofstream out("out.cpp");
std::ofstream out(outfile);
if (!out.is_open()) {
std::cerr << "Could not open result file!" << std::endl;
return 1;
Expand Down Expand Up @@ -108,6 +116,7 @@ int main(int argc, char *argv[]) {
return 1;
}
ffprint(path, &out);
out << '\n';
continue;
}
if (end_imports == -1) {
Expand All @@ -120,21 +129,23 @@ int main(int argc, char *argv[]) {
lines.pop_front();
}

out << '\n';
while (lines.front().size() == 0) {
lines.pop_front();
}

std::string main_buf;
main_buf.reserve(65536);
for (int i = end_imports; i < lines.size(); i++) {
for (int i = 0; i < lines.size(); i++) {
out << lines[i] << '\n';
main_buf += lines[i] + '\n';
}

Warnings::analyze(main_buf, lines);
if (!vm.count("Wnone"))
Warnings::analyze(main_buf, lines);

out.close();

long long timer2 = clock();
std::cout << "\033[1;32mSuccess!\033[0m Compiled in " << (timer2 - timer) / (double)CLOCKS_PER_SEC * 1000 << " ms." << std::endl;
std::cout << "\033[1;32mSuccess!\033[0m Compiled in " << (clock() - timer) / (double)CLOCKS_PER_SEC * 1000 << " ms." << std::endl;

return 0;
}
11 changes: 8 additions & 3 deletions src/warn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ void Warnings::analyze(std::string &code, std::deque<std::string> &lines) {
std::cout << "\033[1;33mWarning: \033[0m" << "Using `std::` is not recommended, as `using namespace std;` "
<< "is already included." << std::endl;
}
// check for use of unordered set/map
if (code.find("unordered_set") != std::string::npos || code.find("unordered_map") != std::string::npos) {
std::cout << "\033[1;33mWarning: \033[0m" << "Using `unordered_set` or `unordered_map` is not recommended, "
<< "as the worst case time complexity can be O(n). Instead, use `set` or `map`." << std::endl;
}

int depth = 0;
std::vector<std::vector<std::string>> functions;
Expand All @@ -35,7 +40,7 @@ void Warnings::analyze(std::string &code, std::deque<std::string> &lines) {
depth++;
flag = true;
}
if (lines[i].find('}') != std::string::npos) {
if (lines[i].find('}') != std::string::npos) { // mega scuffed
depth--;
flag = true;
}
Expand Down Expand Up @@ -70,7 +75,7 @@ void Warnings::analyze(std::string &code, std::deque<std::string> &lines) {
}
if (functions[i][j].find('}') != std::string::npos) {
depth--;
if (fors.find(depth + 1) != fors.end()) {
if (fors.count(depth + 1)) {
exp_n = std::max(exp_n, (int)fors.size());
fors.erase(depth + 1);
}
Expand All @@ -80,4 +85,4 @@ void Warnings::analyze(std::string &code, std::deque<std::string> &lines) {
else if (exp_n == 1) std::cout << name << " O(n)" << std::endl;
else std::cout << name << " O(n^" << exp_n << ")" << std::endl;
}
}
}
7 changes: 3 additions & 4 deletions todo
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
- un-hardcode include directory for cmake
- have proper argument parsing
- display stats after compilation
- time taken
- **estimated time complexity of code**
- output time complexity for every function (beta)
- output time complexity for every function
- add compiler warnings for:
- running complete search on a sorted array
- lower_bound, upper_bound on an unsorted array
- lower_bound, upper_bound on an unsorted array
- other bad practices in competitive programming

0 comments on commit 64b35f3

Please sign in to comment.