Skip to content

Commit

Permalink
Merge pull request #29 from soasme/doxygen
Browse files Browse the repository at this point in the history
Generate docs using Sphinx & Doxygen.
  • Loading branch information
soasme authored Feb 28, 2021
2 parents 120673b + 299553c commit f82f880
Show file tree
Hide file tree
Showing 32 changed files with 1,942 additions and 235 deletions.
58 changes: 58 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,61 @@ target_compile_options("${P4_LIB}" PRIVATE "-g")
# target_compile_options("${P4_LIB}" PRIVATE "-fsanitize=address")

add_subdirectory(tests)


# Docs
if (ENABLE_DOCS)
find_package(Doxygen REQUIRED)
set(DOXYGEN_INPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/docs)
set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml)
set(DOXYFILE ${CMAKE_CURRENT_SOURCE_DIR}/docs/.doxygen.conf)
add_custom_command(
OUTPUT ${DOXYGEN_INDEX_FILE}
MAIN_DEPENDENCY ${P4_HEADERS} ${P4_SOURCES} ${DOXYFILE}
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE}
COMMENT "Generate doxygen docs"
VERBATIM
)
add_custom_target(
doxygen ALL
DEPENDS ${DOXYGEN_INDEX_FILE}
)

find_program(PYTHON python3)
find_program(PYTHONVENV python3-venv)

set(VIRTUALENV ${PYTHON} "-mvenv")
set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/docs)
set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/docs)
set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html)
set(SPHINX_EXECUTABLE "./venv/bin/sphinx-build")
add_custom_command(
OUTPUT venv
COMMAND ${VIRTUALENV} venv
)
add_custom_command(
OUTPUT ${SPHINX_EXECUTABLE}
DEPENDS venv docs/requirements.txt
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/docs/requirements.txt docs-requirements.txt
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/docs ${CMAKE_CURRENT_BINARY_DIR}/docs
COMMAND ./venv/bin/python3 -mensurepip
COMMAND ./venv/bin/python3 -mpip install -r docs-requirements.txt --upgrade
MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/venv/bin/python
)
add_custom_command(
OUTPUT ${SPHINX_INDEX_FILE}
COMMAND ${SPHINX_EXECUTABLE} -b html ${SPHINX_SOURCE} ${SPHINX_BUILD}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py
${SPHINX_SOURCE}/index.rst
${SPHINX_SOURCE}/references.rst
${SPHINX_SOURCE}/getting_started.rst
${DOXYGEN_INDEX_FILE}
COMMENT "Generating documentation with Sphinx"
)
add_custom_target(
docs ALL
DEPENDS ${SPHINX_EXECUTABLE} ${SPHINX_INDEX_FILE}
)
endif()
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ int main(int argc, char* argv[]) {
return 1;
}

