diff --git a/lint/Makefile b/lint/Makefile new file mode 100644 index 0000000..89c058b --- /dev/null +++ b/lint/Makefile @@ -0,0 +1,15 @@ + +USE_CLANG = 1 + +ifdef USE_CLANG +CC = clang++ +CFLAGS = -std=c++1y -stdlib=libc++ -g +else +CC = g++ +CFLAGS = -std=c++1y -g +endif + +all: peglint + +peglint : peglint.cc ../peglib.h + $(CC) -o peglint $(CFLAGS) -I.. peglint.cc diff --git a/lint/mmap.h b/lint/mmap.h new file mode 100644 index 0000000..e19333c --- /dev/null +++ b/lint/mmap.h @@ -0,0 +1,149 @@ + +#ifndef _MMAP_H_ +#define _MMAP_H_ + +#if defined(_MSC_VER) +#include +#else +#include +#include +#include +#include +#endif + +class MemoryMappedFile +{ +public: + MemoryMappedFile(const char* path); + ~MemoryMappedFile(); + + bool is_open() const; + size_t size() const; + const char* data() const; + +private: + void cleanup(); + +#if defined(_MSC_VER) + HANDLE hFile_; + HANDLE hMapping_; +#else + int fd_; +#endif + size_t size_; + void* addr_; +}; + +#if defined(_MSC_VER) +#define MAP_FAILED NULL +#endif + +inline MemoryMappedFile::MemoryMappedFile(const char* path) +#if defined(_MSC_VER) + : hFile_(NULL) + , hMapping_(NULL) +#else + : fd_(-1) +#endif + , size_(0) + , addr_(MAP_FAILED) +{ +#if defined(_MSC_VER) + hFile_ = ::CreateFileA( + path, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile_ == INVALID_HANDLE_VALUE) { + std::runtime_error(""); + } + + size_ = ::GetFileSize(hFile_, NULL); + + hMapping_ = ::CreateFileMapping(hFile_, NULL, PAGE_READONLY, 0, 0, NULL); + + if (hMapping_ == NULL) { + cleanup(); + std::runtime_error(""); + } + + addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0); +#else + fd_ = open(path, O_RDONLY); + if (fd_ == -1) { + std::runtime_error(""); + } + + struct stat sb; + if (fstat(fd_, &sb) == -1) { + cleanup(); + std::runtime_error(""); + } + size_ = sb.st_size; + + addr_ = mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0); +#endif + + if (addr_ == MAP_FAILED) { + cleanup(); + std::runtime_error(""); + } +} + +inline MemoryMappedFile::~MemoryMappedFile() +{ + cleanup(); +} + +inline bool MemoryMappedFile::is_open() const +{ + return addr_ != MAP_FAILED; +} + +inline size_t MemoryMappedFile::size() const +{ + return size_; +} + +inline const char* MemoryMappedFile::data() const +{ + return (const char*)addr_; +} + +inline void MemoryMappedFile::cleanup() +{ +#if defined(_MSC_VER) + if (addr_) { + ::UnmapViewOfFile(addr_); + addr_ = MAP_FAILED; + } + + if (hMapping_) { + ::CloseHandle(hMapping_); + hMapping_ = NULL; + } + + if (hFile_ != INVALID_HANDLE_VALUE) { + ::CloseHandle(hFile_); + hFile_ = INVALID_HANDLE_VALUE; + } +#else + if (addr_ != MAP_FAILED) { + munmap(addr_, size_); + addr_ = MAP_FAILED; + } + + if (fd_ != -1) { + close(fd_); + fd_ = -1; + } +#endif +} + +#endif // _MMAP_H_ + +// vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/lint/peglint.cc b/lint/peglint.cc new file mode 100644 index 0000000..cc674b9 --- /dev/null +++ b/lint/peglint.cc @@ -0,0 +1,65 @@ +// +// peglint.cc +// +// Copyright (c) 2015 Yuji Hirose. All rights reserved. +// MIT License +// + +#include +#include +#include "mmap.h" + +using namespace peglib; +using namespace std; + +int main(int argc, const char** argv) +{ + if (argc < 2 || string("--help") == argv[1]) { + cerr << "usage: peglint [grammar file path] [source file path]" << endl; + return 1; + } + + // Check PEG grammar + cerr << "checking grammar file..." << endl; + + MemoryMappedFile syntax(argv[1]); + if (!syntax.is_open()) { + cerr << "can't open the grammar file." << endl; + return -1; + } + + auto parser = make_parser(syntax.data(), syntax.size(), [](size_t ln, size_t col, const string& msg) { + cerr << ln << ":" << col << ": " << msg << endl; + }); + + if (parser) { + cerr << "success" << endl; + } else { + cerr << "invalid grammar file." << endl; + return -1; + } + + if (argc < 3) { + return 0; + } + + // Check source + cerr << "checking source file..." << endl; + + MemoryMappedFile source(argv[2]); + if (!source.is_open()) { + cerr << "can't open the source file." << endl; + return -1; + } + + auto m = parser.lint(source.data(), source.size()); + + if (m.ret) { + cerr << "success" << endl; + } else { + auto info = line_info(source.data(), m.ptr); + cerr << info.first << ":" << info.second << ": syntax error" << endl; + } +} + +// vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/lint/peglint.sln b/lint/peglint.sln new file mode 100644 index 0000000..ae9f084 --- /dev/null +++ b/lint/peglint.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peglint", "peglint.vcxproj", "{F85B641A-7538-4809-8175-C528FF632CF6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F85B641A-7538-4809-8175-C528FF632CF6}.Debug|Win32.ActiveCfg = Debug|Win32 + {F85B641A-7538-4809-8175-C528FF632CF6}.Debug|Win32.Build.0 = Debug|Win32 + {F85B641A-7538-4809-8175-C528FF632CF6}.Release|Win32.ActiveCfg = Release|Win32 + {F85B641A-7538-4809-8175-C528FF632CF6}.Release|Win32.Build.0 = Release|Win32 + {1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Debug|Win32.ActiveCfg = Debug|Win32 + {1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Debug|Win32.Build.0 = Debug|Win32 + {1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Release|Win32.ActiveCfg = Release|Win32 + {1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/lint/peglint.vcxproj b/lint/peglint.vcxproj new file mode 100644 index 0000000..6d3ea80 --- /dev/null +++ b/lint/peglint.vcxproj @@ -0,0 +1,99 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + {F85B641A-7538-4809-8175-C528FF632CF6} + Win32Proj + sample + peglint + + + + Application + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + .. + + + Console + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + .. + + + Console + true + true + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file