if (P4_AddLiteral(grammar, HW_ID, "HelloWorld", false) != P4_Ok) {
if (P4_AddLiteral(grammar, ENTRY, "HelloWorld", false) != P4_Ok) {
printf("Error: AddLiteral: MemoryError.\n");
return 1;
}
Expand Down Expand Up @@ -285,7 +285,7 @@ In this example we match an ASCII digit.
// ENTRY <- [0-9]

// lower upper
>> P4_AddLiteral(grammar, ENTRY, '0', '9');
>> P4_AddRange(grammar, ENTRY, '0', '9');
P4_Ok

>> P4_Source* source = P4_Source("0", ENTRY);
Expand All @@ -299,7 +299,7 @@ In this example we match the code points starting from `U+4E00` to `U+9FCC`, e.g
```c
// lower upper
>> P4_AddLiteral(grammar, ENTRY, 0x4E00, 0x9FFF);
>> P4_AddRange(grammar, ENTRY, 0x4E00, 0x9FFF);
P4_Ok
>> P4_Source* source = P4_Source("好", ENTRY);
Expand Down Expand Up @@ -841,12 +841,21 @@ If valgrind is installed, you can also run the test along with memory leak check
(build) $ make check
```

If you feel having a testing environment is hard, try docker:

```bash
$ docker run --rm -v `pwd`:/app -it ubuntu:latest bash
# apt-get install gcc gdb valgrind make cmake python3 python3-venv python3-pip doxygen
# mkdir -p build && cd build && cmake .. && make check
```

## Docs

Peppa PEG docs can be built via doxygen:

```bash
$ doxygen .doxygen.conf
(root) $ cd build
(build) $ rm -rf docs && make docs
```

The outputs are stored on `build/docs`.
Expand All @@ -857,6 +866,6 @@ The outputs are stored on `build/docs`.
* Write a Mustache Parser using Peppa PEG: [mustache.h](examples/mustache.h).
* Write a JSON Parser using Peppa PEG: [json.h](examples/json.h).

Made with ❤️ by [@soasme](https://github.com/soasme).
Made with ❤️ by [Ju](https://github.com/soasme).

[PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
6 changes: 6 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
- [ ] backrefs is not necessary if there is no BackReference in Sequence.
- [ ] A binary executable for display parsed results in JSON output. The executable can support general programming languages, such as Mustache, Python, JSON, YAML, etc. Some other programs can then takes the input from stdin and do some fancy work. `peppapeg --lang=py38 source.py`
- [ ] Create docs and push it to gh-pages branch.
- [ ] Add tutorials (json, mustache, ini) in docs.
- [ ] Add how-to guides in docs.
- [ ] Add doxygen references in docs.
- [ ] Add explanations in docs.
- [ ] Enable AddressSanitizer. Example: cJSON.
- [ ] Return NullError for CreatePositive/CreateNegative/....
- [x] Example JSON: rfc7159. Added in v1.4.0.
- [x] Auto generate documentation for functions and defined macros. Example: doxygen. Added in v1.4.0.
- [x] NeedLoosen, NeedSquash, NeedLift should be well-tested.
Expand Down
12 changes: 4 additions & 8 deletions .doxygen.conf → docs/.doxygen.conf
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.

OUTPUT_DIRECTORY = "build/docs"
OUTPUT_DIRECTORY = "docs"

# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
Expand Down Expand Up @@ -277,7 +277,7 @@ ALIASES =
# members will be omitted, etc.
# The default value is: NO.

OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_FOR_C = YES

# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
# Python sources only. Doxygen will then generate output that is more tailored
Expand Down Expand Up @@ -864,11 +864,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.

INPUT = README.md \
CHANGELOG.md \
ROADMAP.md \
peppapeg.h \
peppapeg.c
INPUT = ../

# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
Expand Down Expand Up @@ -2060,7 +2056,7 @@ MAN_LINKS = NO
# captures the structure of the code including all documentation.
# The default value is: NO.

GENERATE_XML = NO
GENERATE_XML = YES

# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
Expand Down
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
62 changes: 62 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))


# -- Project information -----------------------------------------------------

project = 'Peppa PEG'
copyright = '2021, Ju'
author = 'Ju'

# The full version, including alpha/beta/rc tags
release = '1.4.0'


# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'furo',
'breathe',
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'furo'

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# Breathe Configuration
breathe_projects = { "PeppaPEG": "../build/docs/xml/" }
breathe_default_project = 'PeppaPEG'
breathe_domain_by_extension = {"h": "c"}
100 changes: 100 additions & 0 deletions docs/development.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
Development
===========

Debug
-----

If you encounter segfaults or memory leaks, please check with your grammar implementation.
If you believe the issue origins from Peppa PEG and want to debug it, this document can be helpful.

Checking Segfaults
``````````````````

Assuming your operation system has gdb or lldb installed. Depending on your toolchain, use gdb if using gcc, use lldb if using llvm. After installing a debugger, you can create a simple program that recurs the segfault problem.

For example,

.. code-block:: c
#include "peppapeg.h"
int main() {
P4_Grammar* grammar = NULL;
printf("%lu\n", grammar->count);
}
Compile the program with debugging option enabled:

.. code-block:: console
$ gcc -g peppapeg.c debug.c
Run the program with a debugger. Gdb directive `run` can run the program, `where` can output where the program stops, and `p` can print the value of the variable.


.. code-block:: console
$ gdb ./a.out
(gdb) run
Starting program: /app/a.out
warning: Error disabling address space randomization: Operation not permitted
Program received signal SIGSEGV, Segmentation fault.
0x000055c62cc11e6e in main () at debug.c:4
4 printf("count: %u\n", grammar->count);
(gdb) where
#0 0x000055c62cc11e6e in main () at debug.c:4
(gdb) p grammar
$1 = (P4_Grammar *) 0x0
(gdb) quit
In this case, it's `0x0` so a segfault occurred. To fix it, create the grammar using `P4_CreateGrammar()`.

Checking Memory Leaks
`````````````````````

Assuming your operation system has gdb or lldb installed. Depending on your toolchain, use gdb if using gcc, use lldb if using llvm. After installing a debugger, you can create a simple program that recurs the segfault problem.

For example,

.. code-block:: c
#include "peppapeg.h"
int main() {
P4_Grammar* grammar = NULL;
printf("%lu\n", grammar->count);
}
Compile the program with debugging option enabled:

.. code-block:: console
$ gcc -g peppapeg.c debug.c
Run the program with a debugger. Gdb directive `run` can run the program, `where` can output where the program stops, and `p` can print the value of the variable.


.. code-block:: console
$ gdb ./a.out
(gdb) run
Starting program: /app/a.out
warning: Error disabling address space randomization: Operation not permitted
Program received signal SIGSEGV, Segmentation fault.
0x000055c62cc11e6e in main () at debug.c:4
4 printf("count: %u\n", grammar->count);
(gdb) where
#0 0x000055c62cc11e6e in main () at debug.c:4
(gdb) p grammar
$1 = (P4_Grammar *) 0x0
(gdb) quit
In this case, it's `0x0` so a segfault occurred. To fix it, create the grammar using `P4_CreateGrammar()`.

Conclusion
``````````

Programs are not always correct as human makes mistakes.
By crafting the debugging skills using tools like gdb/lldb/valgrind, we will follow the trace, pin point the problem, and fix the bug 🐛.


Loading

0 comments on commit f82f880

Please sign in to comment.