Compare commits
4
Commits
rust
..
fix-travis
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b33e47273e | ||
|
|
e2297ae915 | ||
|
|
97a043594d | ||
|
|
a2cbefdb34 |
@@ -41,7 +41,7 @@ jobs:
|
||||
python-version: '3.8'
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
|
||||
+143
-27
@@ -24,38 +24,89 @@ jobs:
|
||||
# Linux
|
||||
- name: linux-gcc-ubsan-ootree
|
||||
os: ubuntu-latest
|
||||
generator: Unix Makefiles
|
||||
build-type: Ubsan
|
||||
build-dir: .build
|
||||
cxx-flags: -O2
|
||||
skeleton: ${{ false }}
|
||||
|
||||
- name: linux-gcc-asan-ootree
|
||||
os: ubuntu-latest
|
||||
generator: Unix Makefiles
|
||||
build-type: Asan
|
||||
build-dir: .build
|
||||
cxx-flags: -O2
|
||||
skeleton: ${{ false }}
|
||||
|
||||
- name: linux-gcc-debug-ootree-skeleton
|
||||
os: ubuntu-latest
|
||||
generator: Unix Makefiles
|
||||
build-type: Debug
|
||||
build-dir: .build
|
||||
cxx-flags: -O2
|
||||
skeleton: ${{ true }}
|
||||
|
||||
- name: linux-gcc-debug-intree-m32-skeleton
|
||||
os: ubuntu-latest
|
||||
generator: Unix Makefiles
|
||||
build-type: Debug
|
||||
build-dir: .
|
||||
cxx-flags: -O2 -m32
|
||||
ld-flags: -m32
|
||||
skeleton: ${{ true }}
|
||||
|
||||
- name: linux-gcc-release-ootree-skeleton
|
||||
os: ubuntu-latest
|
||||
generator: Unix Makefiles
|
||||
build-type: Release
|
||||
build-dir: .build
|
||||
skeleton: ${{ true }}
|
||||
|
||||
# macOS
|
||||
- name: macos-clang-debug-ootree-skeleton
|
||||
os: macos-latest
|
||||
generator: Unix Makefiles
|
||||
build-type: Debug
|
||||
build-dir: .build
|
||||
cxx-flags: -O2
|
||||
skeleton: ${{ true }}
|
||||
|
||||
- name: macos-clang-debug-intree-skeleton
|
||||
os: macos-latest
|
||||
generator: Unix Makefiles
|
||||
build-type: Debug
|
||||
build-dir: .
|
||||
cxx-flags: -O2
|
||||
skeleton: ${{ true }}
|
||||
|
||||
- name: macos-clang-release-ootree-skeleton
|
||||
os: macos-latest
|
||||
generator: Unix Makefiles
|
||||
build-type: Release
|
||||
build-dir: .build
|
||||
skeleton: ${{ true }}
|
||||
|
||||
# Windows
|
||||
- name: windows-msvc-debug-ootree
|
||||
os: windows-latest
|
||||
generator: Visual Studio 16 2019
|
||||
build-type: Debug
|
||||
build-dir: .build
|
||||
skeleton: ${{ false }}
|
||||
|
||||
- name: windows-msvc-debug-intree
|
||||
os: windows-latest
|
||||
generator: Visual Studio 16 2019
|
||||
build-type: Debug
|
||||
build-dir: .
|
||||
skeleton: ${{ false }}
|
||||
|
||||
- name: windows-msvc-release-ootree
|
||||
os: windows-latest
|
||||
generator: Visual Studio 16 2019
|
||||
build-type: Release
|
||||
build-dir: .build
|
||||
skeleton: ${{ false }}
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
@@ -76,10 +127,16 @@ jobs:
|
||||
case ${{ runner.os }} in
|
||||
Linux*)
|
||||
sudo apt install gcc-multilib g++-multilib # for -m32
|
||||
echo "CC=gcc" >> $GITHUB_ENV
|
||||
echo "CXX=g++" >> $GITHUB_ENV
|
||||
;;
|
||||
macOS*)
|
||||
sudo xcode-select -switch /Applications/Xcode.app
|
||||
|
||||
echo "CC=$(xcrun -f clang)" >> $GITHUB_ENV
|
||||
echo "CXX=$(xcrun -f clang++)" >> $GITHUB_ENV
|
||||
echo "SDKROOT=$(xcodebuild -version -sdk macosx Path)" >> $GITHUB_ENV
|
||||
|
||||
echo "$(xcodebuild -version -sdk macosx Path)" >> $GITHUB_PATH
|
||||
;;
|
||||
Windows*)
|
||||
@@ -101,49 +158,108 @@ jobs:
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install docutils pygments
|
||||
|
||||
- name: Check Available Configure Presets
|
||||
run: cmake --list-presets
|
||||
- name: Prepare Configure Command
|
||||
id: configure-command
|
||||
run: |
|
||||
# Common CMake arguments
|
||||
args=( -S . -B ${{ matrix.build-dir }} )
|
||||
|
||||
# Generator's specific stuff.
|
||||
args+=( -G "${{ matrix.generator }}" )
|
||||
case "${{ matrix.generator }}" in
|
||||
'Visual Studio'*)
|
||||
args+=( -A x64 )
|
||||
;;
|
||||
*)
|
||||
# CMAKE_BUILD_TYPE is not used by multi-config build
|
||||
# types (e.g Visual Studio) at the configure time
|
||||
# thus we add it only for single-config build types
|
||||
args+=( -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} )
|
||||
;;
|
||||
esac
|
||||
|
||||
# CFLAGS, CXXFLAGS, LDFLAGS
|
||||
args+=( -DCMAKE_C_FLAGS="${{ matrix.cxx-flags }}" )
|
||||
args+=( -DCMAKE_CXX_FLAGS="${{ matrix.cxx-flags }}" )
|
||||
args+=( -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld-flags }}" )
|
||||
args+=( -DCMAKE_SHARED_LINKER_FLAGS="${{ matrix.ld-flags }}" )
|
||||
|
||||
# Quote each argument to prevent word split.
|
||||
echo "::set-output name=cmake::$(printf " '%s'" "${args[@]}")"
|
||||
|
||||
- name: Fast Configure
|
||||
run: cmake --preset=${{ matrix.name }}-fast
|
||||
run: |
|
||||
# Read prepared command into an array
|
||||
args=( ${{ steps.configure-command.outputs.cmake }} )
|
||||
|
||||
# Amend Build Options
|
||||
args+=( -DCMAKE_INSTALL_PREFIX="$(pwd)/install" )
|
||||
|
||||
# Disable some defaults for now to speed up the build as
|
||||
# they are not necessary in a minimal installation
|
||||
args+=( -DRE2C_BUILD_RE2GO=OFF )
|
||||
|
||||
# Print the resulting command line for debugging purposes
|
||||
printf "cmake" && printf " '%s'" "${args[@]}" && printf "\n"
|
||||
|
||||
# Run CMake, pass quoted arguments to prevent word split.
|
||||
printf " '%s'" "${args[@]}" | xargs cmake
|
||||
|
||||
- name: Fast Build
|
||||
run: cmake --build --preset=${{ matrix.name }}-fast
|
||||
run: cmake --build ${{ matrix.build-dir }} --config ${{ matrix.build-type }}
|
||||
|
||||
- name: Install
|
||||
run: cmake --build --preset=${{ matrix.name }}-fast --target install
|
||||
run: |
|
||||
cmake --build ${{ matrix.build-dir }} --config ${{ matrix.build-type }} --target install
|
||||
echo -e "Install tree:\n$(find install | sed 's/^/-- /')"
|
||||
|
||||
- name: Minimal Install Test
|
||||
working-directory: ./install/bin
|
||||
run: ./re2c --version
|
||||
|
||||
- name: Full Configure
|
||||
run: cmake --preset=${{ matrix.name }}-full
|
||||
run: |
|
||||
# Read prepared command into an array
|
||||
args=( ${{ steps.configure-command.outputs.cmake }} )
|
||||
|
||||
# Amend Build Options
|
||||
args+=( -DCMAKE_INSTALL_PREFIX="$(pwd)/install-2" -DRE2C_BUILD_RE2GO=ON -DRE2C_BUILD_LIBS=ON )
|
||||
args+=( -DRE2C_REBUILD_LEXERS=ON -DRE2C_FOR_BUILD="$(pwd)/install/bin/re2c" )
|
||||
|
||||
# Windows does not have a native 'man' and 'sed' commands.
|
||||
# Disabled until this https://github.com/skvadrik/re2c/issues/327
|
||||
# will be implemented
|
||||
case ${{ runner.os }} in
|
||||
Windows*)
|
||||
args+=( -DRE2C_REBUILD_DOCS=OFF )
|
||||
;;
|
||||
*)
|
||||
args+=( -DRE2C_REBUILD_DOCS=ON )
|
||||
;;
|
||||
esac
|
||||
|
||||
# Print the resulting command line for debugging purposes
|
||||
printf "cmake" && printf " '%s'" "${args[@]}" && printf "\n"
|
||||
|
||||
# Run CMake, pass quoted arguments to prevent word split.
|
||||
printf " '%s'" "${args[@]}" | xargs cmake
|
||||
|
||||
- name: Full Build
|
||||
run: |
|
||||
find src -name '*.re' | xargs touch
|
||||
cmake --build --preset=${{ matrix.name }}-full
|
||||
cmake --build ${{ matrix.build-dir }} --config ${{ matrix.build-type }}
|
||||
|
||||
- name: Run Main Test Suite
|
||||
run: cmake --build --preset=${{ matrix.name }}-full --target tests
|
||||
|
||||
- name: Get build dir
|
||||
id: build-info
|
||||
run: |
|
||||
if echo "${{ matrix.name }}" | grep -q "ootree"; then
|
||||
BUILD_DIR="$(pwd)/.build/${{ matrix.name }}-full"
|
||||
else
|
||||
BUILD_DIR="$(pwd)"
|
||||
fi
|
||||
|
||||
echo "::set-output name=BUILD_DIR::$BUILD_DIR"
|
||||
|
||||
- name: Run Skeleton Tests
|
||||
if: "contains(matrix.name, 'skeleton')"
|
||||
- name: Test
|
||||
# Remove the following line after fix Windows tests
|
||||
working-directory: ${{ steps.build-info.outputs.BUILD_DIR }}
|
||||
run: python run_tests.py --skeleton
|
||||
working-directory: ${{ matrix.build-dir }}
|
||||
run: |
|
||||
# main test suite
|
||||
cmake --build . --target check
|
||||
|
||||
# skeleton tests (if enabled)
|
||||
if [[ "x${{ matrix.skeleton }}" == "xtrue" ]] ; then
|
||||
python run_tests.py --skeleton
|
||||
fi
|
||||
|
||||
- name: Archive test artifacts
|
||||
# Run this step only if tests failed (otherwise there is nothing to upload).
|
||||
@@ -154,7 +270,7 @@ jobs:
|
||||
# use a different name per job.
|
||||
name: test-${{ matrix.name }}
|
||||
# Tests run in a temporary directory that has a name test_<timestamp>.
|
||||
path: ${{ steps.build-info.outputs.BUILD_DIR }}/test_[0-9]*
|
||||
path: ${{ matrix.build-dir }}/test_[0-9]*
|
||||
# Artifacts are retained for 90 days by default.
|
||||
# In fact, we don't need such long period.
|
||||
# In fact we don't need such long period.
|
||||
retention-days: 30
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
/test_*
|
||||
/.build*
|
||||
|
||||
# Ignore user defined CMake presets
|
||||
CMakeUserPresets.json
|
||||
|
||||
# The files autogenerated by automake.
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
|
||||
+30
-20
@@ -1,5 +1,9 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- freebsd
|
||||
|
||||
# use Ubuntu 20.04 (Focal Fossa) that defaults to Python 3
|
||||
dist: focal
|
||||
|
||||
@@ -10,25 +14,35 @@ compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
# preinstalled packages
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- bison
|
||||
- python3-docutils
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then apt install bison python3-docutils ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then pkg install textproc/py-docutils; fi
|
||||
|
||||
# configurations: cmake/autotools, in-tree/out-of-tree, release/debug, etc.
|
||||
env:
|
||||
- CMAKE=no BUILD_DIR=. CONFIG_DIR=. COMMON_FLAGS="-O2 -g"
|
||||
- CMAKE=no BUILD_DIR=.build CONFIG_DIR=.. CONFIG_FLAGS="--enable-debug" COMMON_FLAGS="-O2 -g"
|
||||
- CMAKE=yes BUILD_DIR=. CONFIG_DIR=. BUILD_TYPE=Debug COMMON_FLAGS="-O2 -g"
|
||||
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Debug COMMON_FLAGS="-O2 -g" SKELETON=yes
|
||||
- CMAKE=no BUILD_DIR=. CONFIG_DIR=. COMMON_FLAGS="-O2 -g"
|
||||
- CMAKE=no BUILD_DIR=.build CONFIG_DIR=.. COMMON_FLAGS="-O2 -g"
|
||||
- CMAKE=yes BUILD_DIR=. CONFIG_DIR=. BUILD_TYPE=Debug
|
||||
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Release
|
||||
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Debug COMMON_FLAGS="-O2 -g -fsanitize=address"
|
||||
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Debug COMMON_FLAGS="-O2 -g -fsanitize=undefined"
|
||||
- CMAKE=yes BUILD_DIR=. CONFIG_DIR=. BUILD_TYPE=Asan
|
||||
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Ubsan
|
||||
|
||||
jobs:
|
||||
exclude:
|
||||
- os: freebsd
|
||||
env: BUILD_TYPE=Asan
|
||||
- os: freebsd
|
||||
env: BUILD_TYPE=Ubsan
|
||||
|
||||
script:
|
||||
- |
|
||||
function ncpus() {
|
||||
if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
sysctl -n hw.ncpu
|
||||
else
|
||||
nproc
|
||||
fi
|
||||
}
|
||||
function run_cmake() {
|
||||
cmake \
|
||||
-B . -S ${CONFIG_DIR} \
|
||||
@@ -41,7 +55,6 @@ script:
|
||||
}
|
||||
function run_configure() {
|
||||
${CONFIG_DIR}/configure \
|
||||
${CONFIG_FLAGS} \
|
||||
CFLAGS="${COMMON_FLAGS}" \
|
||||
CXXFLAGS="${COMMON_FLAGS}" \
|
||||
LDFLAGS="${COMMON_FLAGS}" \
|
||||
@@ -56,7 +69,7 @@ script:
|
||||
mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
run_configure --prefix="$(pwd)/install"
|
||||
fi
|
||||
- make -j$(nproc)
|
||||
- make -j$(ncpus)
|
||||
- make install
|
||||
- |
|
||||
if [ x${CMAKE} = "xyes" ]; then
|
||||
@@ -75,10 +88,7 @@ script:
|
||||
RE2C_FOR_BUILD="$(pwd)/install/bin/re2c"
|
||||
fi
|
||||
- find ${CONFIG_DIR}/src -name '*.re' | xargs touch
|
||||
- make -j$(nproc)
|
||||
- make -j$(ncpus)
|
||||
- |
|
||||
if [ x${SKELETON} = "xyes" ]; then
|
||||
./run_tests.py --skeleton
|
||||
else
|
||||
make -j$(nproc) check VERBOSE=1
|
||||
fi
|
||||
make -j$(ncpus) check VERBOSE=1
|
||||
./run_tests.py --skeleton
|
||||
|
||||
@@ -1,45 +1,6 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
----
|
||||
2.2x
|
||||
----
|
||||
|
||||
2.2 (2021-08-01)
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- Added named blocks and block lists in directives.
|
||||
|
||||
- Added local blocks ``/*!local:re2c ... */``.
|
||||
|
||||
- Added in-block ``!include`` directive.
|
||||
|
||||
- Added in-block ``!use`` directive.
|
||||
|
||||
- Allowed reusable blocks without ``-r --reusable`` option.
|
||||
|
||||
- Allowed customizing the generated code with configurations for directives
|
||||
``max:re2c``, ``maxnmatch:re2c``, ``stags:re2c``, ``mtags:re2c`` and
|
||||
``types:re2c`` (see directive descriptions for details).
|
||||
|
||||
- Forbid arbitrary text at the end of ``max:re2c`` directive. This may break
|
||||
backwards compatibility, although it is unlikely that this was used by anyone.
|
||||
The change was necessary in order to allow customization of the generated code
|
||||
with configurations.
|
||||
|
||||
- Deprecated configurations ``flags:i``, ``flags:no-debug-info`` in favour of
|
||||
the global options ``-i``, ``--no-debug-info``.
|
||||
|
||||
- Reimplemented re2c test runner in Python (thanks to
|
||||
`Serghei Iakovlev <https://github.com/sergeyklay>`_). Improved integration
|
||||
with GitHub Actions.
|
||||
|
||||
- Changes in the experimental libre2c library: added new algorithms that
|
||||
construct t-string or extract submatch on all repetitions; added TDFA
|
||||
benchmark written in Java by Angelo Borsotti.
|
||||
|
||||
- Updated documentation.
|
||||
|
||||
----
|
||||
2.1x
|
||||
----
|
||||
|
||||
+2
-5
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(re2c VERSION 2.2 HOMEPAGE_URL "https://re2c.org/")
|
||||
project(re2c VERSION 2.1.1 HOMEPAGE_URL "https://re2c.org/")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
@@ -232,6 +232,7 @@ re2c_bootstrap_parser("src/parse/parser.ypp" "src/parse/parser.cc" "src/parse/pa
|
||||
# docs
|
||||
set(re2c_docs_sources
|
||||
"${re2c_manpage_source}"
|
||||
"doc/manual/api/api.rst_"
|
||||
"doc/manual/api/interface.rst_"
|
||||
"doc/manual/conditions/conditions.rst_"
|
||||
"doc/manual/configurations/configurations.rst_"
|
||||
@@ -261,10 +262,6 @@ set(re2c_docs_sources
|
||||
"doc/manual/submatch/submatch_example_stags_fill.rst_"
|
||||
"doc/manual/submatch/submatch.rst_"
|
||||
"doc/manual/syntax/syntax.rst_"
|
||||
"doc/manual/syntax/api1.rst_"
|
||||
"doc/manual/syntax/api2_c.rst_"
|
||||
"doc/manual/syntax/api2_go.rst_"
|
||||
"doc/manual/syntax/api3.rst_"
|
||||
"doc/manual/warnings/warnings_general.rst_"
|
||||
"doc/manual/warnings/warnings_list.rst_"
|
||||
"examples/c/01_basic.re"
|
||||
|
||||
@@ -1,471 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 21,
|
||||
"patch": 1
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "default-full-configuration",
|
||||
"hidden": true,
|
||||
"installDir": "${sourceDir}/install-2",
|
||||
"cacheVariables": {
|
||||
"RE2C_BUILD_RE2GO": true,
|
||||
"RE2C_BUILD_LIBS": true,
|
||||
"RE2C_REBUILD_LEXERS": true,
|
||||
"RE2C_REBUILD_DOCS": true,
|
||||
"RE2C_FOR_BUILD": "${sourceDir}/install/bin/re2c"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "linux-config-base",
|
||||
"hidden": true,
|
||||
"generator": "Unix Makefiles",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "gcc",
|
||||
"CMAKE_CXX_COMPILER": "g++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-ubsan-ootree-fast",
|
||||
"displayName": "Linux x86_64: GCC / Ubsan / Out of tree (fast)",
|
||||
"inherits": "linux-config-base",
|
||||
"binaryDir": "${sourceDir}/.build/${presetName}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Ubsan",
|
||||
"CMAKE_C_FLAGS": "-O2",
|
||||
"CMAKE_CXX_FLAGS": "-O2",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-ubsan-ootree-full",
|
||||
"displayName": "Linux x86_64: GCC / Ubsan / Out of tree (full)",
|
||||
"inherits": ["default-full-configuration", "linux-gcc-ubsan-ootree-fast"]
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-asan-ootree-fast",
|
||||
"displayName": "Linux x86_64: GCC / Asan / Out of tree (fast)",
|
||||
"inherits": "linux-config-base",
|
||||
"binaryDir": "${sourceDir}/.build/${presetName}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Asan",
|
||||
"CMAKE_C_FLAGS": "-O2",
|
||||
"CMAKE_CXX_FLAGS": "-O2",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-asan-ootree-full",
|
||||
"displayName": "Linux x86_64: GCC / Asan / Out of tree (full)",
|
||||
"inherits": ["default-full-configuration", "linux-gcc-asan-ootree-fast"]
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug-ootree-skeleton-fast",
|
||||
"displayName": "Linux x86_64: GCC / Debug / Skeleton / Out of tree (fast)",
|
||||
"inherits": "linux-config-base",
|
||||
"binaryDir": "${sourceDir}/.build/${presetName}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_C_FLAGS": "-O2",
|
||||
"CMAKE_CXX_FLAGS": "-O2",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug-ootree-skeleton-full",
|
||||
"displayName": "Linux x86_64: GCC / Debug / Skeleton / Out of tree (full)",
|
||||
"inherits": ["default-full-configuration", "linux-gcc-debug-ootree-skeleton-fast"]
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug-intree-m32-skeleton-fast",
|
||||
"displayName": "Linux x86: GCC / Debug / Skeleton / In tree (fast)",
|
||||
"inherits": "linux-config-base",
|
||||
"binaryDir": "${sourceDir}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"architecture": {
|
||||
"value": "x86",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_C_FLAGS": "-O2 -m32",
|
||||
"CMAKE_CXX_FLAGS": "-O2 -m32",
|
||||
"CMAKE_EXE_LINKER_FLAGS": "-m32",
|
||||
"CMAKE_SHARED_LINKER_FLAGS": "-m32",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug-intree-m32-skeleton-full",
|
||||
"displayName": "Linux x86: GCC / Debug / Skeleton / In tree (full)",
|
||||
"inherits": ["default-full-configuration", "linux-gcc-debug-intree-m32-skeleton-fast"]
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-release-ootree-skeleton-fast",
|
||||
"displayName": "Linux x86_64: GCC / Release / Skeleton / Out of tree (fast)",
|
||||
"inherits": "linux-config-base",
|
||||
"binaryDir": "${sourceDir}/.build/${presetName}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-release-ootree-skeleton-full",
|
||||
"displayName": "Linux x86_64: GCC / Release / Skeleton / Out of tree (full)",
|
||||
"inherits": ["default-full-configuration", "linux-gcc-release-ootree-skeleton-fast"]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "macos-config-base",
|
||||
"hidden": true,
|
||||
"generator": "Unix Makefiles",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
},
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-debug-ootree-skeleton-fast",
|
||||
"displayName": "macOS x86_64: Clang / Debug / Skeleton / Out of tree (fast)",
|
||||
"inherits": "macos-config-base",
|
||||
"binaryDir": "${sourceDir}/.build/${presetName}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_C_FLAGS": "-O2",
|
||||
"CMAKE_CXX_FLAGS": "-O2",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-debug-ootree-skeleton-full",
|
||||
"displayName": "macOS x86_64: Clang / Debug / Skeleton / Out of tree (full)",
|
||||
"inherits": ["default-full-configuration", "macos-clang-debug-ootree-skeleton-fast"]
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-debug-intree-skeleton-fast",
|
||||
"displayName": "macOS x86_64: Clang / Debug / Skeleton / In tree (fast)",
|
||||
"inherits": "macos-config-base",
|
||||
"binaryDir": "${sourceDir}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_C_FLAGS": "-O2",
|
||||
"CMAKE_CXX_FLAGS": "-O2",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-debug-intree-skeleton-full",
|
||||
"displayName": "macOS x86_64: Clang / Debug / Skeleton / In tree (full)",
|
||||
"inherits": ["default-full-configuration", "macos-clang-debug-intree-skeleton-fast"]
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-release-ootree-skeleton-fast",
|
||||
"displayName": "macOS x86_64: CLang / Release / Skeleton / Out of tree (fast)",
|
||||
"inherits": "macos-config-base",
|
||||
"binaryDir": "${sourceDir}/.build/${presetName}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-release-ootree-skeleton-full",
|
||||
"displayName": "macOS x86_64: CLang / Release / Skeleton / Out of tree (full)",
|
||||
"inherits": ["default-full-configuration", "macos-clang-release-ootree-skeleton-fast"]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "windows-config-base",
|
||||
"hidden": true,
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "cl",
|
||||
"CMAKE_CXX_COMPILER": "cl"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-debug-ootree-fast",
|
||||
"displayName": "Windows x86_64: MSVC / Debug / Out of tree (fast)",
|
||||
"inherits": "windows-config-base",
|
||||
"binaryDir": "${sourceDir}/.build/${presetName}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-debug-ootree-full",
|
||||
"displayName": "Windows x86_64: MSVC / Debug / Out of tree (full)",
|
||||
"inherits": ["default-full-configuration", "windows-msvc-debug-ootree-fast"],
|
||||
"cacheVariables": {
|
||||
"RE2C_REBUILD_DOCS": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-debug-intree-fast",
|
||||
"displayName": "Windows x86_64: MSVC / Debug / In tree (fast)",
|
||||
"inherits": "windows-config-base",
|
||||
"binaryDir": "${sourceDir}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-debug-intree-full",
|
||||
"displayName": "Windows x86_64: MSVC / Debug / In tree (full)",
|
||||
"inherits": ["default-full-configuration", "windows-msvc-debug-intree-fast"],
|
||||
"cacheVariables": {
|
||||
"RE2C_REBUILD_DOCS": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-release-ootree-fast",
|
||||
"displayName": "Windows x86_64: MSVC / Release / Out of tree (fast)",
|
||||
"inherits": "windows-config-base",
|
||||
"binaryDir": "${sourceDir}/.build/${presetName}",
|
||||
"installDir": "${sourceDir}/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"RE2C_BUILD_RE2GO": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-release-ootree-full",
|
||||
"displayName": "Windows x86_64: MSVC / Release / Out of tree (full)",
|
||||
"inherits": ["default-full-configuration", "windows-msvc-release-ootree-fast"],
|
||||
"cacheVariables": {
|
||||
"RE2C_REBUILD_DOCS": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "linux-build-base",
|
||||
"hidden": true,
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-ubsan-ootree-fast",
|
||||
"displayName": "Linux x86_64: GCC / Ubsan / Out of tree (fast)",
|
||||
"configurePreset": "linux-gcc-ubsan-ootree-fast",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Ubsan"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-ubsan-ootree-full",
|
||||
"displayName": "Linux x86_64: GCC / Ubsan / Out of tree (full)",
|
||||
"configurePreset": "linux-gcc-ubsan-ootree-full",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Ubsan"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-asan-ootree-fast",
|
||||
"displayName": "Linux x86_64: GCC / Asan / Out of tree (fast)",
|
||||
"configurePreset": "linux-gcc-asan-ootree-fast",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Asan"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-asan-ootree-full",
|
||||
"displayName": "Linux x86_64: GCC / Asan / Out of tree (full)",
|
||||
"configurePreset": "linux-gcc-asan-ootree-full",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Asan"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug-ootree-skeleton-fast",
|
||||
"displayName": "Linux x86_64: GCC / Debug / Skeleton / Out of tree (fast)",
|
||||
"configurePreset": "linux-gcc-debug-ootree-skeleton-fast",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug-ootree-skeleton-full",
|
||||
"displayName": "Linux x86_64: GCC / Debug / Skeleton / Out of tree (full)",
|
||||
"configurePreset": "linux-gcc-debug-ootree-skeleton-full",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug-intree-m32-skeleton-fast",
|
||||
"displayName": "Linux x86: GCC / Debug / Skeleton / In tree (fast)",
|
||||
"configurePreset": "linux-gcc-debug-intree-m32-skeleton-fast",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug-intree-m32-skeleton-full",
|
||||
"displayName": "Linux x86: GCC / Debug / Skeleton / In tree (full)",
|
||||
"configurePreset": "linux-gcc-debug-intree-m32-skeleton-full",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-release-ootree-skeleton-fast",
|
||||
"displayName": "Linux x86_64: GCC / Release / Skeleton / Out of tree (fast)",
|
||||
"configurePreset": "linux-gcc-release-ootree-skeleton-fast",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-release-ootree-skeleton-full",
|
||||
"displayName": "Linux x86_64: GCC / Release / Skeleton / Out of tree (full)",
|
||||
"configurePreset": "linux-gcc-release-ootree-skeleton-full",
|
||||
"inherits": "linux-build-base",
|
||||
"configuration": "Release"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "macos-build-base",
|
||||
"hidden": true,
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-debug-ootree-skeleton-fast",
|
||||
"displayName": "macOS x86_64: Clang / Debug / Skeleton / Out of tree (fast)",
|
||||
"configurePreset": "macos-clang-debug-ootree-skeleton-fast",
|
||||
"inherits": "macos-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-debug-ootree-skeleton-full",
|
||||
"displayName": "macOS x86_64: Clang / Debug / Skeleton / Out of tree (full)",
|
||||
"configurePreset": "macos-clang-debug-ootree-skeleton-full",
|
||||
"inherits": "macos-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-debug-intree-skeleton-fast",
|
||||
"displayName": "macOS x86_64: Clang / Debug / Skeleton / In tree (fast)",
|
||||
"configurePreset": "macos-clang-debug-intree-skeleton-fast",
|
||||
"inherits": "macos-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-debug-intree-skeleton-full",
|
||||
"displayName": "macOS x86_64: Clang / Debug / Skeleton / In tree (full)",
|
||||
"configurePreset": "macos-clang-debug-intree-skeleton-full",
|
||||
"inherits": "macos-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-release-ootree-skeleton-fast",
|
||||
"displayName": "macOS x86_64: CLang / Release / Skeleton / Out of tree (fast)",
|
||||
"configurePreset": "macos-clang-release-ootree-skeleton-fast",
|
||||
"inherits": "macos-build-base",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "macos-clang-release-ootree-skeleton-full",
|
||||
"displayName": "macOS x86_64: CLang / Release / Skeleton / Out of tree (full)",
|
||||
"configurePreset": "macos-clang-release-ootree-skeleton-full",
|
||||
"inherits": "macos-build-base",
|
||||
"configuration": "Release"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "windows-build-base",
|
||||
"hidden": true,
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-debug-ootree-fast",
|
||||
"displayName": "Windows x86_64: MSVC / Debug / Out of tree (fast)",
|
||||
"configurePreset": "windows-msvc-debug-ootree-fast",
|
||||
"inherits": "windows-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-debug-ootree-full",
|
||||
"displayName": "Windows x86_64: MSVC / Debug / Out of tree (full)",
|
||||
"configurePreset": "windows-msvc-debug-ootree-full",
|
||||
"inherits": "windows-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-debug-intree-fast",
|
||||
"displayName": "Windows x86_64: MSVC / Debug / In tree (fast)",
|
||||
"configurePreset": "windows-msvc-debug-intree-fast",
|
||||
"inherits": "windows-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-debug-intree-full",
|
||||
"displayName": "Windows x86_64: MSVC / Debug / In tree (full)",
|
||||
"configurePreset": "windows-msvc-debug-intree-full",
|
||||
"inherits": "windows-build-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-release-ootree-fast",
|
||||
"displayName": "Windows x86_64: MSVC / Release / Out of tree (fast)",
|
||||
"configurePreset": "windows-msvc-release-ootree-fast",
|
||||
"inherits": "windows-build-base",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "windows-msvc-release-ootree-full",
|
||||
"displayName": "Windows x86_64: MSVC / Release / Out of tree (full)",
|
||||
"configurePreset": "windows-msvc-release-ootree-full",
|
||||
"inherits": "windows-build-base",
|
||||
"configuration": "Release"
|
||||
}
|
||||
]
|
||||
}
|
||||
+1
-4
@@ -215,6 +215,7 @@ re2c_CUSTOM = \
|
||||
# docs
|
||||
re2c_SRC_DOC = doc/manpage.rst
|
||||
re2c_SRC_DOC_EXT = \
|
||||
doc/manual/api/api.rst_ \
|
||||
doc/manual/api/interface.rst_ \
|
||||
doc/manual/conditions/conditions.rst_ \
|
||||
doc/manual/configurations/configurations.rst_ \
|
||||
@@ -244,10 +245,6 @@ re2c_SRC_DOC_EXT = \
|
||||
doc/manual/submatch/submatch_example_stags_fill.rst_ \
|
||||
doc/manual/submatch/submatch.rst_ \
|
||||
doc/manual/syntax/syntax.rst_ \
|
||||
doc/manual/syntax/api1.rst_ \
|
||||
doc/manual/syntax/api2_c.rst_ \
|
||||
doc/manual/syntax/api2_go.rst_ \
|
||||
doc/manual/syntax/api3.rst_ \
|
||||
doc/manual/warnings/warnings_general.rst_ \
|
||||
doc/manual/warnings/warnings_list.rst_ \
|
||||
examples/c/01_basic.re \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
bench_submatch_dfa_jit_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 -O3 -I $(top_srcdir)
|
||||
bench_submatch_dfa_jit_LDFLAGS = $(LDFLAGS_RE2) -lbenchmark -lpthread
|
||||
bench_submatch_dfa_jit_LDFLAGS = $(LDFLAGS_RE2) -lbenchmark
|
||||
bench_submatch_dfa_jit_LDADD = $(top_builddir)/libre2c.la
|
||||
|
||||
noinst_PROGRAMS = bench_submatch_dfa_jit
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
bench_submatch_nfa_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 -O3 -I $(top_srcdir)
|
||||
bench_submatch_nfa_LDFLAGS = $(LDFLAGS_RE2) -lbenchmark -lpthread
|
||||
bench_submatch_nfa_LDFLAGS = $(LDFLAGS_RE2) -lbenchmark
|
||||
bench_submatch_nfa_LDADD = $(top_builddir)/libre2c.la
|
||||
|
||||
noinst_PROGRAMS = bench_submatch_nfa
|
||||
|
||||
+365
-457
File diff suppressed because it is too large
Load Diff
+366
-464
File diff suppressed because it is too large
Load Diff
+1425
-1467
File diff suppressed because it is too large
Load Diff
+409
-415
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* Generated by re2c 2.2 on Mon Nov 22 21:59:42 2021 */
|
||||
/* Generated by re2c 2.1.1 on Fri Jul 16 08:52:38 2021 */
|
||||
|
||||
#ifndef _RE2C_PARSE_LEX_
|
||||
#define _RE2C_PARSE_LEX_
|
||||
|
||||
+716
-729
File diff suppressed because it is too large
Load Diff
+10
-21
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
@@ -14,33 +14,22 @@ autoreconf -i -W all
|
||||
# try to be portable on various MAKEs
|
||||
for make_prog in make bmake
|
||||
do
|
||||
rm -rf "$builddir"
|
||||
mkdir "$builddir"
|
||||
cd "$builddir"
|
||||
|
||||
# stage 1
|
||||
mkdir stage1
|
||||
../configure --prefix "$(pwd)/stage1" \
|
||||
&& $make_prog \
|
||||
&& $make_prog install
|
||||
|
||||
# stage 2
|
||||
rm -rf $builddir
|
||||
mkdir $builddir
|
||||
cd $builddir
|
||||
# 'make' implies 'make docs'; running both in parallel may cause data races
|
||||
# configure without --enable-debug, this is the release binary
|
||||
../configure \
|
||||
--enable-docs \
|
||||
--enable-libs \
|
||||
--enable-lexers RE2C_FOR_BUILD="$(pwd)/stage1/bin/re2c" \
|
||||
&& $make_prog bootstrap -j"$(nproc)" \
|
||||
&& $make_prog distcheck -j"$(nproc)"
|
||||
../configure --enable-docs --enable-libs \
|
||||
&& $make_prog bootstrap -j$(nproc) \
|
||||
&& $make_prog distcheck -j$(nproc)
|
||||
cd ..
|
||||
done
|
||||
|
||||
# test that the release tarball builds with CMake
|
||||
cd "$builddir"
|
||||
cd $builddir
|
||||
tarball=$(find . -name 're2c-*.tar.xz')
|
||||
test -f "$tarball" && tar -xf "$tarball" \
|
||||
|| { echo "*** failed to extract tarball ***" && exit 1; }
|
||||
cd "${tarball%.tar.xz}" && cmake . && make -j"$(nproc)" && cd .. \
|
||||
|| { echo "*** failed to find tarball ***" && exit 1; }
|
||||
cd "${tarball%.tar.xz}" && cmake . && make -j$(nproc) && cd .. \
|
||||
|| { echo "*** failed to build with cmake ***" && exit 1; }
|
||||
cd ..
|
||||
|
||||
@@ -9,11 +9,9 @@ lang="$3"
|
||||
|
||||
case $lang in
|
||||
c) ext=h
|
||||
lang_name=C
|
||||
disclaimer=
|
||||
;;
|
||||
go) ext=go
|
||||
lang_name=Go
|
||||
disclaimer="Note: This manual includes examples for Go, but it refers to re2c (rather than re2go) as the name of the program in general."
|
||||
;;
|
||||
*) echo "*** $0: unknown lang: $lang"
|
||||
@@ -22,7 +20,6 @@ case $lang in
|
||||
esac
|
||||
|
||||
LANG=C sed \
|
||||
-e "s/RE2C_LANG_NAME/$lang_name/g" \
|
||||
-e "s/RE2C_LANG/$lang/g" \
|
||||
-e "s/RE2C_HEADER_EXT/$ext/g" \
|
||||
-e "s/RE2C_DISCLAIMER/$disclaimer/g" \
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
function(re2c_gen_manpage source target bootstrap lang)
|
||||
if(RE2C_REBUILD_DOCS)
|
||||
get_filename_component(targetdir "${target}" DIRECTORY)
|
||||
set(source_l "${source}.${lang}")
|
||||
add_custom_command(
|
||||
OUTPUT "${target}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory ${targetdir}
|
||||
COMMAND "${re2c_splitman}" "${source}" "${source_l}" "${lang}"
|
||||
COMMAND "${RST2MAN}" --tab-width=4 "${source_l}" "${target}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${target}" "${bootstrap}"
|
||||
@@ -25,10 +23,8 @@ endfunction()
|
||||
|
||||
function(re2c_gen_help source target bootstrap)
|
||||
if(RE2C_REBUILD_DOCS)
|
||||
get_filename_component(targetdir "${target}" DIRECTORY)
|
||||
add_custom_command(
|
||||
OUTPUT "${target}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory ${targetdir}
|
||||
COMMAND "${RST2MAN}" "${source}" "${target}.1"
|
||||
COMMAND "${re2c_genhelp}" "${target}.1" "${target}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${target}" "${bootstrap}"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
AC_INIT([re2c],[2.2],[re2c-general@lists.sourceforge.net])
|
||||
AC_INIT([re2c],[2.1.1],[re2c-general@lists.sourceforge.net])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects dist-xz dist-lzip no-dist-gzip])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
+36
-26
@@ -2,9 +2,9 @@
|
||||
re2c
|
||||
++++
|
||||
|
||||
================================================
|
||||
generate fast lexical analyzers for C/C++ and Go
|
||||
================================================
|
||||
===================================
|
||||
compile regular expressions to code
|
||||
===================================
|
||||
|
||||
:Manual section: 1
|
||||
|
||||
@@ -15,55 +15,65 @@ SYNOPSIS
|
||||
|
||||
``re2go [OPTIONS] INPUT [-o OUTPUT]``
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
|
||||
re2c is a tool for generating fast lexical analyzers for C, C++ and Go.
|
||||
|
||||
RE2C_DISCLAIMER
|
||||
|
||||
Introduction
|
||||
============
|
||||
Syntax
|
||||
======
|
||||
.. include:: @top_srcdir@/doc/manual/syntax/syntax.rst_
|
||||
.. include:: @top_srcdir@/doc/manual/syntax/api1.rst_
|
||||
.. include:: @top_srcdir@/doc/manual/syntax/api2_RE2C_LANG.rst_
|
||||
.. include:: @top_srcdir@/doc/manual/syntax/api3.rst_
|
||||
|
||||
Example
|
||||
EXAMPLE
|
||||
=======
|
||||
|
||||
Here is a simple re2c program:
|
||||
Input file
|
||||
----------
|
||||
|
||||
.. include:: @top_srcdir@/examples/RE2C_LANG/01_basic.re
|
||||
:literal:
|
||||
:code: RE2C_LANG
|
||||
|
||||
The generated code looks like this:
|
||||
Output file
|
||||
-----------
|
||||
|
||||
.. include:: @top_srcdir@/examples/RE2C_LANG/01_basic.RE2C_LANG
|
||||
:literal:
|
||||
:code: RE2C_LANG
|
||||
|
||||
Command-line options
|
||||
====================
|
||||
Command-line interface consists of options and warnings.
|
||||
Some of the options have corresponding `configurations`_,
|
||||
others are global and cannot be changed after re2c starts reading the input file.
|
||||
Debug options generally require building re2c in debug configuration.
|
||||
Internal options are useful for experimenting with the algorithms used in re2c.
|
||||
Warnings can be invividually enabled, disabled and turned into an error.
|
||||
|
||||
Options
|
||||
=======
|
||||
.. include:: @top_srcdir@/doc/manual/options/options.rst_
|
||||
|
||||
Debug options
|
||||
-------------
|
||||
.. include:: @top_srcdir@/doc/manual/options/debug.rst_
|
||||
|
||||
Internal options
|
||||
----------------
|
||||
.. include:: @top_srcdir@/doc/manual/options/internal.rst_
|
||||
|
||||
Warnings
|
||||
--------
|
||||
.. include:: @top_srcdir@/doc/manual/warnings/warnings_general.rst_
|
||||
.. include:: @top_srcdir@/doc/manual/warnings/warnings_list.rst_
|
||||
|
||||
Blocks and directives
|
||||
=====================
|
||||
.. include:: @top_srcdir@/doc/manual/directives/directives.rst_
|
||||
Program interface
|
||||
=================
|
||||
.. include:: @top_srcdir@/doc/manual/api/api.rst_
|
||||
|
||||
Interface primitives
|
||||
====================
|
||||
API primitives
|
||||
--------------
|
||||
.. include:: @top_srcdir@/doc/manual/api/interface.rst_
|
||||
|
||||
Directives
|
||||
----------
|
||||
.. include:: @top_srcdir@/doc/manual/directives/directives.rst_
|
||||
|
||||
Configurations
|
||||
==============
|
||||
--------------
|
||||
.. include:: @top_srcdir@/doc/manual/configurations/configurations.rst_
|
||||
|
||||
Regular expressions
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
Re2c has a flexible interface that gives the user both the freedom and the responsibility
|
||||
to define how the generated code interacts with the outer program.
|
||||
There are two major options:
|
||||
|
||||
- **Pointer API**.
|
||||
It is also called "default API", since it was historically the first, and for a long time the only one.
|
||||
This is a more restricted API based on C pointer arithmetics.
|
||||
It consists of pointer-like primitives ``YYCURSOR``, ``YYMARKER``,
|
||||
``YYCTXMARKER`` and ``YYLIMIT``, which are normally defined as pointers
|
||||
of type ``YYCTYPE*``.
|
||||
Pointer API is enabled by default for the C backend,
|
||||
and it cannot be used with other backends that do not have pointer arithmetics.
|
||||
|
||||
|
|
||||
|
||||
- **Generic API**.
|
||||
This is a less restricted API that does not assume pointer semantics.
|
||||
It consists of primitives
|
||||
``YYPEEK``,
|
||||
``YYSKIP``,
|
||||
``YYBACKUP``,
|
||||
``YYBACKUPCTX``,
|
||||
``YYSTAGP``,
|
||||
``YYSTAGN``,
|
||||
``YYMTAGP``,
|
||||
``YYMTAGN``,
|
||||
``YYRESTORE``,
|
||||
``YYRESTORECTX``,
|
||||
``YYRESTORETAG``,
|
||||
``YYSHIFT``,
|
||||
``YYSHIFTSTAG``,
|
||||
``YYSHIFTMTAG`` and
|
||||
``YYLESSTHAN``.
|
||||
For the C backend generic API is enabled with ``--input custom`` option or
|
||||
``re2c:flags:input = custom;`` configuration;
|
||||
for the Go backend it is enabled by default.
|
||||
Generic API was added in version 0.14.
|
||||
It is intentionally designed to give the user as much freedom as possible
|
||||
in redefining the input model and the semantics of different actions performed
|
||||
by the generated code. As an example, one can override ``YYPEEK`` to check for
|
||||
the end of input before reading the input character, or do some logging, etc.
|
||||
|
||||
Generic API has two styles:
|
||||
|
||||
- **Function-like**.
|
||||
This style is enabled with ``re2c:api:style = functions;`` configuration,
|
||||
and it is the default for C backend. In this style API primitives should be
|
||||
defined as functions or macros with parentheses, accepting the necessary
|
||||
arguments. For example, in C the default pointer API can be defined in
|
||||
function-like style generic API as follows:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#define YYPEEK() *YYCURSOR
|
||||
#define YYSKIP() ++YYCURSOR
|
||||
#define YYBACKUP() YYMARKER = YYCURSOR
|
||||
#define YYBACKUPCTX() YYCTXMARKER = YYCURSOR
|
||||
#define YYRESTORE() YYCURSOR = YYMARKER
|
||||
#define YYRESTORECTX() YYCURSOR = YYCTXMARKER
|
||||
#define YYRESTORETAG(tag) YYCURSOR = tag
|
||||
#define YYLESSTHAN(len) YYLIMIT - YYCURSOR < len
|
||||
#define YYSTAGP(tag) tag = YYCURSOR
|
||||
#define YYSTAGN(tag) tag = NULL
|
||||
#define YYSHIFT(shift) YYCURSOR += shift
|
||||
#define YYSHIFTSTAG(tag, shift) tag += shift
|
||||
|
||||
|
|
||||
|
||||
- **Free-form**.
|
||||
This style is enabled with ``re2c:api:style = free-form;`` configuration, and
|
||||
it is the default for Go backend. In this style API primitives can be defined
|
||||
as free-form pieces of code, and instead of arguments they have interpolated
|
||||
variables of the form ``@@{name}``, or optionally just ``@@`` if there is only one
|
||||
argument. The ``@@`` text is called "sigil". It can be redefined to any other
|
||||
text with ``re2c:api:sigil`` configuration. For example, the default pointer API
|
||||
can be defined in free-form style generic API as follows:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
re2c:define:YYPEEK = "*YYCURSOR";
|
||||
re2c:define:YYSKIP = "++YYCURSOR";
|
||||
re2c:define:YYBACKUP = "YYMARKER = YYCURSOR";
|
||||
re2c:define:YYBACKUPCTX = "YYCTXMARKER = YYCURSOR";
|
||||
re2c:define:YYRESTORE = "YYCURSOR = YYMARKER";
|
||||
re2c:define:YYRESTORECTX = "YYCURSOR = YYCTXMARKER";
|
||||
re2c:define:YYRESTORETAG = "YYCURSOR = ${tag}";
|
||||
re2c:define:YYLESSTHAN = "YYLIMIT - YYCURSOR < @@{len}";
|
||||
re2c:define:YYSTAGP = "@@{tag} = YYCURSOR";
|
||||
re2c:define:YYSTAGN = "@@{tag} = NULL";
|
||||
re2c:define:YYSHIFT = "YYCURSOR += @@{shift}";
|
||||
re2c:define:YYSHIFTSTAG = "@@{tag} += @@{shift}";
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
Here is a list of API primitives that may be used by the generated
|
||||
code in order to interface with the outer program.
|
||||
Here is a list of API primitives that may be used by the generated code in order to interface with the outer program.
|
||||
Which primitives are needed depends on multiple factors, including
|
||||
the complexity of regular expressions, input representation,
|
||||
buffering, the use of various features and so on.
|
||||
All the necessary primitives should be defined by the user in the form
|
||||
of macros, functions, variables, free-form pieces of code, or any other
|
||||
suitable form.
|
||||
Re2c does not (and cannot) check the definitions, so if anything is
|
||||
missing or defined incorrectly the generated code will not compile.
|
||||
the complexity of regular expressions, input representation, buffering, the use of various features and so on.
|
||||
All the necessary primitives should be defined by the user in the form of macros, functions, variables, free-form pieces of code or any other suitable form.
|
||||
Re2c does not (and cannot) check the definitions, so if anything is missing or defined incorrectly the generated code will not compile.
|
||||
|
||||
``YYCTYPE``
|
||||
The type of the input characters (code units).
|
||||
@@ -19,23 +14,22 @@ missing or defined incorrectly the generated code will not compile.
|
||||
A pointer-like l-value that stores the current input position (usually a
|
||||
pointer of type ``YYCTYPE*``). Initially ``YYCURSOR`` should point to the
|
||||
first input character. It is advanced by the generated code.
|
||||
When a rule matches, ``YYCURSOR`` points to the position after the
|
||||
last matched character. It is used only in the default C API.
|
||||
When a rule matches, ``YYCURSOR`` points to the one after the last matched
|
||||
character. It is used only in the default C API.
|
||||
|
||||
``YYLIMIT``
|
||||
A pointer-like r-value that stores the end of input position (usually a
|
||||
pointer of type ``YYCTYPE*``). Initially ``YYLIMIT`` should point to the
|
||||
position after the last available input character. It is not changed by the
|
||||
generated code. The lexer compares ``YYCURSOR`` to ``YYLIMIT``
|
||||
in order to determine if there are enough input characters left.
|
||||
one after the last available input character. It is not changed by the
|
||||
generated code. Lexer compares ``YYCURSOR`` to ``YYLIMIT``
|
||||
in order to determine if there is enough input characters left.
|
||||
``YYLIMIT`` is used only in the default C API.
|
||||
|
||||
``YYMARKER``
|
||||
A pointer-like l-value (usually a pointer of type ``YYCTYPE*``)
|
||||
that stores the position of the latest matched rule. It is used to
|
||||
restore the ``YYCURSOR`` position if the longer match fails and
|
||||
the lexer needs to rollback. Initialization is not
|
||||
needed. ``YYMARKER`` is used only in the default C API.
|
||||
A pointer-like l-value (usually a pointer of type ``YYCTYPE*``) that stores
|
||||
the position of the latest matched rule. It is used to restores ``YYCURSOR``
|
||||
position if the longer match fails and lexer needs to rollback.
|
||||
Initialization is not needed. ``YYMARKER`` is used only in the default C API.
|
||||
|
||||
``YYCTXMARKER``
|
||||
A pointer-like l-value that stores the position of the trailing context
|
||||
@@ -44,28 +38,24 @@ missing or defined incorrectly the generated code will not compile.
|
||||
``/``.
|
||||
|
||||
``YYFILL``
|
||||
A generic API primitive with one argument ``len``. ``YYFILL`` requests
|
||||
that the program provide at least ``len`` more input characters or
|
||||
fail.
|
||||
If an EOF rule is used, ``YYFILL`` should always return to the
|
||||
calling function; the return value should be zero on success and
|
||||
non-zero on failure.
|
||||
If an EOF rule is not used, the ``YYFILL`` return value is ignored
|
||||
and it should not return on failure.
|
||||
The maximal value of ``len`` is ``YYMAXFILL``, which can be
|
||||
generated with the ``/*!max:re2c*/`` directive. The definition of
|
||||
``YYFILL`` can be either function-like or free-form depending on
|
||||
the API style (see ``re2c:api:style`` and
|
||||
``re2c:define:YYFILL:naked``).
|
||||
API primitive with one argument ``len``.
|
||||
The meaning of ``YYFILL`` is to provide at least ``len`` more input
|
||||
characters or fail. If EOF rule is used, ``YYFILL`` should always return to
|
||||
the calling function; the return value should be zero on success and non-zero
|
||||
on failure. If EOF rule is not used, ``YYFILL`` return value is ignored and
|
||||
it should not return on failure. Maximal value of ``len`` is ``YYMAXFILL``,
|
||||
which can be generated with ``/*!max:re2c*/`` directive. The definition of
|
||||
``YYFILL`` can be either function-like or free-form depending on the API
|
||||
style (see ``re2c:api:style`` and ``re2c:define:YYFILL:naked``).
|
||||
|
||||
``YYMAXFILL``
|
||||
An integral constant equal to the maximal value of the argument to
|
||||
``YYFILL``. It can be generated with ``/*!max:re2c*/`` directive.
|
||||
An integral constant equal to the maximal value of ``YYFILL`` argument.
|
||||
It can be generated with ``/*!max:re2c*/`` directive.
|
||||
|
||||
``YYLESSTHAN``
|
||||
A generic API primitive with one argument ``len``.
|
||||
It should be defined as an r-value of boolean type that equals ``true`` if
|
||||
and only if there are less than ``len`` input characters left.
|
||||
and only if there is less than ``len`` input characters left.
|
||||
The definition can be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
@@ -73,101 +63,93 @@ missing or defined incorrectly the generated code will not compile.
|
||||
A generic API primitive with no arguments.
|
||||
It should be defined as an r-value of type ``YYCTYPE`` that is equal to the
|
||||
character at the current input position. The definition can be either
|
||||
function-like or free-form depending on the API style
|
||||
(see ``re2c:api:style``).
|
||||
function-like or free-form depending on the API style (see ``re2c:api:style``).
|
||||
|
||||
``YYSKIP``
|
||||
A generic API primitive with no arguments.
|
||||
``YYSKIP`` should advance the current input position by one
|
||||
The meaning of ``YYSKIP`` is to advance the current input position by one
|
||||
character. The definition can be either function-like or free-form
|
||||
depending on the API style (see ``re2c:api:style``).
|
||||
|
||||
``YYBACKUP``
|
||||
A generic API primitive with no arguments.
|
||||
``YYBACKUP`` should save the current input position, which is
|
||||
The meaning of ``YYBACKUP`` is to save the current input position, which is
|
||||
later restored with ``YYRESTORE``.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYRESTORE``
|
||||
A generic API primitive with no arguments.
|
||||
``YYRESTORE`` should restore the current input position to the
|
||||
The meaning of ``YYRESTORE`` is to restore the current input position to the
|
||||
value saved by ``YYBACKUP``.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYBACKUPCTX``
|
||||
A generic API primitive with zero arguments.
|
||||
``YYBACKUPCTX`` should save the current input position as the
|
||||
position of the trailing context, which is later restored by
|
||||
``YYRESTORECTX``.
|
||||
The meaning of ``YYBACKUPCTX`` is to save the current input position as the
|
||||
position of the trailing context, which is later restored by ``YYRESTORECTX``.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYRESTORECTX``
|
||||
A generic API primitive with no arguments.
|
||||
``YYRESTORECTX`` should restore the trailing context position
|
||||
The meaning of ``YYRESTORECTX`` is to restore the trailing context position
|
||||
saved with ``YYBACKUPCTX``.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYRESTORETAG``
|
||||
A generic API primitive with one argument ``tag``.
|
||||
``YYRESTORETAG`` should restore the trailing context position
|
||||
The meaning of ``YYRESTORETAG`` is to restore the trailing context position
|
||||
to the value of ``tag``.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYSTAGP``
|
||||
A generic API primitive with one argument ``tag``.
|
||||
(``tag`` should represent a pointer or an offset, see the section
|
||||
on submatch extraction for details.)
|
||||
``YYSTAGP`` should set the ``tag`` value to the current input
|
||||
The meaning of ``YYSTAGP`` is to set ``tag`` value to the current input
|
||||
position.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYSTAGN``
|
||||
A generic API primitive with one argument ``tag``.
|
||||
(``tag`` should represent a pointer or an offset, see the section
|
||||
on submatch extraction for details.)
|
||||
``YYSTAGN`` should to set the ``tag`` value to null (or
|
||||
some default value).
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
The meaning of ``YYSTAGN`` is to set ``tag`` value to null (or some default
|
||||
value). The definition should be either function-like or free-form depending
|
||||
on the API style (see ``re2c:api:style``).
|
||||
|
||||
``YYMTAGP``
|
||||
A generic API primitive with one argument ``tag``.
|
||||
``YYMTAGP`` should append the current position to the history
|
||||
of ``tag``. (See the section on submatch extraction for details.)
|
||||
The meaning of ``YYMTAGP`` is to append the current position to the history
|
||||
of ``tag``.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYMTAGN``
|
||||
A generic API primitive with one argument ``tag``.
|
||||
``YYMTAGN`` should append null (or some other default) value
|
||||
The meaning of ``YYMTAGN`` is to append null (or some other default) value
|
||||
to the history of ``tag``.
|
||||
(See the section on submatch extraction for details.)
|
||||
The definition can be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYSHIFT``
|
||||
A generic API primitive with one argument ``shift``.
|
||||
``YYSHIFT`` should shift the current input position by
|
||||
The meaning of ``YYSHIFT`` is to shift the current input position by
|
||||
``shift`` characters (the shift value may be negative). The definition
|
||||
can be either function-like or free-form depending on the API style
|
||||
(see ``re2c:api:style``).
|
||||
|
||||
``YYSHIFTSTAG``
|
||||
A generic API primitive with two arguments, ``tag`` and ``shift``.
|
||||
``YYSHIFTSTAG`` should shift ``tag`` by ``shift`` characters
|
||||
The meaning of ``YYSHIFTSTAG`` is to shift ``tag`` by ``shift`` characters
|
||||
(the shift value may be negative).
|
||||
The definition can be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
|
||||
``YYSHIFTMTAG``
|
||||
A generic API primitive with two arguments, ``tag`` and ``shift``.
|
||||
``YYSHIFTMTAG`` should shift the latest value in the history
|
||||
The meaning of ``YYSHIFTMTAG`` is to shift the latest value in the history
|
||||
of ``tag`` by ``shift`` characters (the shift value may be negative).
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style``).
|
||||
@@ -178,8 +160,8 @@ missing or defined incorrectly the generated code will not compile.
|
||||
|
||||
``YYCONDTYPE``
|
||||
The type of the condition enum.
|
||||
It should be generated either with the ``/*!types:re2c*/``
|
||||
directive or the ``-t`` ``--type-header`` option.
|
||||
It should be generated either with ``/*!types:re2c*/`` directive or ``-t``
|
||||
``--type-header`` option.
|
||||
|
||||
``YYGETCONDITION``
|
||||
An API primitive with zero arguments.
|
||||
@@ -190,8 +172,8 @@ missing or defined incorrectly the generated code will not compile.
|
||||
|
||||
``YYSETCONDITION``
|
||||
An API primitive with one argument ``cond``.
|
||||
The meaning of ``YYSETCONDITION`` is to set the current condition
|
||||
identifier to ``cond``.
|
||||
The meaning of ``YYSETCONDITION`` is to set the current condition identifier
|
||||
to ``cond``.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style`` and ``re2c:define:YYSETCONDITION@cond``).
|
||||
|
||||
@@ -204,8 +186,7 @@ missing or defined incorrectly the generated code will not compile.
|
||||
|
||||
``YYSETSTATE``
|
||||
An API primitive with one argument ``state``.
|
||||
The meaning of ``YYSETSTATE`` is to set the current lexer state to
|
||||
``state``.
|
||||
The meaning of ``YYSETSTATE`` is to set the current lexer state to ``state``.
|
||||
The definition should be either function-like or free-form depending on the
|
||||
API style (see ``re2c:api:style`` and ``re2c:define:YYSETSTATE@state``).
|
||||
|
||||
|
||||
@@ -5,28 +5,28 @@ except that the name can be used to reference a block in other parts of the
|
||||
program. More information on each directive can be found in the related
|
||||
sections.
|
||||
|
||||
``/*!re2c[:<name>] ... */``
|
||||
``/*!re2c[:NAME] ... */``
|
||||
A global re2c block with an optional name. The block may contain named
|
||||
definitions, configurations and rules in any order. Named definitions and
|
||||
configurations are defined in the global scope, so they are inherited by
|
||||
subsequent blocks. The code for a global block is generated at the point
|
||||
where the block is specified.
|
||||
|
||||
``/*!local:re2c[:<name>] ... */``
|
||||
``/*!local:re2c[:NAME] ... */``
|
||||
A local re2c block with an optional name. Unlike global blocks, definitions
|
||||
and configurations inside of a local block are not added into the global
|
||||
scope. In all other respects local blocks are the same as global blocks.
|
||||
|
||||
``/*!rules:re2c[:<name>] ... */``
|
||||
``/*!rules:re2c[:NAME] ... */``
|
||||
A reusable block with an optional name. Rules blocks have the same structure
|
||||
as local or global blocks, but they do not produce any code and they can be
|
||||
reused multiple times in other blocks with the help of a ``!use:<name>;``
|
||||
directive or a ``/*!use:re2c[:<name>] ... */`` block. A rules block on its
|
||||
reused multiple times in other blocks with the help of a ``!use:NAME;``
|
||||
directive or a ``/*!use:re2c[:NAME] ... */`` block. A rules block on its
|
||||
own does not add any definitions into the global scope. The code for it is
|
||||
generated at the point of use. Prior to re2c version 2.2 rules blocks
|
||||
required ``-r --reusable`` option.
|
||||
|
||||
``/*!use:re2c[:<name>] ... */``
|
||||
``/*!use:re2c[:NAME] ... */``
|
||||
A use block that references a previously defined rules block. If the name is
|
||||
specified, re2c looks for a rules blocks with this name. Otherwise the most
|
||||
recent rules block is used (either a named or an unnamed one). A use block
|
||||
@@ -34,7 +34,7 @@ sections.
|
||||
those of the referenced rules block. Prior to re2c version 2.2 use blocks
|
||||
required ``-r --reusable`` option.
|
||||
|
||||
``!use:<name>;``
|
||||
``!use:NAME;``
|
||||
An in-block use directive that merges a previously defined rules block with
|
||||
the specified name into the current block. Named definitions, configurations
|
||||
and rules of the referenced block are added to the current ones. Conflicts
|
||||
@@ -45,7 +45,7 @@ sections.
|
||||
can be placed anywhere inside of a block, and multiple use directives are
|
||||
allowed.
|
||||
|
||||
``/*!max:re2c[:<name1>[:<name2>...]] ... */``
|
||||
``/*!max:re2c[:NAME1[:NAME2...]] ... */``
|
||||
A directive that generates ``YYMAXFILL`` definition.
|
||||
An optional list of block names specifies which blocks should be included
|
||||
when computing ``YYMAXFILL`` value (if the list is empty, all blocks are
|
||||
@@ -56,7 +56,7 @@ sections.
|
||||
configuration ``format`` that specifies a template string where ``@@{max}``
|
||||
(or ``@@`` for short) is replaced with the numeric value of ``YYMAXFILL``.
|
||||
|
||||
``/*!maxnmatch:re2c[:<name1>[:<name2>...]] ... */``
|
||||
``/*!maxnmatch:re2c[:NAME1[:NAME2...]] ... */``
|
||||
A directive that generates ``YYMAXNMATCH`` definition (it requires
|
||||
``-P --posix-captures`` option).
|
||||
An optional list of block names specifies which blocks should be included
|
||||
@@ -68,7 +68,7 @@ sections.
|
||||
configuration ``format`` that specifies a template string where ``@@{max}``
|
||||
(or ``@@`` for short) is replaced with the numeric value of ``YYMAXNMATCH``.
|
||||
|
||||
``/*!stags:re2c[:<name1>[:<name2>...]] ... */``, ``/*!mtags:re2c[:<name1>[:<name2>...]] ... */``
|
||||
``/*!stags:re2c[:NAME1[:NAME2...]] ... */``, ``/*!mtags:re2c[:NAME1[:NAME2...]] ... */``
|
||||
Directives that specify a template piece of code that is expanded for each
|
||||
s-tag/m-tag variable generated by re2c.
|
||||
An optional list of block names specifies which blocks should be included
|
||||
@@ -80,7 +80,7 @@ sections.
|
||||
Configuration ``separator`` specifies a piece of code used to join the
|
||||
generated ``format`` pieces for different tag variables.
|
||||
|
||||
``/*!getstate:re2c[:<name1>[:<name2>...]] ... */``
|
||||
``/*!getstate:re2c[:NAME1[:NAME2...]] ... */``
|
||||
A directive that generates conditional dispatch on the lexer state (it
|
||||
requires ``-f --storable-state`` option).
|
||||
An optional list of block names specifies which blocks should be included in
|
||||
@@ -89,7 +89,7 @@ sections.
|
||||
the default transition goes to the first block in the file that has a start
|
||||
label.
|
||||
|
||||
``/*!types:re2c[:<name1>[:<name2>...]] ... */``
|
||||
``/*!types:re2c[:NAME1[:NAME2...]] ... */``
|
||||
A directive that generates condition enumeration (it requires
|
||||
``-c --conditions`` option).
|
||||
An optional list of block names specifies which blocks should be included
|
||||
@@ -103,15 +103,15 @@ sections.
|
||||
Configuration ``separator`` specifies a piece of code used to join the
|
||||
generated ``format`` pieces for different conditions.
|
||||
|
||||
``/*!include:re2c <file> */``
|
||||
This directive allows one to include ``<file>``, which must be a double-quoted
|
||||
``/*!include:re2c FILE */``
|
||||
This directive allows one to include ``FILE``, which must be a double-quoted
|
||||
file path. The contents of the file are literally substituted in place of
|
||||
the directive, in the same way as ``#include`` works in C/C++. This
|
||||
directive can be used together with the ``--depfile`` option to generate
|
||||
build system dependencies on the included files.
|
||||
|
||||
``!include <file>;``
|
||||
This directive is the same as ``/*!include:re2c <file> */``, except that it
|
||||
``!include FILE;``
|
||||
This directive is the same as ``/*!include:re2c FILE */``, except that it
|
||||
should be used inside of a re2c block.
|
||||
|
||||
``/*!header:re2c:on*/``
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
The generated code interfaces with the outer program with the help of
|
||||
*primitives* -- symbolic names that can be defined as variables, functions or
|
||||
macros in the target language (collectively referred to as the API).
|
||||
The primitives should be defined by the user. This approach gives the user
|
||||
freedom and flexibility in customizing the lexer, but it also requires some
|
||||
understanding of how the lexer works in order to implement the primitives
|
||||
correctly and efficiently. The manual provides examples for the most popular
|
||||
use cases. For the full list of primitives see the `interface primitives`_
|
||||
section.
|
||||
|
||||
.. _generic_api:
|
||||
|
||||
There are two *API flavours* that define the set of primitives used by re2c:
|
||||
|
||||
**Pointer API**
|
||||
This API is also called *default API*, since it was historically the first,
|
||||
and for a long time the only one. This is a more restrictive API based on C
|
||||
pointer arithmetics. It consists of pointer-like primitives ``YYCURSOR``,
|
||||
``YYMARKER``, ``YYCTXMARKER``, ``YYLIMIT`` (which are normally defined as
|
||||
pointers of type ``YYCTYPE*``) and ``YYFILL``. Pointer API is enabled by
|
||||
default for the C backend, and it cannot be used with backends that do not
|
||||
support pointer arithmetics.
|
||||
|
||||
**Generic API**
|
||||
This is a more flexible API that does not assume pointer semantics. It
|
||||
consists of primitives
|
||||
``YYPEEK``,
|
||||
``YYSKIP``,
|
||||
``YYBACKUP``,
|
||||
``YYBACKUPCTX``,
|
||||
``YYSTAGP``,
|
||||
``YYSTAGN``,
|
||||
``YYMTAGP``,
|
||||
``YYMTAGN``,
|
||||
``YYRESTORE``,
|
||||
``YYRESTORECTX``,
|
||||
``YYRESTORETAG``,
|
||||
``YYSHIFT``,
|
||||
``YYSHIFTSTAG``,
|
||||
``YYSHIFTMTAG``,
|
||||
``YYLESSTHAN``
|
||||
and ``YYFILL``.
|
||||
For the C backend generic API is enabled with ``--input custom`` option or
|
||||
``re2c:flags:input = custom;`` configuration; for the Go backend it is
|
||||
enabled by default. Generic API was added in version 0.14. It is
|
||||
intentionally designed to give the user as much freedom as possible in
|
||||
redefining the input model and the semantics of different actions performed
|
||||
by the generated code.
|
||||
|
||||
There are two *API styles* determine the form in which the primitives should be
|
||||
defined:
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
|
||||
**Free-form**
|
||||
This style is enabled with ``re2c:api:style = free-form;`` configuration.
|
||||
Interface primitives should be defined as free-form pieces of code with
|
||||
interpolated variables of the form ``@@{name}`` or optionally just ``@@``
|
||||
if there is only one variable. The ``@@`` marker can be customized with the
|
||||
``re2c:api:sigil`` configuration. In C/C++ free-form style generic API can
|
||||
be defined in terms of pointers ``cursor``, ``limit``, ``marker`` and
|
||||
``ctxmarker`` as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/*!re2c
|
||||
re2c:define:YYPEEK = "*cursor";
|
||||
re2c:define:YYSKIP = "++cursor";
|
||||
re2c:define:YYBACKUP = "marker = cursor";
|
||||
re2c:define:YYRESTORE = "cursor = marker";
|
||||
re2c:define:YYBACKUPCTX = "ctxmarker = cursor";
|
||||
re2c:define:YYRESTORECTX = "cursor = ctxmarker";
|
||||
re2c:define:YYRESTORETAG = "cursor = ${tag}";
|
||||
re2c:define:YYLESSTHAN = "limit - cursor < @@{len}";
|
||||
re2c:define:YYSTAGP = "@@{tag} = cursor";
|
||||
re2c:define:YYSTAGN = "@@{tag} = NULL";
|
||||
re2c:define:YYSHIFT = "cursor += @@{shift}";
|
||||
re2c:define:YYSHIFTSTAG = "@@{tag} += @@{shift}";
|
||||
*/
|
||||
|
||||
|
|
||||
|
||||
**Function-like**
|
||||
This style is enabled with ``re2c:api:style = functions;`` configuration.
|
||||
Primitives should be defined as functions or macros with parentheses,
|
||||
accepting the necessary number of arguments. For historical reasons this
|
||||
API style is the default for C/C++ backend. Function style generic API can
|
||||
be defined in terms of pointers ``cursor``, ``limit``, ``marker`` and
|
||||
``ctxmarker`` as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define YYPEEK() *cursor
|
||||
#define YYSKIP() ++cursor
|
||||
#define YYBACKUP() marker = cursor
|
||||
#define YYRESTORE() cursor = marker
|
||||
#define YYBACKUPCTX() ctxmarker = cursor
|
||||
#define YYRESTORECTX() cursor = ctxmarker
|
||||
#define YYRESTORETAG(tag) cursor = tag
|
||||
#define YYLESSTHAN(len) limit - cursor < len
|
||||
#define YYSTAGP(tag) tag = cursor
|
||||
#define YYSTAGN(tag) tag = NULL
|
||||
#define YYSHIFT(shift) cursor += shift
|
||||
#define YYSHIFTSTAG(tag, shift) tag += shift
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
|
||||
**Free-form**
|
||||
This style is enabled with ``re2c:api:style = free-form;`` configuration,
|
||||
and it is the default for the Go backend. Interface primitives should be
|
||||
defined as free-form pieces of code with interpolated variables of the form
|
||||
``@@{name}`` or optionally just ``@@`` if there is only one variable. The
|
||||
``@@`` text can be customized with the ``re2c:api:sigil`` configuration.
|
||||
In Go free-form style generic API can be defined in terms of integer
|
||||
variables ``cursor``, ``limit``, ``marker``, ``ctxmarker`` and a string (or
|
||||
a byte slice) ``data`` as follows:
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
/*!re2c
|
||||
re2c:define:YYPEEK = "data[cursor]";
|
||||
re2c:define:YYSKIP = "cursor++";
|
||||
re2c:define:YYBACKUP = "marker = cursor";
|
||||
re2c:define:YYRESTORE = "cursor = marker";
|
||||
re2c:define:YYBACKUPCTX = "ctxmarker = cursor";
|
||||
re2c:define:YYRESTORECTX = "cursor = ctxmarker";
|
||||
re2c:define:YYRESTORETAG = "cursor = ${tag}";
|
||||
re2c:define:YYLESSTHAN = "limit - cursor < @@{len}";
|
||||
re2c:define:YYSTAGP = "@@{tag} = cursor";
|
||||
re2c:define:YYSTAGN = "@@{tag} = -1";
|
||||
re2c:define:YYSHIFT = "cursor += @@{shift}";
|
||||
re2c:define:YYSHIFTSTAG = "@@{tag} += @@{shift}";
|
||||
*/
|
||||
|
||||
|
|
||||
|
||||
**Function-like**
|
||||
This style is enabled with ``re2c:api:style = functions;`` configuration.
|
||||
Primitives should be defined as functions with parentheses, accepting the
|
||||
necessary number of arguments. This style can be used with the Go backend,
|
||||
but it is more restrictive than the free-form style and some primitives are
|
||||
problematic to define. Most of the primitives can be defined as closures in
|
||||
terms of integer variables ``cursor``, ``limit``, ``marker``, ``ctxmarker``
|
||||
and a string (or a byte slice) ``data``:
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
YYPEEK := func() byte { return data[cursor] }
|
||||
YYSKIP := func() { cursor++ }
|
||||
YYBACKUP := func() { marker = cursor }
|
||||
YYRESTORE := func() { cursor = marker }
|
||||
YYBACKUPCTX := func() { ctxmarker = cursor }
|
||||
YYRESTORECTX := func() { cursor = ctxmarker }
|
||||
YYLESSTHAN := func(n int) bool { return limit-cursor < n }
|
||||
YYSHIFT := func(n int) { cursor += n }
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
For ``YYFILL`` definition and instructions how to customize or disable
|
||||
end-of-input checks see the `handling the end of input`_ and
|
||||
`buffer refilling`_ sections.
|
||||
|
||||
@@ -1,70 +1,20 @@
|
||||
Re2c works as a preprocessor. It reads the input file (which is usually a
|
||||
program in the target language, but can be anything) and looks for blocks of
|
||||
code enclosed in special-form comments. The text outside of these blocks is
|
||||
copied verbatim into the output file. The contents of the blocks are processed
|
||||
by re2c. It translates them to code in the target language and outputs the
|
||||
generated code in place of the block. There are different kinds of blocks;
|
||||
see the `blocks and directives`_ section for a full list of them. The main block
|
||||
kinds are the following:
|
||||
|
||||
``/*!re2c[:<name>] ... */``
|
||||
A *global block* that contains a mixture of named definitions,
|
||||
configurations, directives and rules (regular expressions with associated
|
||||
semantic actions). Re2c compiles regular expressions to a deterministic
|
||||
finite automaton, encodes it in the form of conditional jumps and replaces
|
||||
the block with the generated code. Names and configurations defined
|
||||
in the block are added to the global scope and become visible to subsequent
|
||||
blocks (at the start of the program global scope is initialized with the
|
||||
`command-line options`_).
|
||||
The ``:<name>`` part is optional: if specified, the name can be used to
|
||||
refer to the block in another part of the program.
|
||||
|
||||
``/*!local:re2c[:<name>] ... */``
|
||||
A *local block* is like a global block, but the names and configurations
|
||||
defined in it have local scope (they do not affect other blocks).
|
||||
|
||||
``/*!rules:re2c[:<name>] ... */``
|
||||
A *rules block* is like a local block, but it does not generate any code and
|
||||
is meant to be reused in other blocks. This is a way of sharing code
|
||||
(more details in the `reusable blocks`_ section).
|
||||
|
||||
A block may contain the following kinds of statements:
|
||||
|
||||
``<name> = <regular expression>;``
|
||||
A *named definition* binds a name to a regular expression. Names may contain
|
||||
alphanumeric characters and underscore. The `regular expressions`_ section
|
||||
gives an overview of re2c syntax for regular expressions. Once defined, the
|
||||
name can be used in other regular expressions and in rules. Recursion in
|
||||
named definitions is not allowed, and each name should be defined before it
|
||||
is used. A block inherits named definitions from the global scope.
|
||||
Redefining a name that exists in the current scope is an error.
|
||||
|
||||
``<configuration> = <value>;``
|
||||
A *configuration* allows one to change re2c behavior and customize the
|
||||
generated code. For a full list of configurations supported by re2c see the
|
||||
`configurations`_ section. Depending on a particular configuration, the
|
||||
value can be a keyword, a nonnegative integer number or a one-line string
|
||||
which should be enclosed in double or single quotes unless it consists of
|
||||
alphanumeric characters. A block inherits configurations from the global
|
||||
scope and may redefine them or add new ones. Configurations defined inside
|
||||
of a block affect the whole block, even if they appear at the end of it.
|
||||
|
||||
``<regular expression> { <code> }``
|
||||
A *rule* binds a regular expression to a semantic action (a block of code in
|
||||
the target language). If the regular expression matches, the associated
|
||||
semantic action is executed. If multiple rules match, the longest match
|
||||
takes precedence. If multiple rules match the same string, the earliest one
|
||||
takes precedence. There are two special rules: the default rule ``*`` and
|
||||
the end of input rule ``$``. The default rule should always be defined, it
|
||||
has the lowest priority regardless of its place in the block, and it matches
|
||||
any code unit (not necessarily a valid character, see the
|
||||
`encoding support`_ section). The end of input rule should be defined if the
|
||||
corresponding method for `handling the end of input`_ is used. If
|
||||
`start conditions`_ are used, rules have more complex syntax.
|
||||
|
||||
``!<directive>;``
|
||||
A *directive* is one of the special predefined statements. Each directive
|
||||
has a unique purpose. For example, the ``!use`` directive merges a rules
|
||||
block into the current one (see the `reusable blocks`_ section), and the
|
||||
``!include`` directive allows one to include an outer file (see the
|
||||
`include files`_ section).
|
||||
A re2c program consists of normal code intermixed with re2c blocks and `directives`_.
|
||||
Each re2c block may contain definitions, configurations and rules.
|
||||
Definitions are of the form ``name = regexp;`` where ``name`` is an identifier that
|
||||
consists of letters, digits and underscores, and ``regexp`` is a regular expression.
|
||||
`Regular expressions`_ may contain other definitions, but recursion is not allowed and each name should be defined before used.
|
||||
`Configurations`_ are of the form ``re2c:config = value;`` where ``config`` is the configuration descriptor
|
||||
and ``value`` can be a number, a string or a special word.
|
||||
Rules consist of a regular expression followed by a semantic action
|
||||
(a block of code enclosed in curly braces ``{`` and ``}``,
|
||||
or a raw one line of code preceded with ``:=`` and ended with a newline that is not followed by a whitespace).
|
||||
If the input matches the regular expression, the associated semantic action is executed.
|
||||
If multiple rules match, the longest match takes precedence.
|
||||
If multiple rules match the same string, the earlier rule takes precedence.
|
||||
There are two special rules: default rule ``*`` and EOF rule ``$``.
|
||||
Default rule should always be defined, it has the lowest priority regardless of its place and matches any code unit (not necessarily a valid character, see `encoding support`_).
|
||||
EOF rule matches the end of input, it should be defined if the corresponding method for `handling the end of input`_ is used.
|
||||
If `start conditions`_ are used, rules have more complex syntax.
|
||||
All rules of a single block are compiled into a deterministic finite-state automaton (DFA) and encoded in the form of a program in the target language.
|
||||
The generated code interfaces with the outer program by the means of a few user-defined primitives (see the `program interface`_ section).
|
||||
`Reusable blocks`_ allow sharing rules, definitions and configurations between different blocks.
|
||||
|
||||
+15
-9
@@ -1,13 +1,16 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --case-ranges -i
|
||||
|
||||
int lex(const char *YYCURSOR) { // C/C++ code
|
||||
|
||||
// re2c $INPUT -o $OUTPUT -i
|
||||
#include <assert.h> //
|
||||
// C/C++ code
|
||||
int lex(const char *YYCURSOR) //
|
||||
{
|
||||
|
||||
{
|
||||
char yych;
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case 'A' ... 'Z':
|
||||
case '_':
|
||||
case 'a' ... 'z': goto yy4;
|
||||
default: goto yy2;
|
||||
}
|
||||
@@ -19,6 +22,7 @@ yy4:
|
||||
switch (yych) {
|
||||
case '0' ... '9':
|
||||
case 'A' ... 'Z':
|
||||
case '_':
|
||||
case 'a' ... 'z': goto yy4;
|
||||
default: goto yy6;
|
||||
}
|
||||
@@ -26,8 +30,10 @@ yy6:
|
||||
{ return 0; }
|
||||
}
|
||||
|
||||
} //
|
||||
//
|
||||
int main() { // C/C++ code
|
||||
return lex("qwerty42"); //
|
||||
} //
|
||||
} //
|
||||
//
|
||||
int main() //
|
||||
{ // C/C++ code
|
||||
assert(lex("_Zer0") == 0); //
|
||||
return 0; //
|
||||
} //
|
||||
|
||||
+22
-18
@@ -1,18 +1,22 @@
|
||||
// re2c $INPUT -o $OUTPUT --case-ranges -i
|
||||
|
||||
int lex(const char *YYCURSOR) { // C/C++ code
|
||||
/*!re2c
|
||||
re2c:define:YYCTYPE = char; // configurations
|
||||
re2c:yyfill:enable = 0; //
|
||||
//
|
||||
alpha = [a-zA-Z]; // named definitions
|
||||
ident = alpha (alpha | [0-9])*; //
|
||||
//
|
||||
ident { return 0; } // rules
|
||||
* { return 1; } //
|
||||
*/
|
||||
} //
|
||||
//
|
||||
int main() { // C/C++ code
|
||||
return lex("qwerty42"); //
|
||||
} //
|
||||
// re2c $INPUT -o $OUTPUT -i
|
||||
#include <assert.h> //
|
||||
// C/C++ code
|
||||
int lex(const char *YYCURSOR) //
|
||||
{
|
||||
/*!re2c // start of re2c block
|
||||
re2c:define:YYCTYPE = char; // configuration
|
||||
re2c:yyfill:enable = 0; // configuration
|
||||
re2c:flags:case-ranges = 1; // configuration
|
||||
//
|
||||
ident = [a-zA-Z_][a-zA-Z_0-9]*; // named definition
|
||||
//
|
||||
ident { return 0; } // normal rule
|
||||
* { return 1; } // default rule
|
||||
*/
|
||||
} //
|
||||
//
|
||||
int main() //
|
||||
{ // C/C++ code
|
||||
assert(lex("_Zer0") == 0); //
|
||||
return 0; //
|
||||
} //
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <assert.h>
|
||||
|
||||
static const uint64_t ERROR = ~0lu;
|
||||
enum YYCONDTYPE {
|
||||
};
|
||||
|
||||
|
||||
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
static const uint64_t ERROR = ~0lu;
|
||||
/*!types:re2c*/
|
||||
|
||||
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
|
||||
{
|
||||
|
||||
+14
-13
@@ -1,12 +1,11 @@
|
||||
// Code generated by re2c, DO NOT EDIT.
|
||||
//go:generate re2go $INPUT -o $OUTPUT -i
|
||||
package main //
|
||||
//
|
||||
func lex(str string) int { // Go code
|
||||
var cursor int //
|
||||
|
||||
package main //
|
||||
//
|
||||
func lex(str string) { // Go code
|
||||
var cursor int //
|
||||
//
|
||||
|
||||
|
||||
{
|
||||
var yych byte
|
||||
yych = str[cursor]
|
||||
@@ -18,7 +17,7 @@ func lex(str string) { // Go code
|
||||
}
|
||||
yy2:
|
||||
cursor += 1
|
||||
{ panic("error!"); }
|
||||
{ return 1; }
|
||||
yy4:
|
||||
cursor += 1
|
||||
yych = str[cursor]
|
||||
@@ -29,11 +28,13 @@ yy4:
|
||||
goto yy4
|
||||
}
|
||||
yy6:
|
||||
{ return }
|
||||
{ return 0; }
|
||||
}
|
||||
|
||||
} //
|
||||
//
|
||||
func main() { // Go code
|
||||
lex("1234\x00") //
|
||||
} //
|
||||
} //
|
||||
//
|
||||
func main() { //
|
||||
if lex("1234\x00") != 0 { // Go code
|
||||
panic("failed!") //
|
||||
} //
|
||||
} //
|
||||
|
||||
+23
-22
@@ -1,24 +1,25 @@
|
||||
//go:generate re2go $INPUT -o $OUTPUT -i
|
||||
package main //
|
||||
//
|
||||
func lex(str string) int { // Go code
|
||||
var cursor int //
|
||||
|
||||
package main //
|
||||
//
|
||||
func lex(str string) { // Go code
|
||||
var cursor int //
|
||||
//
|
||||
/*!re2c
|
||||
re2c:define:YYCTYPE = byte; //
|
||||
re2c:define:YYPEEK = "str[cursor]"; //
|
||||
re2c:define:YYSKIP = "cursor += 1"; // configurations
|
||||
re2c:yyfill:enable = 0; //
|
||||
re2c:flags:nested-ifs = 1; //
|
||||
//
|
||||
number = [1-9][0-9]*; // named definition
|
||||
//
|
||||
number { return } // rules
|
||||
* { panic("error!"); } //
|
||||
*/
|
||||
} //
|
||||
//
|
||||
func main() { // Go code
|
||||
lex("1234\x00") //
|
||||
} //
|
||||
/*!re2c // start of re2c block
|
||||
re2c:define:YYCTYPE = byte; // configuration
|
||||
re2c:define:YYPEEK = "str[cursor]"; // configuration
|
||||
re2c:define:YYSKIP = "cursor += 1"; // configuration
|
||||
re2c:yyfill:enable = 0; // configuration
|
||||
re2c:flags:nested-ifs = 1; // configuration
|
||||
//
|
||||
number = [1-9][0-9]*; // named definition
|
||||
//
|
||||
number { return 0; } // normal rule
|
||||
* { return 1; } // default rule
|
||||
*/
|
||||
} //
|
||||
//
|
||||
func main() { //
|
||||
if lex("1234\x00") != 0 { // Go code
|
||||
panic("failed!") //
|
||||
} //
|
||||
} //
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Code generated by re2c, DO NOT EDIT.
|
||||
//go:generate re2go $INPUT -o $OUTPUT -i
|
||||
//go:generate re2go -c $INPUT -o $OUTPUT -i
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate re2go $INPUT -o $OUTPUT -i
|
||||
//go:generate re2go -c $INPUT -o $OUTPUT -i
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Code generated by re2c, DO NOT EDIT.
|
||||
//go:generate re2go $INPUT -o $OUTPUT -i
|
||||
//go:generate re2go -c $INPUT -o $OUTPUT -i
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate re2go $INPUT -o $OUTPUT -i
|
||||
//go:generate re2go -c $INPUT -o $OUTPUT -i
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
#ifndef _RE2C_LIB_REGOFF_TRIE_
|
||||
#define _RE2C_LIB_REGOFF_TRIE_
|
||||
|
||||
#include <algorithm>
|
||||
#include "regex.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/util/forbid_copy.h"
|
||||
|
||||
|
||||
namespace re2c {
|
||||
|
||||
+3
-27
@@ -12,7 +12,6 @@ import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap as _textwrap
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from functools import cmp_to_key
|
||||
from pathlib import Path
|
||||
@@ -40,7 +39,6 @@ FILEPATH_CONTEXT_PATTERN = re.compile(b'('
|
||||
+ b')')
|
||||
|
||||
|
||||
@dataclass
|
||||
class Context:
|
||||
"""Class for passing a context to parallel processes."""
|
||||
|
||||
@@ -253,29 +251,12 @@ def create_tests_tree():
|
||||
return test_blddir
|
||||
|
||||
|
||||
# We cannot use `shutil.copytree` because we need to copy multiple directories
|
||||
# into one, and that is problematic for two reasons:
|
||||
# 1) it requires `dirs_exist_ok` parameter which was added only in python-3.8
|
||||
# 2) `make distcheck` fails when trying to copy the second directory because
|
||||
# it makes source files read-only
|
||||
def copy_dir(src, dst):
|
||||
"""Copy the contents of directory `src` to directory `dst`, preserving
|
||||
directory structure."""
|
||||
|
||||
for path, dirs, files in os.walk(src, topdown=False):
|
||||
dstpath = os.path.join(dst, path[len(src)+1:])
|
||||
if not os.path.isdir(dstpath):
|
||||
os.makedirs(dstpath)
|
||||
for f in files:
|
||||
shutil.copy(os.path.join(path, f), dstpath)
|
||||
|
||||
|
||||
def copy_tests(tests, dst): # type: (list, str) -> None
|
||||
"""Copy the test structure to 'dst'."""
|
||||
# preserve directory structure unless given explicit args
|
||||
if not tests:
|
||||
copy_dir(here(TOP_SRCDIR, 'test'), dst)
|
||||
copy_dir(here(TOP_SRCDIR, 'examples'), dst)
|
||||
shutil.copytree(here(TOP_SRCDIR, 'test'), dst, dirs_exist_ok=True)
|
||||
shutil.copytree(here(TOP_SRCDIR, 'examples'), dst, dirs_exist_ok=True)
|
||||
return
|
||||
|
||||
files = []
|
||||
@@ -392,11 +373,6 @@ def run_test(test):
|
||||
if header:
|
||||
os.makedirs(os.path.dirname(header), exist_ok=True)
|
||||
|
||||
# Disable Wine warnings, or else they are dumped into .stderr files for
|
||||
# random tests, so the test results don't match and the tests fail.
|
||||
if _ctx.wine:
|
||||
os.environ['WINEDEBUG'] = '-all'
|
||||
|
||||
# run re2c
|
||||
args = [_ctx.valgrind] + _ctx.valgrind_opts
|
||||
args += [_ctx.wine, _ctx.re2c] + _ctx.incpaths + switches.split()
|
||||
@@ -431,7 +407,7 @@ def run_test(test):
|
||||
pass # if there is an error, some files may be missing
|
||||
|
||||
# On windows we need to patch output to match expected test results.
|
||||
if os.name == 'nt' or _ctx.wine:
|
||||
if os.name == 'nt':
|
||||
patch_newlines_and_slashes(outy, stem)
|
||||
|
||||
# compare results
|
||||
|
||||
@@ -510,6 +510,10 @@ void DFA::calc_stats(OutputBlock &out)
|
||||
out.stags.insert(stagnames.begin(), stagnames.end());
|
||||
out.mtags.insert(mtagnames.begin(), mtagnames.end());
|
||||
}
|
||||
|
||||
if (!cond.empty()) {
|
||||
out.conds.push_back(cond);
|
||||
}
|
||||
}
|
||||
|
||||
static bool can_hoist_tags(const State *s, const opt_t *opts)
|
||||
|
||||
+2
-1
@@ -21,7 +21,7 @@
|
||||
namespace re2c {
|
||||
|
||||
class Msg;
|
||||
struct Output;
|
||||
class Output;
|
||||
struct dfa_t;
|
||||
struct opt_t;
|
||||
struct Label;
|
||||
@@ -130,6 +130,7 @@ struct DFA {
|
||||
void reorder();
|
||||
void prepare(const opt_t *opts);
|
||||
void calc_stats(OutputBlock &out);
|
||||
void emit_body(Output &output, CodeList *program) const;
|
||||
void emit_dot(Output &output, CodeList *program) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -63,9 +63,6 @@ void interfere(const tcmd_t *cmd, const bool *live, bool *interf,
|
||||
memcpy(buf, live, nver * sizeof(bool));
|
||||
cfg_t::live_through_bblock(p->next, buf);
|
||||
|
||||
// a register does not interfere with itself
|
||||
buf[l] = false;
|
||||
|
||||
// if copy command, exclude RHS
|
||||
if (tcmd_t::iscopy(p)) buf[r] = false;
|
||||
|
||||
|
||||
+17
-37
@@ -9,7 +9,6 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "src/constants.h"
|
||||
#include "src/dfa/tcmd.h"
|
||||
@@ -17,6 +16,7 @@
|
||||
#include "src/msg/location.h"
|
||||
#include "src/util/forbid_copy.h"
|
||||
#include "src/util/slab_allocator.h"
|
||||
#include "src/util/uniq_vector.h"
|
||||
#include "src/util/smart_ptr.h"
|
||||
#include "src/util/string_utils.h"
|
||||
|
||||
@@ -30,8 +30,8 @@ struct opt_t;
|
||||
struct Code;
|
||||
struct CodeGo;
|
||||
struct CodeGoIf;
|
||||
struct Output;
|
||||
struct OutputBlock;
|
||||
class Output;
|
||||
class OutputBlock;
|
||||
struct State;
|
||||
struct DFA;
|
||||
typedef std::vector<smart_ptr<DFA> > dfas_t;
|
||||
@@ -315,7 +315,6 @@ struct Code {
|
||||
CodeVar var;
|
||||
CodeFmt fmt;
|
||||
CodeLabel label;
|
||||
CodeList *loop;
|
||||
loc_t loc;
|
||||
};
|
||||
|
||||
@@ -375,13 +374,6 @@ inline Code *code_stmt(code_alc_t &alc, const char *text)
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Code *code_loop(code_alc_t &alc, CodeList *loop)
|
||||
{
|
||||
Code *x = new_code(alc, CODE_LOOP);
|
||||
x->loop = loop;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Code *code_text(code_alc_t &alc, const char *text)
|
||||
{
|
||||
Code *x = new_code(alc, CODE_TEXT);
|
||||
@@ -471,11 +463,6 @@ inline Code *code_yyaccept_def(code_alc_t &alc)
|
||||
return new_code(alc, CODE_YYACCEPT);
|
||||
}
|
||||
|
||||
inline Code *code_yystate_def(code_alc_t &alc)
|
||||
{
|
||||
return new_code(alc, CODE_YYSTATE);
|
||||
}
|
||||
|
||||
inline Code *code_line_info_output(code_alc_t &alc)
|
||||
{
|
||||
return new_code(alc, CODE_LINE_INFO_OUTPUT);
|
||||
@@ -641,10 +628,12 @@ struct CodegenCtxGlobal {
|
||||
Scratchbuf &scratchbuf;
|
||||
Msg &msg;
|
||||
const opt_t *opts;
|
||||
const blocks_t &cblocks;
|
||||
const blocks_t &hblocks;
|
||||
const blocks_t *pblocks;
|
||||
mutable blocks_t tmpblocks; // temporary buffer for block lists in directives
|
||||
uniq_vector_t<std::string> conds;
|
||||
tagnames_t stags;
|
||||
tagnames_t mtags;
|
||||
size_t max_fill;
|
||||
size_t max_nmatch;
|
||||
const bool warn_cond_ord;
|
||||
};
|
||||
|
||||
@@ -673,14 +662,6 @@ struct OutputFragment {
|
||||
uint32_t indent;
|
||||
};
|
||||
|
||||
struct StartCond {
|
||||
std::string name;
|
||||
uint32_t number;
|
||||
};
|
||||
typedef std::vector<StartCond> StartConds;
|
||||
|
||||
typedef std::map<uint32_t, CodeList*> storable_states_t;
|
||||
|
||||
struct OutputBlock {
|
||||
InputBlockKind kind;
|
||||
std::string name;
|
||||
@@ -688,7 +669,7 @@ struct OutputBlock {
|
||||
std::vector<OutputFragment> fragments;
|
||||
bool used_yyaccept;
|
||||
bool have_user_code;
|
||||
StartConds conds;
|
||||
std::vector<std::string> conds;
|
||||
tagnames_t stags;
|
||||
tagnames_t mtags;
|
||||
const opt_t *opts;
|
||||
@@ -697,23 +678,25 @@ struct OutputBlock {
|
||||
size_t max_nmatch; // YYMAXNMATCH
|
||||
|
||||
// Used in the state switch (with `-f --storable-state` option).
|
||||
Label *start_label; // label of the DFA start state
|
||||
uint32_t fill_index; // next free index in YYFILL state enumeration
|
||||
uint32_t fill_state; // index of the most recent YYFILL state
|
||||
storable_states_t fill_goto; // transitions to YYFILL states
|
||||
Label *start_label; // label of the DFA start state
|
||||
uint32_t fill_index_start; // start of YYFILL index range
|
||||
uint32_t fill_index_end; // end of YYFILL index range (not included)
|
||||
std::vector<CodeList*> fill_goto; // transitions to YYFILL states
|
||||
|
||||
OutputBlock(InputBlockKind kind, const std::string &name, const loc_t &loc);
|
||||
~OutputBlock();
|
||||
FORBID_COPY(OutputBlock);
|
||||
};
|
||||
|
||||
struct Output {
|
||||
class Output {
|
||||
blocks_t cblocks; /* .c file */
|
||||
blocks_t hblocks; /* .h file */
|
||||
blocks_t *pblocks; /* selector */
|
||||
|
||||
public:
|
||||
uint32_t label_counter;
|
||||
bool state_goto;
|
||||
bool cond_enum_autogen; // true unless an explicit `types:re2c` directive is used
|
||||
bool cond_enum_in_hdr;
|
||||
bool cond_goto;
|
||||
bool warn_condition_order;
|
||||
bool need_header;
|
||||
@@ -763,9 +746,6 @@ void gen_goto(Output &output, const DFA &dfa, CodeList *stmts, const State *from
|
||||
const CodeJump &jump);
|
||||
const char *gen_lessthan(Scratchbuf &o, const opt_t *opts, size_t n);
|
||||
void gen_code(Output &output, dfas_t &dfas);
|
||||
void gen_dfa_as_blocks_with_labels(Output &output, const DFA &dfa, CodeList *stmts);
|
||||
void gen_dfa_as_switch_cases(Output &output, DFA &dfa, CodeCases *cases);
|
||||
void wrap_dfas_in_loop_switch(Output &output, CodeList *stmts, CodeCases *cases);
|
||||
|
||||
void expand_pass_1(CodegenCtxPass1 &ctx, Code *code);
|
||||
void expand_pass_2(CodegenCtxPass2 &ctx, Code *code);
|
||||
|
||||
+31
-36
@@ -12,7 +12,7 @@
|
||||
namespace re2c {
|
||||
|
||||
static CodeGoIf *code_goif(code_alc_t &alc, CodeGoIf::Kind kind, const Span *sp,
|
||||
uint32_t nsp, State *next, bool skip, uint32_t eof, const opt_t *opts);
|
||||
uint32_t nsp, State *next, bool skip, uint32_t eof);
|
||||
|
||||
static bool is_eof(uint32_t eof, uint32_t ub)
|
||||
{
|
||||
@@ -97,7 +97,7 @@ static CodeCmp *code_cmp(code_alc_t &alc, const char *cmp, uint32_t val)
|
||||
}
|
||||
|
||||
static CodeGoIfB *code_goifb(code_alc_t &alc, const Span *s, uint32_t n, State *next,
|
||||
bool skip, uint32_t eof, const opt_t *opts)
|
||||
bool skip, uint32_t eof)
|
||||
{
|
||||
const uint32_t l = n / 2;
|
||||
const uint32_t h = n - l;
|
||||
@@ -106,13 +106,13 @@ static CodeGoIfB *code_goifb(code_alc_t &alc, const Span *s, uint32_t n, State *
|
||||
|
||||
CodeGoIfB *x = alc.alloct<CodeGoIfB>(1);
|
||||
x->cond = code_cmp(alc, "<=", s[l - 1].ub - 1);
|
||||
x->gothen = code_goif(alc, tkind, &s[0], l, next, skip, eof, opts);
|
||||
x->goelse = code_goif(alc, ekind, &s[l], h, next, skip, eof, opts);
|
||||
x->gothen = code_goif(alc, tkind, &s[0], l, next, skip, eof);
|
||||
x->goelse = code_goif(alc, ekind, &s[l], h, next, skip, eof);
|
||||
return x;
|
||||
}
|
||||
|
||||
static void add_branch(CodeGoIfL *go, const CodeCmp *cond, State *to, State *next,
|
||||
const Span &sp, bool skip, uint32_t eof, const opt_t *opts)
|
||||
const Span &sp, bool skip, uint32_t eof)
|
||||
{
|
||||
CodeGoIfL::Branch &b = go->branches[go->nbranches++];
|
||||
b.cond = cond;
|
||||
@@ -121,16 +121,11 @@ static void add_branch(CodeGoIfL *go, const CodeCmp *cond, State *to, State *nex
|
||||
b.jump.tags = sp.tags;
|
||||
b.jump.skip = skip && consume(sp.to);
|
||||
b.jump.eof = is_eof(eof, sp.ub);
|
||||
// TODO: support transition elision with --loop-switch option. This requires
|
||||
// used-label analysis before the start of code generation phase, because in Rust
|
||||
// there is no fallthrough between cases and we can only elide a transition if we can
|
||||
// elide the whole case, which is only possible if there are no other transitions into
|
||||
// this state (so its label is unused).
|
||||
b.jump.elide = !opts->loop_switch && !to;
|
||||
b.jump.elide = !to;
|
||||
}
|
||||
|
||||
static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *next,
|
||||
bool skip, uint32_t eof, const opt_t *opts)
|
||||
bool skip, uint32_t eof)
|
||||
{
|
||||
CodeGoIfL *x = alc.alloct<CodeGoIfL>(1);
|
||||
x->nbranches = 0;
|
||||
@@ -139,17 +134,17 @@ static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *
|
||||
|
||||
for (;;) {
|
||||
if (n == 1 && s[0].to == next) {
|
||||
add_branch(x, NULL, NULL, next, s[0], skip, eof, opts);
|
||||
add_branch(x, NULL, NULL, next, s[0], skip, eof);
|
||||
break;
|
||||
}
|
||||
else if (n == 1) {
|
||||
add_branch(x, NULL, s[0].to, next, s[0], skip, eof, opts);
|
||||
add_branch(x, NULL, s[0].to, next, s[0], skip, eof);
|
||||
break;
|
||||
}
|
||||
else if (n == 2 && s[0].to == next) {
|
||||
CodeCmp *cmp = code_cmp(alc, ">=", s[0].ub);
|
||||
add_branch(x, cmp, s[1].to, next, s[1], skip, eof, opts);
|
||||
add_branch(x, NULL, NULL, next, s[0], skip, eof, opts);
|
||||
add_branch(x, cmp, s[1].to, next, s[1], skip, eof);
|
||||
add_branch(x, NULL, NULL, next, s[0], skip, eof);
|
||||
break;
|
||||
}
|
||||
else if (n == 3
|
||||
@@ -158,8 +153,8 @@ static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *
|
||||
&& s[2].to == s[0].to
|
||||
&& s[2].tags == s[0].tags) {
|
||||
CodeCmp *cmp = code_cmp(alc, "!=", s[0].ub);
|
||||
add_branch(x, cmp, s[0].to, next, s[0], skip, eof, opts);
|
||||
add_branch(x, NULL, NULL, next, s[1], skip, eof, opts);
|
||||
add_branch(x, cmp, s[0].to, next, s[0], skip, eof);
|
||||
add_branch(x, NULL, NULL, next, s[1], skip, eof);
|
||||
break;
|
||||
}
|
||||
else if (n >= 3
|
||||
@@ -167,13 +162,13 @@ static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *
|
||||
&& s[2].to == s[0].to
|
||||
&& s[2].tags == s[0].tags) {
|
||||
CodeCmp *cmp = code_cmp(alc, "==", s[0].ub);
|
||||
add_branch(x, cmp, s[1].to, next, s[1], skip, eof, opts);
|
||||
add_branch(x, cmp, s[1].to, next, s[1], skip, eof);
|
||||
n -= 2;
|
||||
s += 2;
|
||||
}
|
||||
else {
|
||||
CodeCmp *cmp = code_cmp(alc, "<=", s[0].ub - 1);
|
||||
add_branch(x, cmp, s[0].to, next, s[0], skip, eof, opts);
|
||||
add_branch(x, cmp, s[0].to, next, s[0], skip, eof);
|
||||
n -= 1;
|
||||
s += 1;
|
||||
}
|
||||
@@ -183,35 +178,35 @@ static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *
|
||||
}
|
||||
|
||||
static CodeGoIf *code_goif(code_alc_t &alc, CodeGoIf::Kind kind, const Span *sp,
|
||||
uint32_t nsp, State *next, bool skip, uint32_t eof, const opt_t *opts)
|
||||
uint32_t nsp, State *next, bool skip, uint32_t eof)
|
||||
{
|
||||
CodeGoIf *x = alc.alloct<CodeGoIf>(1);
|
||||
x->kind = kind;
|
||||
if (kind == CodeGoIf::BINARY) {
|
||||
x->goifb = code_goifb(alc, sp, nsp, next, skip, eof, opts);
|
||||
x->goifb = code_goifb(alc, sp, nsp, next, skip, eof);
|
||||
}
|
||||
else {
|
||||
x->goifl = code_goifl(alc, sp, nsp, next, skip, eof, opts);
|
||||
x->goifl = code_goifl(alc, sp, nsp, next, skip, eof);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static CodeGoSwIf *code_goswif(code_alc_t &alc, const Span *sp, uint32_t nsp,
|
||||
State *next, bool skip, uint32_t eof, const opt_t *opts)
|
||||
State *next, bool sflag, bool skip, uint32_t eof)
|
||||
{
|
||||
CodeGoSwIf *x = alc.alloct<CodeGoSwIf>(1);
|
||||
if ((!opts->sFlag && nsp > 2)
|
||||
if ((!sflag && nsp > 2)
|
||||
|| (nsp > 8 && (sp[nsp - 2].ub - sp[0].ub <= 3 * (nsp - 2)))) {
|
||||
x->kind = CodeGoSwIf::SWITCH;
|
||||
x->gosw = code_gosw(alc, sp, nsp, skip, eof);
|
||||
}
|
||||
else if (nsp > 5) {
|
||||
x->kind = CodeGoSwIf::IF;
|
||||
x->goif = code_goif(alc, CodeGoIf::BINARY, sp, nsp, next, skip, eof, opts);
|
||||
x->goif = code_goif(alc, CodeGoIf::BINARY, sp, nsp, next, skip, eof);
|
||||
}
|
||||
else {
|
||||
x->kind = CodeGoSwIf::IF;
|
||||
x->goif = code_goif(alc, CodeGoIf::LINEAR, sp, nsp, next, skip, eof, opts);
|
||||
x->goif = code_goif(alc, CodeGoIf::LINEAR, sp, nsp, next, skip, eof);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
@@ -246,7 +241,7 @@ static uint32_t unmap(Span *new_span, const Span *old_span, uint32_t old_nspans,
|
||||
|
||||
static CodeGoBm *code_gobm(code_alc_t &alc, const Span *span, uint32_t nSpans,
|
||||
const Span *hspan, uint32_t hSpans, const CodeBmState *bm, State *next,
|
||||
uint32_t eof, const opt_t *opts)
|
||||
bool sflag, uint32_t eof)
|
||||
{
|
||||
CodeGoBm *x = alc.alloct<CodeGoBm>(1);
|
||||
x->bitmap = bm;
|
||||
@@ -256,11 +251,11 @@ static CodeGoBm *code_gobm(code_alc_t &alc, const Span *span, uint32_t nSpans,
|
||||
Span *bspan = allocate<Span>(nSpans); // temporary
|
||||
uint32_t bSpans = unmap (bspan, span, nSpans, bm->state);
|
||||
x->lgo = bSpans == 0 ? NULL
|
||||
: code_goswif(alc, bspan, bSpans, next, false, eof, opts);
|
||||
: code_goswif(alc, bspan, bSpans, next, sflag, false, eof);
|
||||
// if there are any low spans, then next state for high spans
|
||||
// must be NULL to trigger explicit goto generation in linear 'if'
|
||||
x->hgo = hSpans == 0 ? NULL
|
||||
: code_goswif(alc, hspan, hSpans, x->lgo ? NULL : next, false, eof, opts);
|
||||
: code_goswif(alc, hspan, hSpans, x->lgo ? NULL : next, sflag, false, eof);
|
||||
x->bitmap->state->label->used = true;
|
||||
operator delete(bspan);
|
||||
|
||||
@@ -287,11 +282,11 @@ static CodeGoCpTable *code_gocp_table(code_alc_t &alc, const Span * span, uint32
|
||||
}
|
||||
|
||||
static CodeGoCp *code_gocp(code_alc_t &alc, const Span *span, uint32_t nSpans,
|
||||
const Span *hspan, uint32_t hSpans, State *next, uint32_t eof, const opt_t *opts)
|
||||
const Span *hspan, uint32_t hSpans, State *next, bool sflag, uint32_t eof)
|
||||
{
|
||||
CodeGoCp *x = alc.alloct<CodeGoCp>(1);
|
||||
x->hgo = hSpans == 0 ? NULL
|
||||
: code_goswif(alc, hspan, hSpans, next, false, eof, opts);
|
||||
: code_goswif(alc, hspan, hSpans, next, sflag, false, eof);
|
||||
x->table = code_gocp_table(alc, span, nSpans);
|
||||
return x;
|
||||
}
|
||||
@@ -361,18 +356,18 @@ void code_go(code_alc_t &alc, CodeGo *go, const State *from, const opt_t *opts,
|
||||
&& !low_spans_have_tags) {
|
||||
go->kind = CodeGo::CPGOTO;
|
||||
go->gocp = code_gocp(alc, go->span, go->nspans, hspan, hSpans, from->next,
|
||||
eof, opts);
|
||||
opts->sFlag, eof);
|
||||
}
|
||||
else if (opts->bFlag && !part_skip && nBitmaps > 0) {
|
||||
go->kind = CodeGo::BITMAP;
|
||||
go->gobm = code_gobm(alc, go->span, go->nspans, hspan, hSpans, bm,
|
||||
from->next, eof, opts);
|
||||
from->next, opts->sFlag, eof);
|
||||
bitmap->used = true;
|
||||
}
|
||||
else {
|
||||
go->kind = CodeGo::SWITCH_IF;
|
||||
go->goswif = code_goswif(alc, go->span, go->nspans, from->next,
|
||||
part_skip, eof, opts);
|
||||
go->goswif = code_goswif(alc, go->span, go->nspans, from->next, opts->sFlag,
|
||||
part_skip, eof);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+121
-234
@@ -9,44 +9,18 @@
|
||||
|
||||
namespace re2c {
|
||||
|
||||
static OutputBlock *find_block_with_name(CodegenCtxPass1 &ctx, const char *name)
|
||||
static const OutputBlock *find_block_with_name(CodegenCtxPass1 &ctx,
|
||||
const char *name, const char *where)
|
||||
{
|
||||
const blocks_t &cblocks = ctx.global->cblocks;
|
||||
for (size_t i = 0; i < cblocks.size(); ++i) {
|
||||
if (cblocks[i]->name.compare(name) == 0) return cblocks[i];
|
||||
}
|
||||
const blocks_t &hblocks = ctx.global->hblocks;
|
||||
for (size_t i = 0; i < hblocks.size(); ++i) {
|
||||
if (hblocks[i]->name.compare(name) == 0) return hblocks[i];
|
||||
const blocks_t &blocks = *ctx.global->pblocks;
|
||||
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||
const OutputBlock *b = blocks[i];
|
||||
if (b->name.compare(name) == 0) return b;
|
||||
}
|
||||
error("cannot find block '%s' listed in `%s` directive", name, where);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void find_blocks(CodegenCtxPass1 &ctx, const BlockNameList *names,
|
||||
blocks_t &blocks, const char *directive)
|
||||
{
|
||||
blocks.clear();
|
||||
for (const BlockNameList *p = names; p; p = p->next) {
|
||||
OutputBlock *b = find_block_with_name(ctx, p->name);
|
||||
if (b) {
|
||||
blocks.push_back(b);
|
||||
} else {
|
||||
error("cannot find block '%s' listed in `%s` directive", p->name, directive);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string output_cond_get(const opt_t *opts)
|
||||
{
|
||||
return opts->cond_get + (opts->cond_get_naked ? "" : "()");
|
||||
}
|
||||
|
||||
static std::string output_state_get(const opt_t *opts)
|
||||
{
|
||||
return opts->state_get + (opts->state_get_naked ? "" : "()");
|
||||
}
|
||||
|
||||
void gen_tags(Scratchbuf &buf, const opt_t *opts, Code *code, const tagnames_t &tags)
|
||||
{
|
||||
DASSERT(code->kind == CODE_STAGS || code->kind == CODE_MTAGS);
|
||||
@@ -75,18 +49,6 @@ void gen_tags(Scratchbuf &buf, const opt_t *opts, Code *code, const tagnames_t &
|
||||
code->raw.data = buf.flush();
|
||||
}
|
||||
|
||||
static void add_tags_from_blocks(const blocks_t &blocks, tagnames_t &tags, bool multival)
|
||||
{
|
||||
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||
const OutputBlock &block = *blocks[i];
|
||||
if (multival) {
|
||||
tags.insert(block.mtags.begin(), block.mtags.end());
|
||||
} else {
|
||||
tags.insert(block.stags.begin(), block.stags.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void expand_tags_directive(CodegenCtxPass1 &ctx, Code *code)
|
||||
{
|
||||
DASSERT(code->kind == CODE_STAGS || code->kind == CODE_MTAGS);
|
||||
@@ -96,24 +58,31 @@ static void expand_tags_directive(CodegenCtxPass1 &ctx, Code *code)
|
||||
}
|
||||
|
||||
Scratchbuf &buf = ctx.global->scratchbuf;
|
||||
bool multival = (code->kind == CODE_MTAGS);
|
||||
bool oneval = (code->kind == CODE_STAGS);
|
||||
|
||||
tagnames_t tags;
|
||||
if (code->fmt.block_names == NULL) {
|
||||
// Gather tags from all blocks in the output and header files.
|
||||
add_tags_from_blocks(ctx.global->cblocks, tags, multival);
|
||||
add_tags_from_blocks(ctx.global->hblocks, tags, multival);
|
||||
// Use the global set of tags accumulated from all blocks.
|
||||
gen_tags(buf, ctx.block->opts, code,
|
||||
oneval ? ctx.global->stags : ctx.global->mtags);
|
||||
} else {
|
||||
// Gather tags from the blocks on the list.
|
||||
const char *directive = multival ? "mtags:re2c" : "stags:re2c";
|
||||
find_blocks(ctx, code->fmt.block_names, ctx.global->tmpblocks, directive);
|
||||
add_tags_from_blocks(ctx.global->tmpblocks, tags, multival);
|
||||
const char *directive = oneval ? "stags:re2c" : "mtags:re2c";
|
||||
tagnames_t tags;
|
||||
for (BlockNameList *p = code->fmt.block_names; p; p = p->next) {
|
||||
const OutputBlock *b = find_block_with_name(ctx, p->name, directive);
|
||||
if (!b) exit(1);
|
||||
if (oneval) {
|
||||
tags.insert(b->stags.begin(), b->stags.end());
|
||||
} else {
|
||||
tags.insert(b->mtags.begin(), b->mtags.end());
|
||||
}
|
||||
}
|
||||
gen_tags(buf, ctx.block->opts, code, tags);
|
||||
}
|
||||
gen_tags(buf, ctx.block->opts, code, tags);
|
||||
}
|
||||
|
||||
static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const opt_t *opts,
|
||||
const StartConds &conds)
|
||||
static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code,
|
||||
const opt_t *opts, const uniq_vector_t<std::string> &conds)
|
||||
{
|
||||
DASSERT(opts->target == TARGET_CODE);
|
||||
|
||||
@@ -124,11 +93,10 @@ static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const op
|
||||
for (size_t i = 0; i < conds.size(); ++i) {
|
||||
if (i > 0 && sep) buf.cstr(sep);
|
||||
std::ostringstream s(fmt);
|
||||
// The main substitution (the one allowing unnamed sigil) must go last, or
|
||||
// else it will erroneously substitute all the named ones.
|
||||
size_t cid = opts->loop_switch ? conds[i].number : i;
|
||||
argsubst(s, opts->api_sigil, "num", false, cid);
|
||||
argsubst(s, opts->api_sigil, "cond", true, conds[i].name);
|
||||
// The main substitution (the one allowing unnamed sigil) must go
|
||||
// last, or else it will erroneously substitute all the named ones.
|
||||
argsubst(s, opts->api_sigil, "num", false, i);
|
||||
argsubst(s, opts->api_sigil, "cond", true, conds[i]);
|
||||
buf.str(s.str());
|
||||
}
|
||||
buf.cstr("\n");
|
||||
@@ -138,7 +106,7 @@ static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const op
|
||||
code->raw.data = buf.flush();
|
||||
|
||||
} else {
|
||||
const char *start = NULL, *end = NULL;
|
||||
const char *text, *start = NULL, *end = NULL;
|
||||
CodeList *stmts = code_list(alc);
|
||||
CodeList *block = code_list(alc);
|
||||
|
||||
@@ -146,23 +114,15 @@ static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const op
|
||||
start = buf.cstr("enum ").str(opts->yycondtype).cstr(" {").flush();
|
||||
end = "};";
|
||||
for (size_t i = 0; i < conds.size(); ++i) {
|
||||
buf.str(conds[i].name);
|
||||
if (opts->loop_switch) {
|
||||
buf.cstr(" = ").u32(conds[i].number);
|
||||
}
|
||||
append(block, code_text(alc, buf.cstr(",").flush()));
|
||||
text = buf.str(conds[i]).cstr(",").flush();
|
||||
append(block, code_text(alc, text));
|
||||
}
|
||||
} else if (opts->lang == LANG_GO) {
|
||||
start = buf.cstr("const (").flush();
|
||||
end = ")";
|
||||
for (size_t i = 0; i < conds.size(); ++i) {
|
||||
buf.str(conds[i].name);
|
||||
if (opts->loop_switch) {
|
||||
buf.cstr(" = ").u32(conds[i].number);
|
||||
} else if (i == 0) {
|
||||
buf.cstr(" = iota");
|
||||
}
|
||||
append(block, code_text(alc, buf.flush()));
|
||||
text = buf.str(conds[i]).cstr(i == 0 ? " = iota" : "").flush();
|
||||
append(block, code_text(alc, text));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,43 +136,6 @@ static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const op
|
||||
}
|
||||
}
|
||||
|
||||
static void add_condition_from_block(const OutputBlock &block, StartConds &conds,
|
||||
const StartCond &cond)
|
||||
{
|
||||
// Condition prefix is specific to the block that defines it. If a few blocks define
|
||||
// conditions with the same name, but a different prefix, they should have different
|
||||
// enum entries.
|
||||
StartCond sc = cond;
|
||||
sc.name = block.opts->condEnumPrefix + sc.name;
|
||||
|
||||
for (size_t i = 0; i < conds.size(); ++i) {
|
||||
if (conds[i].name == sc.name) {
|
||||
if (conds[i].number == sc.number) {
|
||||
// A duplicate condition, it's not an error but don't add it.
|
||||
return;
|
||||
} else {
|
||||
// An error: conditions with idetical names but different numbers.
|
||||
error("cannot generate condition enumeration: conditon '%s' has "
|
||||
"different numbers in different blocks (use `re2c:condenumprefix` "
|
||||
"configuration to set per-block prefix)", sc.name.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conds.push_back(sc);
|
||||
}
|
||||
|
||||
static void add_conditions_from_blocks(const blocks_t &blocks, StartConds &conds)
|
||||
{
|
||||
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||
const OutputBlock &block = *blocks[i];
|
||||
for (size_t i = 0; i < block.conds.size(); ++i) {
|
||||
add_condition_from_block(block, conds, block.conds[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void expand_cond_enum(CodegenCtxPass1 &ctx, Code *code)
|
||||
{
|
||||
Scratchbuf &buf = ctx.global->scratchbuf;
|
||||
@@ -228,34 +151,37 @@ static void expand_cond_enum(CodegenCtxPass1 &ctx, Code *code)
|
||||
return;
|
||||
}
|
||||
|
||||
StartConds conds;
|
||||
if (code->fmt.block_names == NULL) {
|
||||
// Gather conditions from all blocks in the output and header files.
|
||||
add_conditions_from_blocks(ctx.global->cblocks, conds);
|
||||
add_conditions_from_blocks(ctx.global->hblocks, conds);
|
||||
// Use the global set of conditions accumulated from all blocks.
|
||||
gen_cond_enum(buf, alc, code, globopts, ctx.global->conds);
|
||||
} else {
|
||||
// Gather conditions from the blocks on the list.
|
||||
find_blocks(ctx, code->fmt.block_names, ctx.global->tmpblocks, "types:re2c");
|
||||
add_conditions_from_blocks(ctx.global->tmpblocks, conds);
|
||||
uniq_vector_t<std::string> conds;
|
||||
for (BlockNameList *p = code->fmt.block_names; p; p = p->next) {
|
||||
const OutputBlock *b = find_block_with_name(ctx, p->name, "types:re2c");
|
||||
if (!b) exit(1);
|
||||
for (size_t i = 0; i < b->conds.size(); ++i) {
|
||||
// Condition prefix is specific to the block that defines it.
|
||||
// If a few blocks define conditions with the same name, but a
|
||||
// different prefix, they result in different enum entries.
|
||||
conds.find_or_add(b->opts->condEnumPrefix + b->conds[i]);
|
||||
}
|
||||
}
|
||||
gen_cond_enum(buf, alc, code, globopts, conds);
|
||||
}
|
||||
|
||||
// Do not generate empty condition enum. Some compilers or language standards
|
||||
// allow it, but generally it's more likely to indicate an error in user code.
|
||||
if (conds.empty()) {
|
||||
code->kind = CODE_EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
gen_cond_enum(buf, alc, code, globopts, conds);
|
||||
}
|
||||
|
||||
static void gen_state_goto_cases(CodegenCtxPass1 &ctx, CodeCases *cases,
|
||||
const OutputBlock *block)
|
||||
{
|
||||
code_alc_t &alc = ctx.global->allocator;
|
||||
for (storable_states_t::const_iterator i = block->fill_goto.begin();
|
||||
i != block->fill_goto.end(); ++i) {
|
||||
append(cases, code_case_number(alc, i->second, static_cast<int32_t>(i->first)));
|
||||
|
||||
uint32_t index_count = block->fill_index_end - block->fill_index_start;
|
||||
DASSERT(index_count <= block->fill_goto.size());
|
||||
|
||||
for (uint32_t i = 0; i < index_count; ++i) {
|
||||
append(cases, code_case_number(alc, block->fill_goto[i],
|
||||
static_cast<int32_t>(i + block->fill_index_start)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,10 +200,6 @@ static void gen_state_goto(CodegenCtxPass1 &ctx, Code *code)
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop/switch approach is handled differently (by appending special cases
|
||||
// to the state switch).
|
||||
DASSERT(!globopts->loop_switch);
|
||||
|
||||
Scratchbuf &o = ctx.global->scratchbuf;
|
||||
code_alc_t &alc = ctx.global->allocator;
|
||||
const char *text;
|
||||
@@ -323,18 +245,19 @@ static void gen_state_goto(CodegenCtxPass1 &ctx, Code *code)
|
||||
}
|
||||
} else {
|
||||
// Generate a switch for all specified named blocks.
|
||||
blocks_t &blocks = ctx.global->tmpblocks;
|
||||
find_blocks(ctx, code->fmt.block_names, blocks, "getstate:re2c");
|
||||
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||
const OutputBlock *b = blocks[i];
|
||||
for (BlockNameList *p = code->fmt.block_names; p; p = p->next) {
|
||||
const OutputBlock *b = find_block_with_name(ctx, p->name, "getstate:re2c");
|
||||
if (!b) exit(1);
|
||||
if (!b->start_label) {
|
||||
error("block '%s' does not generate code, so it should not be"
|
||||
" listed in `getstate:re2c` directive", b->name.c_str());
|
||||
" listed in `getstate:re2c` directive", p->name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gen_state_goto_cases(ctx, cases, b);
|
||||
|
||||
// Use start label of the first block on the list.
|
||||
if (!bstart) bstart = b;
|
||||
gen_state_goto_cases(ctx, cases, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +283,7 @@ static void gen_state_goto(CodegenCtxPass1 &ctx, Code *code)
|
||||
}
|
||||
|
||||
CodeList *stmts = code_list(alc);
|
||||
text = o.str(output_state_get(globopts)).flush();
|
||||
text = o.str(globopts->state_get).cstr(globopts->state_get_naked ? "" : "()").flush();
|
||||
append(stmts, code_switch(alc, text, cases));
|
||||
|
||||
if (globopts->bUseStateNext) {
|
||||
@@ -399,45 +322,6 @@ static void gen_yyaccept_def(const opt_t *opts, Code *code, bool used_yyaccept)
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_yystate_def(CodegenCtxPass1 &ctx, Code *code)
|
||||
{
|
||||
const opt_t *opts = ctx.block->opts;
|
||||
Scratchbuf &o = ctx.global->scratchbuf;
|
||||
|
||||
if (opts->loop_switch) {
|
||||
code->kind = CODE_VAR;
|
||||
code->var.name = o.str(opts->yystate).flush();
|
||||
if (opts->fFlag) {
|
||||
// With storable state `yystate` should be initialized to YYGETSTATE.
|
||||
// Since there is a -1 case, `yystate` should have a signed type.
|
||||
// If conditions are also used, YYGETSTATE takes priority over YYGETCONDITION,
|
||||
// because the lexer may be reentered after an YYFILL invocation. In that case
|
||||
// we use YYSETSTATE instead of YYSETCONDITION in the final states.
|
||||
code->var.type = "int";
|
||||
code->var.init = o.str(output_state_get(opts)).flush();
|
||||
} else if (opts->cFlag) {
|
||||
// Else with start conditions yystate should be initialized to YYGETCONDITION.
|
||||
code->var.type = "unsigned int";
|
||||
code->var.init = o.str(output_cond_get(opts)).flush();
|
||||
} else {
|
||||
// Else it should be the start DFA state (always case 0 with --loop-switch).
|
||||
code->var.type = "unsigned int";
|
||||
code->var.init = "0";
|
||||
}
|
||||
} else {
|
||||
code->kind = CODE_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t max_among_blocks(const blocks_t &blocks, size_t max, CodeKind kind)
|
||||
{
|
||||
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||
const OutputBlock &block = *blocks[i];
|
||||
max = std::max(max, kind == CODE_MAXFILL ? block.max_fill : block.max_nmatch);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
static void gen_yymax(CodegenCtxPass1 &ctx, Code *code)
|
||||
{
|
||||
const opt_t *opts = ctx.block->opts;
|
||||
@@ -448,19 +332,22 @@ static void gen_yymax(CodegenCtxPass1 &ctx, Code *code)
|
||||
return;
|
||||
}
|
||||
|
||||
CodeKind kind = code->kind;
|
||||
const char *dirname = kind == CODE_MAXFILL ? "max:re2c" : "maxnmatch:re2c";
|
||||
const char *varname = kind == CODE_MAXFILL ? "YYMAXFILL" : "YYMAXNMATCH";
|
||||
bool is_maxfill = (code->kind == CODE_MAXFILL);
|
||||
const char *dirname = is_maxfill ? "max:re2c" : "maxnmatch:re2c";
|
||||
const char *varname = is_maxfill ? "YYMAXFILL" : "YYMAXNMATCH";
|
||||
|
||||
size_t max = 1;
|
||||
size_t max;
|
||||
if (code->fmt.block_names == NULL) {
|
||||
// Gather max value from all blocks in the output and header files.
|
||||
max = max_among_blocks(ctx.global->cblocks, max, kind);
|
||||
max = max_among_blocks(ctx.global->hblocks, max, kind);
|
||||
// Global maximum in the file.
|
||||
max = is_maxfill ? ctx.global->max_fill : ctx.global->max_nmatch;
|
||||
} else {
|
||||
// Maximum among the blocks listed in the directive.
|
||||
find_blocks(ctx, code->fmt.block_names, ctx.global->tmpblocks, dirname);
|
||||
max = max_among_blocks(ctx.global->tmpblocks, max, kind);
|
||||
max = 0;
|
||||
for (BlockNameList *p = code->fmt.block_names; p; p = p->next) {
|
||||
const OutputBlock *b = find_block_with_name(ctx, p->name, dirname);
|
||||
if (!b) exit(1);
|
||||
max = std::max(max, is_maxfill ? b->max_fill : b->max_nmatch);
|
||||
}
|
||||
}
|
||||
|
||||
if (code->fmt.format) {
|
||||
@@ -501,59 +388,65 @@ static void gen_yymax(CodegenCtxPass1 &ctx, Code *code)
|
||||
* dispatch shrinks to unconditional jump
|
||||
*/
|
||||
|
||||
static CodeList *gen_cond_goto_binary(CodegenCtxPass1 &ctx, size_t lower, size_t upper)
|
||||
static std::string output_cond_get(const opt_t *opts)
|
||||
{
|
||||
const opt_t *opts = ctx.block->opts;
|
||||
code_alc_t &alc = ctx.global->allocator;
|
||||
Scratchbuf &o = ctx.global->scratchbuf;
|
||||
return opts->cond_get + (opts->cond_get_naked ? "" : "()");
|
||||
}
|
||||
|
||||
static CodeList *gen_cond_goto_binary(Scratchbuf &o, code_alc_t &alc,
|
||||
const std::vector<std::string> &conds, const opt_t *opts,
|
||||
size_t lower, size_t upper)
|
||||
{
|
||||
CodeList *stmts = code_list(alc);
|
||||
const char *text;
|
||||
|
||||
if (lower == upper) {
|
||||
o.cstr("goto ").str(opts->condPrefix).str(ctx.block->conds[lower].name);
|
||||
append(stmts, code_stmt(alc, o.flush()));
|
||||
} else {
|
||||
const size_t middle = lower + (upper - lower + 1) / 2;
|
||||
CodeList *if_then = gen_cond_goto_binary(ctx, lower, middle - 1);
|
||||
CodeList *if_else = gen_cond_goto_binary(ctx, middle, upper);
|
||||
o.str(output_cond_get(opts)).cstr(" < ").u64(middle);
|
||||
append(stmts, code_if_then_else(alc, o.flush(), if_then, if_else));
|
||||
text = o.cstr("goto ").str(opts->condPrefix).str(conds[lower]).flush();
|
||||
append(stmts, code_stmt(alc, text));
|
||||
}
|
||||
else {
|
||||
const size_t middle = lower + (upper - lower + 1) / 2;
|
||||
text = o.str(output_cond_get(opts)).cstr(" < ").u64(middle).flush();
|
||||
CodeList *if_then = gen_cond_goto_binary(o, alc, conds, opts, lower, middle - 1);
|
||||
CodeList *if_else = gen_cond_goto_binary(o, alc, conds, opts, middle, upper);
|
||||
append(stmts, code_if_then_else(alc, text, if_then, if_else));
|
||||
}
|
||||
|
||||
return stmts;
|
||||
}
|
||||
|
||||
static void gen_cond_goto(CodegenCtxPass1 &ctx, Code *code)
|
||||
static void gen_cond_goto(Scratchbuf &o, code_alc_t &alc, Code *code,
|
||||
const std::vector<std::string> &conds, const opt_t *opts, Msg &msg,
|
||||
bool warn_cond_ord, const loc_t &loc)
|
||||
{
|
||||
const opt_t *opts = ctx.block->opts;
|
||||
code_alc_t &alc = ctx.global->allocator;
|
||||
Scratchbuf &o = ctx.global->scratchbuf;
|
||||
const StartConds &conds = ctx.block->conds;
|
||||
bool warn_cond_ord = ctx.global->warn_cond_ord;
|
||||
|
||||
const size_t ncond = conds.size();
|
||||
CodeList *stmts = code_list(alc);
|
||||
const char *text;
|
||||
|
||||
if (opts->target == TARGET_DOT) {
|
||||
for (size_t i = 0; i < ncond; ++i) {
|
||||
const std::string &cond = conds[i].name;
|
||||
const std::string &cond = conds[i];
|
||||
text = o.cstr("0 -> ").str(cond).cstr(" [label=\"state=").str(cond)
|
||||
.cstr("\"]").flush();
|
||||
append(stmts, code_text(alc, text));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (opts->gFlag) {
|
||||
text = o.cstr("goto *").str(opts->yyctable).cstr("[")
|
||||
.str(output_cond_get(opts)).cstr("]").flush();
|
||||
append(stmts, code_stmt(alc, text));
|
||||
} else if (opts->sFlag) {
|
||||
}
|
||||
else if (opts->sFlag) {
|
||||
warn_cond_ord &= ncond > 1;
|
||||
append(stmts, gen_cond_goto_binary(ctx, 0, ncond - 1));
|
||||
} else {
|
||||
append(stmts, gen_cond_goto_binary(o, alc, conds, opts, 0, ncond - 1));
|
||||
}
|
||||
else {
|
||||
warn_cond_ord = false;
|
||||
|
||||
CodeCases *ccases = code_cases(alc);
|
||||
for (size_t i = 0; i < ncond; ++i) {
|
||||
const std::string &cond = conds[i].name;
|
||||
const std::string &cond = conds[i];
|
||||
|
||||
CodeList *body = code_list(alc);
|
||||
text = o.cstr("goto ").str(opts->condPrefix).str(cond).flush();
|
||||
@@ -569,7 +462,7 @@ static void gen_cond_goto(CodegenCtxPass1 &ctx, Code *code)
|
||||
// see note [condition order]
|
||||
warn_cond_ord &= opts->header_file.empty();
|
||||
if (warn_cond_ord) {
|
||||
ctx.global->msg.warn.condition_order(ctx.block->loc);
|
||||
msg.warn.condition_order(loc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,23 +471,22 @@ static void gen_cond_goto(CodegenCtxPass1 &ctx, Code *code)
|
||||
code->block.fmt = CodeBlock::RAW;
|
||||
}
|
||||
|
||||
static void gen_cond_table(CodegenCtxPass1 &ctx, Code *code)
|
||||
static void gen_cond_table(Scratchbuf &o, code_alc_t &alc, Code *code,
|
||||
const std::vector<std::string> &conds, const opt_t *opts)
|
||||
{
|
||||
const opt_t *opts = ctx.block->opts;
|
||||
code_alc_t &alc = ctx.global->allocator;
|
||||
Scratchbuf &o = ctx.global->scratchbuf;
|
||||
const StartConds &conds = ctx.block->conds;
|
||||
const size_t ncond = conds.size();
|
||||
|
||||
CodeList *stmts = code_list(alc);
|
||||
const char *text;
|
||||
|
||||
o.cstr("static void *").str(opts->yyctable).cstr("[").u64(ncond).cstr("] = {");
|
||||
append(stmts, code_text(alc, o.flush()));
|
||||
text = o.cstr("static void *").str(opts->yyctable).cstr("[").u64(ncond)
|
||||
.cstr("] = {").flush();
|
||||
append(stmts, code_text(alc, text));
|
||||
|
||||
CodeList *block = code_list(alc);
|
||||
for (size_t i = 0; i < ncond; ++i) {
|
||||
o.cstr("&&").str(opts->condPrefix).str(conds[i].name).cstr(",");
|
||||
append(block, code_text(alc, o.flush()));
|
||||
text = o.cstr("&&").str(opts->condPrefix).str(conds[i]).cstr(",").flush();
|
||||
append(block, code_text(alc, text));
|
||||
}
|
||||
append(stmts, code_block(alc, block, CodeBlock::INDENTED));
|
||||
|
||||
@@ -616,6 +508,9 @@ static void expand_pass_1_list(CodegenCtxPass1 &ctx, CodeList *stmts)
|
||||
void expand_pass_1(CodegenCtxPass1 &ctx, Code *code)
|
||||
{
|
||||
const opt_t *opts = ctx.block->opts;
|
||||
Scratchbuf &buf = ctx.global->scratchbuf;
|
||||
code_alc_t &alc = ctx.global->allocator;
|
||||
|
||||
switch (code->kind) {
|
||||
case CODE_BLOCK:
|
||||
expand_pass_1_list(ctx, code->block.stmts);
|
||||
@@ -629,9 +524,6 @@ void expand_pass_1(CodegenCtxPass1 &ctx, Code *code)
|
||||
expand_pass_1_list(ctx, x->body);
|
||||
}
|
||||
break;
|
||||
case CODE_LOOP:
|
||||
expand_pass_1_list(ctx, code->loop);
|
||||
break;
|
||||
case CODE_STAGS:
|
||||
case CODE_MTAGS:
|
||||
expand_tags_directive(ctx, code);
|
||||
@@ -646,17 +538,15 @@ void expand_pass_1(CodegenCtxPass1 &ctx, Code *code)
|
||||
case CODE_YYACCEPT:
|
||||
gen_yyaccept_def(opts, code, ctx.block->used_yyaccept);
|
||||
break;
|
||||
case CODE_YYSTATE:
|
||||
gen_yystate_def(ctx, code);
|
||||
break;
|
||||
case CODE_COND_ENUM:
|
||||
expand_cond_enum(ctx, code);
|
||||
break;
|
||||
case CODE_COND_GOTO:
|
||||
gen_cond_goto(ctx, code);
|
||||
gen_cond_goto(buf, alc, code, ctx.block->conds, opts,
|
||||
ctx.global->msg, ctx.global->warn_cond_ord, ctx.block->loc);
|
||||
break;
|
||||
case CODE_COND_TABLE:
|
||||
gen_cond_table(ctx, code);
|
||||
gen_cond_table(buf, alc, code, ctx.block->conds, opts);
|
||||
break;
|
||||
case CODE_STATE_GOTO:
|
||||
gen_state_goto(ctx, code);
|
||||
@@ -728,9 +618,6 @@ void expand_pass_2(CodegenCtxPass2 &ctx, Code *code)
|
||||
expand_pass_2_list(ctx, x->body);
|
||||
}
|
||||
break;
|
||||
case CODE_LOOP:
|
||||
expand_pass_2_list(ctx, code->loop);
|
||||
break;
|
||||
case CODE_LABEL:
|
||||
gen_label(ctx.scratchbuf, ctx.opts, code);
|
||||
break;
|
||||
|
||||
+49
-138
@@ -40,9 +40,7 @@ static void emit_state(Output &output, const State *s, CodeList *stmts)
|
||||
Scratchbuf &o = output.scratchbuf;
|
||||
const char *text;
|
||||
|
||||
if (!opts->loop_switch) {
|
||||
append(stmts, code_nlabel(alc, s->label));
|
||||
}
|
||||
append(stmts, code_nlabel(alc, s->label));
|
||||
|
||||
if (opts->dFlag && (s->action.type != Action::INITIAL)) {
|
||||
text = o.str(opts->yydebug).cstr("(").label(*s->label).cstr(", ")
|
||||
@@ -51,84 +49,31 @@ static void emit_state(Output &output, const State *s, CodeList *stmts)
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_storable_state_cases(Output &output, CodeCases *cases)
|
||||
{
|
||||
OutputBlock &block = output.block();
|
||||
const opt_t *opts = block.opts;
|
||||
code_alc_t &alc = output.allocator;
|
||||
|
||||
if (!opts->fFlag || !opts->loop_switch) return;
|
||||
|
||||
// TODO: If `re2c:eof` is not used, some of these cases are redundant (they contain a
|
||||
// single transition to the DFA state that has the corresponding YYFILL invocation).
|
||||
for (storable_states_t::const_iterator i = block.fill_goto.begin();
|
||||
i != block.fill_goto.end(); ++i) {
|
||||
append(cases, code_case_number(alc, i->second, static_cast<int32_t>(i->first)));
|
||||
}
|
||||
|
||||
CodeList *start_case = code_list(alc);
|
||||
if (opts->lang == LANG_GO) {
|
||||
append(start_case, code_stmt(alc, "fallthrough"));
|
||||
}
|
||||
prepend(cases, code_case_number(alc, start_case, -1));
|
||||
}
|
||||
|
||||
void gen_dfa_as_blocks_with_labels(Output &output, const DFA &dfa, CodeList *stmts)
|
||||
void DFA::emit_body(Output &output, CodeList *stmts) const
|
||||
{
|
||||
const opt_t *opts = output.block().opts;
|
||||
code_alc_t &alc = output.allocator;
|
||||
Scratchbuf &o = output.scratchbuf;
|
||||
const char *text;
|
||||
|
||||
gen_settags(output, stmts, dfa, dfa.tags0, /*delayed*/ false);
|
||||
gen_settags(output, stmts, *this, tags0, false /* delayed */);
|
||||
|
||||
// If DFA has transitions into the initial state and --eager-skip option is not used,
|
||||
// then the initial state must have a YYSKIP statement that must be bypassed when
|
||||
// first entering the DFA. With --loop-switch that would be impossible, because there
|
||||
// can be no transitions in the middle of a state.
|
||||
DASSERT(!opts->loop_switch);
|
||||
if (dfa.head->label->used && !opts->eager_skip) {
|
||||
dfa.initial_label->used = true;
|
||||
o.cstr("goto ").str(opts->labelPrefix).label(*dfa.initial_label);
|
||||
append(stmts, code_stmt(alc, o.flush()));
|
||||
// If DFA has transitions to initial state, then initial state
|
||||
// has a piece of code that advances input position. Wee must
|
||||
// skip it when entering DFA.
|
||||
if (head->label->used) {
|
||||
initial_label->used = true;
|
||||
text = o.cstr("goto ").str(opts->labelPrefix).label(*initial_label).flush();
|
||||
append(stmts, code_stmt(alc, text));
|
||||
}
|
||||
|
||||
for (State *s = dfa.head; s; s = s->next) {
|
||||
for (State * s = head; s; s = s->next) {
|
||||
emit_state(output, s, stmts);
|
||||
emit_action(output, dfa, s, stmts);
|
||||
gen_go(output, dfa, &s->go, s, stmts);
|
||||
emit_action(output, *this, s, stmts);
|
||||
gen_go(output, *this, &s->go, s, stmts);
|
||||
}
|
||||
}
|
||||
|
||||
void gen_dfa_as_switch_cases(Output &output, DFA &dfa, CodeCases *cases)
|
||||
{
|
||||
const opt_t *opts = output.block().opts;
|
||||
code_alc_t &alc = output.allocator;
|
||||
|
||||
DASSERT(opts->loop_switch);
|
||||
DASSERT(dfa.tags0 == TCID0);
|
||||
|
||||
for (State *s = dfa.head; s; s = s->next) {
|
||||
CodeList *body = code_list(alc);
|
||||
emit_state(output, s, body);
|
||||
emit_action(output, dfa, s, body);
|
||||
gen_go(output, dfa, &s->go, s, body);
|
||||
append(cases, code_case_number(alc, body, static_cast<int32_t>(s->label->index)));
|
||||
}
|
||||
}
|
||||
|
||||
void wrap_dfas_in_loop_switch(Output &output, CodeList *stmts, CodeCases *cases)
|
||||
{
|
||||
const opt_t *opts = output.block().opts;
|
||||
code_alc_t &alc = output.allocator;
|
||||
|
||||
DASSERT(opts->loop_switch);
|
||||
|
||||
CodeList* loop = code_list(alc);
|
||||
gen_storable_state_cases(output, cases);
|
||||
append(loop, code_switch(alc, opts->yystate.c_str(), cases));
|
||||
append(stmts, code_loop(alc, loop));
|
||||
}
|
||||
|
||||
void DFA::emit_dot(Output &output, CodeList *program) const
|
||||
{
|
||||
code_alc_t &alc = output.allocator;
|
||||
@@ -198,50 +143,28 @@ void gen_code(Output &output, dfas_t &dfas)
|
||||
const bool first = i == b;
|
||||
DFA &dfa = *(*i);
|
||||
|
||||
if (opts->loop_switch && (first || opts->target == TARGET_SKELETON)) {
|
||||
// With loop/switch there are no labels, and each block has its own state
|
||||
// switch where all conditions are joined. Restart state counter from zero so
|
||||
// that cases start from zero. With skeleton conditions are separate.
|
||||
output.label_counter = 0;
|
||||
if (first) {
|
||||
if (opts->startlabel_force) {
|
||||
// User-enforced start label.
|
||||
dfa.start_label = new_label(alc, output.label_counter++);
|
||||
dfa.start_label->used = true;
|
||||
} else if (opts->fFlag) {
|
||||
// Start label is needed in `-f` mode: it points to state 0 (the
|
||||
// beginning of block, before condition dispatch in `-c` mode).
|
||||
dfa.start_label = new_label(alc, output.label_counter++);
|
||||
}
|
||||
oblock.start_label = dfa.start_label;
|
||||
}
|
||||
|
||||
if (!opts->loop_switch) {
|
||||
if (first) {
|
||||
if (opts->startlabel_force) {
|
||||
// User-enforced start label.
|
||||
dfa.start_label = new_label(alc, output.label_counter++);
|
||||
dfa.start_label->used = true;
|
||||
} else if (opts->fFlag) {
|
||||
// Start label is needed in `-f` mode: it points to state 0 (the
|
||||
// beginning of block, before condition dispatch in `-c` mode).
|
||||
dfa.start_label = new_label(alc, output.label_counter++);
|
||||
}
|
||||
oblock.start_label = dfa.start_label;
|
||||
}
|
||||
// Initial label points to the beginning of the DFA (after condition
|
||||
// dispatch in `-c` mode).
|
||||
dfa.initial_label = new_label(alc, output.label_counter++);
|
||||
dfa.head->action.set_initial();
|
||||
}
|
||||
// Initial label points to the beginning of the DFA (after condition
|
||||
// dispatch in `-c` mode).
|
||||
dfa.initial_label = new_label(alc, output.label_counter++);
|
||||
dfa.head->action.set_initial();
|
||||
|
||||
for (State *s = dfa.head; s; s = s->next) {
|
||||
s->label = new_label(alc, output.label_counter++);
|
||||
}
|
||||
|
||||
// With loop/switch storable states need their own cases in the state switch, as
|
||||
// they have some logic on top of transition to the state that invoked YYFILL.
|
||||
// Give them continuous indices after the last state index.
|
||||
if (opts->loop_switch && opts->fFlag) {
|
||||
oblock.fill_index = output.label_counter;
|
||||
}
|
||||
|
||||
if (!dfa.cond.empty()) {
|
||||
// If loop/switch is used, condition numbers are the numeric indices of their
|
||||
// initial DFA state. Otherwise we do not assign explicit numbers, and
|
||||
// conditions are implicitly assigned consecutive numbers starting from zero.
|
||||
StartCond sc = {dfa.cond, opts->loop_switch ? dfa.head->label->index : 0};
|
||||
oblock.conds.push_back(sc);
|
||||
}
|
||||
|
||||
if (opts->bFlag) {
|
||||
dfa.bitmap = code_bitmap(alc, std::min(dfa.ubChar, 256u));
|
||||
for (State *s = dfa.head; s; s = s->next) {
|
||||
@@ -282,7 +205,6 @@ void gen_code(Output &output, dfas_t &dfas)
|
||||
|
||||
const char *text;
|
||||
CodeList *program1 = code_list(alc);
|
||||
CodeCases *cases = code_cases(alc);
|
||||
for (i = b; i != e; ++i) {
|
||||
const bool first = i == b;
|
||||
DFA &dfa = *(*i);
|
||||
@@ -298,9 +220,6 @@ void gen_code(Output &output, dfas_t &dfas)
|
||||
append(program1, code_yych_decl(alc));
|
||||
append(program1, code_yyaccept_def(alc));
|
||||
}
|
||||
if (first) {
|
||||
append(program1, code_yystate_def(alc));
|
||||
}
|
||||
|
||||
if (!is_cond_block && bms) {
|
||||
append(program1, bms);
|
||||
@@ -310,7 +229,7 @@ void gen_code(Output &output, dfas_t &dfas)
|
||||
append(program1, code_cond_table(alc));
|
||||
}
|
||||
|
||||
if (opts->fFlag && !output.state_goto && !opts->loop_switch) {
|
||||
if (opts->fFlag && !output.state_goto) {
|
||||
append(program1, code_state_goto(alc,
|
||||
block_list_for_implicit_state_goto(alc, oblock)));
|
||||
output.state_goto = true;
|
||||
@@ -327,11 +246,12 @@ void gen_code(Output &output, dfas_t &dfas)
|
||||
append(program1, code_slabel(alc, text));
|
||||
}
|
||||
|
||||
if (is_cond_block && !opts->loop_switch) {
|
||||
if (!output.cond_goto) {
|
||||
append(program1, code_cond_goto(alc));
|
||||
output.cond_goto = true;
|
||||
}
|
||||
if (is_cond_block && !output.cond_goto) {
|
||||
append(program1, code_cond_goto(alc));
|
||||
output.cond_goto = true;
|
||||
}
|
||||
|
||||
if (is_cond_block && !dfa.cond.empty()) {
|
||||
if (opts->condDivider.length()) {
|
||||
o.str(opts->condDivider);
|
||||
argsubst(o.stream(), opts->condDividerParam, "cond", true, dfa.cond);
|
||||
@@ -341,28 +261,19 @@ void gen_code(Output &output, dfas_t &dfas)
|
||||
append(program1, code_slabel(alc, text));
|
||||
}
|
||||
|
||||
if (!opts->loop_switch) {
|
||||
// In the goto/label mode, generate DFA states as blocks of code preceded
|
||||
// with labels, and `goto` transitions between states.
|
||||
CodeList *body = code_list(alc);
|
||||
gen_dfa_as_blocks_with_labels(output, dfa, body);
|
||||
if (is_cond_block && bms) {
|
||||
CodeList *block = code_list(alc);
|
||||
append(block, bms);
|
||||
append(block, body);
|
||||
append(program1, code_block(alc, block, CodeBlock::WRAPPED));
|
||||
} else {
|
||||
append(program1, body);
|
||||
}
|
||||
} else {
|
||||
// In the loop/switch mode append all DFA states as cases of the `yystate`
|
||||
// switch. Merge DFAs for different conditions together in one switch.
|
||||
DASSERT(!bms);
|
||||
gen_dfa_as_switch_cases(output, dfa, cases);
|
||||
// generate code for DFA
|
||||
CodeList *body = code_list(alc);
|
||||
dfa.emit_body(output, body);
|
||||
|
||||
if (is_cond_block && bms) {
|
||||
CodeList *block = code_list(alc);
|
||||
append(block, bms);
|
||||
append(block, body);
|
||||
append(program1, code_block(alc, block, CodeBlock::WRAPPED));
|
||||
}
|
||||
else {
|
||||
append(program1, body);
|
||||
}
|
||||
}
|
||||
if (opts->loop_switch) {
|
||||
wrap_dfas_in_loop_switch(output, program1, cases);
|
||||
}
|
||||
|
||||
const bool prolog = (opts->fFlag && opts->gFlag)
|
||||
|
||||
+42
-12
@@ -14,6 +14,7 @@
|
||||
#include "src/util/file_utils.h"
|
||||
#include "src/util/string_utils.h"
|
||||
#include "src/util/temp_file.h"
|
||||
#include "src/util/uniq_vector.h"
|
||||
|
||||
|
||||
namespace re2c {
|
||||
@@ -58,8 +59,8 @@ OutputBlock::OutputBlock(InputBlockKind kind, const std::string &name,
|
||||
, max_fill(1)
|
||||
, max_nmatch(1)
|
||||
, start_label(NULL)
|
||||
, fill_index(0)
|
||||
, fill_state(0)
|
||||
, fill_index_start(0)
|
||||
, fill_index_end(0)
|
||||
, fill_goto()
|
||||
{}
|
||||
|
||||
@@ -74,7 +75,7 @@ Output::Output(Msg &msg)
|
||||
, pblocks(&cblocks)
|
||||
, label_counter(0)
|
||||
, state_goto(false)
|
||||
, cond_enum_autogen(true)
|
||||
, cond_enum_in_hdr(false)
|
||||
, cond_goto(false)
|
||||
, warn_condition_order(true)
|
||||
, need_header(false)
|
||||
@@ -168,7 +169,8 @@ void Output::new_block(Opt &opts, InputBlockKind kind, const std::string &name,
|
||||
|
||||
b->opts = opts.snapshot();
|
||||
|
||||
b->fill_index = total_fill_index;
|
||||
b->fill_index_start = total_fill_index;
|
||||
b->fill_index_end = total_fill_index;
|
||||
|
||||
pblocks->push_back(b);
|
||||
|
||||
@@ -181,7 +183,7 @@ void Output::gather_info_from_block()
|
||||
{
|
||||
DASSERT(!pblocks->empty());
|
||||
const OutputBlock *b = pblocks->back();
|
||||
total_fill_index = b->fill_index;
|
||||
total_fill_index = b->fill_index_end;
|
||||
}
|
||||
|
||||
static void fix_first_block_opts(const blocks_t &blocks)
|
||||
@@ -274,6 +276,23 @@ bool Output::emit_blocks(const std::string &fname, const CodegenCtxGlobal &globa
|
||||
return true;
|
||||
}
|
||||
|
||||
static void add_symbols(const OutputBlock &block, CodegenCtxGlobal &ctx)
|
||||
{
|
||||
DASSERT(!block.name.empty());
|
||||
|
||||
const std::string &condenumprefix = block.opts->condEnumPrefix;
|
||||
for (size_t j = 0; j < block.conds.size(); ++j) {
|
||||
ctx.conds.find_or_add(condenumprefix + block.conds[j]);
|
||||
}
|
||||
|
||||
const tagnames_t &st = block.stags, &mt = block.mtags;
|
||||
ctx.stags.insert(st.begin(), st.end());
|
||||
ctx.mtags.insert(mt.begin(), mt.end());
|
||||
|
||||
ctx.max_fill = std::max(ctx.max_fill, block.max_fill);
|
||||
ctx.max_nmatch = std::max(ctx.max_nmatch, block.max_nmatch);
|
||||
}
|
||||
|
||||
bool Output::emit()
|
||||
{
|
||||
if (msg.warn.error()) return false;
|
||||
@@ -283,31 +302,42 @@ bool Output::emit()
|
||||
, scratchbuf
|
||||
, msg
|
||||
, total_opts
|
||||
, cblocks
|
||||
, hblocks
|
||||
, /*pblocks*/ NULL
|
||||
, /*tmpblocks*/ blocks_t()
|
||||
, /*conditions*/ uniq_vector_t<std::string>()
|
||||
, /*stags*/ tagnames_t()
|
||||
, /*mtags*/ tagnames_t()
|
||||
, /*max_fill*/ 1
|
||||
, /*max_nmatch*/ 1
|
||||
, warn_condition_order
|
||||
};
|
||||
|
||||
// gather global data accumulated across all blocks and files
|
||||
for (uint32_t i = 0; i < cblocks.size(); ++i) {
|
||||
add_symbols (*cblocks[i], ctx);
|
||||
}
|
||||
for (uint32_t i = 0; i < hblocks.size(); ++i) {
|
||||
add_symbols (*hblocks[i], ctx);
|
||||
}
|
||||
|
||||
// global options are last block's options
|
||||
const opt_t *opts = block().opts;
|
||||
bool ok = true;
|
||||
|
||||
// Emit header file.
|
||||
// emit .h file
|
||||
if (!opts->header_file.empty() || need_header) {
|
||||
if (opts->cFlag && this->cond_enum_autogen) {
|
||||
// Old-style -t, --type-headers usage implies condition enum.
|
||||
// old-style -t, --type-headers usage implies condition generation
|
||||
if (!ctx.conds.empty() && !this->cond_enum_in_hdr) {
|
||||
header_mode(true);
|
||||
wdelay_stmt(0, code_newline(allocator));
|
||||
wdelay_stmt(0, code_fmt(allocator, CODE_COND_ENUM, NULL, NULL, NULL));
|
||||
header_mode(false);
|
||||
}
|
||||
|
||||
ctx.pblocks = &hblocks;
|
||||
ok &= emit_blocks(opts->header_file, ctx);
|
||||
}
|
||||
|
||||
// Emit output file.
|
||||
// emit .c file
|
||||
ctx.pblocks = &cblocks;
|
||||
ok &= emit_blocks(opts->output_file, ctx);
|
||||
|
||||
|
||||
+68
-116
@@ -226,7 +226,54 @@ void emit_accept(Output &output, CodeList *stmts, const DFA &dfa, const accept_t
|
||||
append(stmts, code_switch(alc, text, cases));
|
||||
}
|
||||
|
||||
static void gen_setstate(Output &output, CodeList *stmts, const char *fillidx)
|
||||
void emit_rule(Output &output, CodeList *stmts, const DFA &dfa, size_t rule_idx)
|
||||
{
|
||||
const opt_t *opts = output.block().opts;
|
||||
const Rule &rule = dfa.rules[rule_idx];
|
||||
const SemAct *semact = rule.semact;
|
||||
const std::string &cond = semact->cond;
|
||||
code_alc_t &alc = output.allocator;
|
||||
Scratchbuf &o = output.scratchbuf;
|
||||
std::string s;
|
||||
const char *text;
|
||||
|
||||
gen_fintags(output, stmts, dfa, rule);
|
||||
|
||||
if (opts->target == TARGET_SKELETON) {
|
||||
emit_skeleton_action(output, stmts, dfa, rule_idx);
|
||||
}
|
||||
else {
|
||||
if (!cond.empty() && dfa.cond != cond) {
|
||||
o.str(opts->cond_set);
|
||||
argsubst(o.stream(), opts->cond_set_arg, "cond", true,
|
||||
opts->condEnumPrefix + cond);
|
||||
if (opts->cond_set_naked) {
|
||||
append(stmts, code_text(alc, o.flush()));
|
||||
} else {
|
||||
o.cstr("(").str(opts->condEnumPrefix).str(cond).cstr(")");
|
||||
append(stmts, code_stmt(alc, o.flush()));
|
||||
}
|
||||
}
|
||||
if (!semact->autogen) {
|
||||
if (!dfa.setup.empty()) {
|
||||
text = o.str(dfa.setup).flush();
|
||||
append(stmts, code_text(alc, text));
|
||||
}
|
||||
append(stmts, code_line_info_input(alc, semact->loc));
|
||||
text = o.str(semact->text).flush();
|
||||
append(stmts, code_text(alc, text));
|
||||
append(stmts, code_line_info_output(alc));
|
||||
}
|
||||
else if (!cond.empty()) {
|
||||
o.str(opts->condGoto);
|
||||
argsubst(o.stream(), opts->condGotoParam, "cond", true,
|
||||
opts->condPrefix + cond);
|
||||
append(stmts, code_text(alc, o.flush()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_setstate(Output &output, CodeList *stmts, uint32_t fillidx)
|
||||
{
|
||||
const opt_t *opts = output.block().opts;
|
||||
code_alc_t &alc = output.allocator;
|
||||
@@ -237,85 +284,11 @@ static void gen_setstate(Output &output, CodeList *stmts, const char *fillidx)
|
||||
if (opts->state_set_naked) {
|
||||
append(stmts, code_text(alc, o.flush()));
|
||||
} else {
|
||||
o.cstr("(").cstr(fillidx).cstr(")");
|
||||
o.cstr("(").u32(fillidx).cstr(")");
|
||||
append(stmts, code_stmt(alc, o.flush()));
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_setcondition(Output &output, CodeList *stmts, const char *cond)
|
||||
{
|
||||
const opt_t *opts = output.block().opts;
|
||||
code_alc_t &alc = output.allocator;
|
||||
Scratchbuf &o = output.scratchbuf;
|
||||
|
||||
o.str(opts->cond_set);
|
||||
argsubst(o.stream(), opts->cond_set_arg, "cond", true, cond);
|
||||
if (opts->cond_set_naked) {
|
||||
append(stmts, code_text(alc, o.flush()));
|
||||
} else {
|
||||
o.cstr("(").cstr(cond).cstr(")");
|
||||
append(stmts, code_stmt(alc, o.flush()));
|
||||
}
|
||||
}
|
||||
|
||||
void emit_rule(Output &output, CodeList *stmts, const DFA &dfa, size_t rule_idx)
|
||||
{
|
||||
const opt_t *opts = output.block().opts;
|
||||
const Rule &rule = dfa.rules[rule_idx];
|
||||
const SemAct *semact = rule.semact;
|
||||
code_alc_t &alc = output.allocator;
|
||||
Scratchbuf &o = output.scratchbuf;
|
||||
|
||||
gen_fintags(output, stmts, dfa, rule);
|
||||
|
||||
if (opts->target == TARGET_SKELETON) {
|
||||
emit_skeleton_action(output, stmts, dfa, rule_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_cond_block = !dfa.cond.empty();
|
||||
const std::string &cond = semact->cond.empty() ? dfa.cond : semact->cond;
|
||||
const char *next = is_cond_block
|
||||
? o.str(opts->condEnumPrefix).str(cond).flush() : "0";
|
||||
|
||||
if (opts->loop_switch && opts->fFlag) {
|
||||
// With loop/switch and storable state we need YYSETSTATE in the final state,
|
||||
// because the user may enclose lexer in an outer loop and expect the next
|
||||
// iteration to start from the initial DFA state. Since `yystate` is initialized
|
||||
// to YYGETSTATE, we need to do YYSETSTATE before the user-defined action.
|
||||
//
|
||||
// If both storable state and start conditions are used, only one of YYGETSTATE
|
||||
// and YYGETCONDITION can be used to initialize `yystate`. It must be YYGETSTATE
|
||||
// because the lexer may be reentered after an YYFILL invocation. Consequently we
|
||||
// need to use YYSETSTATE instead of YYSETCONDITION in the final state to match
|
||||
// YYGETSTATE in `yystate` initialization.
|
||||
gen_setstate(output, stmts, next);
|
||||
} else if (is_cond_block && cond != dfa.cond) {
|
||||
// Omit YYSETCONDITION if the current condition is the same as the new one.
|
||||
gen_setcondition(output, stmts, next);
|
||||
}
|
||||
|
||||
if (!semact->autogen) {
|
||||
// User-defined semantic action.
|
||||
if (!dfa.setup.empty()) append(stmts, code_text(alc, o.str(dfa.setup).flush()));
|
||||
append(stmts, code_line_info_input(alc, semact->loc));
|
||||
append(stmts, code_text(alc, o.str(semact->text).flush()));
|
||||
append(stmts, code_line_info_output(alc));
|
||||
} else if (opts->loop_switch) {
|
||||
// Autogenerated action for the :=> rule, loop/switch mode: set `yystate` to the
|
||||
// initial state of the next condition and continue to the head of the loop.
|
||||
o.str(opts->yystate).cstr(" = ").cstr(next);
|
||||
append(stmts, code_stmt(alc, o.flush()));
|
||||
append(stmts, code_stmt(alc, "continue"));
|
||||
} else {
|
||||
// Autogenerated action for the :=> rule, goto/label mode: emit `cond:goto`
|
||||
// configuration with `cond:goto@cond` replaced by the next condition label.
|
||||
o.str(opts->condGoto);
|
||||
argsubst(o.stream(), opts->condGotoParam, "cond", true, opts->condPrefix + cond);
|
||||
append(stmts, code_text(alc, o.flush()));
|
||||
}
|
||||
}
|
||||
|
||||
static CodeList *gen_fill_falllback(Output &output, const DFA &dfa,
|
||||
const State *from, const State *to)
|
||||
{
|
||||
@@ -357,14 +330,8 @@ static CodeList *gen_fill_falllback(Output &output, const DFA &dfa,
|
||||
|
||||
// go to fallback state
|
||||
fallback->label->used = true;
|
||||
if (!opts->loop_switch) {
|
||||
append(fallback_trans, code_stmt(alc, output.scratchbuf.cstr("goto ")
|
||||
.str(opts->labelPrefix).label(*fallback->label).flush()));
|
||||
} else {
|
||||
append(fallback_trans, code_stmt(alc, output.scratchbuf.str(opts->yystate)
|
||||
.cstr(" = ").label(*fallback->label).flush()));
|
||||
append(fallback_trans, code_stmt(alc, "continue"));
|
||||
}
|
||||
append(fallback_trans, code_stmt(alc, output.scratchbuf.cstr("goto ")
|
||||
.str(opts->labelPrefix).label(*fallback->label).flush()));
|
||||
}
|
||||
else {
|
||||
// Transition can be elided, because control flow "falls through" to an
|
||||
@@ -379,7 +346,7 @@ static void gen_fill(Output &output, CodeList *stmts, const DFA &dfa,
|
||||
{
|
||||
const opt_t *opts = output.block().opts;
|
||||
const bool eof_rule = opts->eof != NOEOF;
|
||||
const uint32_t fillidx = output.block().fill_index - 1;
|
||||
const uint32_t fillidx = output.block().fill_index_end - 1;
|
||||
const size_t need = eof_rule ? 1 : from->fill;
|
||||
code_alc_t &alc = output.allocator;
|
||||
Scratchbuf &o = output.scratchbuf;
|
||||
@@ -389,19 +356,13 @@ static void gen_fill(Output &output, CodeList *stmts, const DFA &dfa,
|
||||
|
||||
// Transition to YYFILL label from the initial state dispatch.
|
||||
CodeList *goto_fill = code_list(alc);
|
||||
if (!opts->loop_switch) {
|
||||
const char *flabel = gen_fill_label(output, fillidx);
|
||||
append(goto_fill, code_stmt(alc, o.cstr("goto ").cstr(flabel).flush()));
|
||||
} else {
|
||||
o.str(opts->yystate).cstr(" = ").u32(output.block().fill_state);
|
||||
append(goto_fill, code_stmt(alc, o.flush()));
|
||||
append(goto_fill, code_stmt(alc, "continue"));
|
||||
}
|
||||
const char *flabel = gen_fill_label(output, fillidx);
|
||||
append(goto_fill, code_stmt(alc, o.cstr("goto ").cstr(flabel).flush()));
|
||||
|
||||
CodeList *fill = code_list(alc);
|
||||
|
||||
if (opts->fFlag) {
|
||||
gen_setstate(output, eof_rule ? fill : stmts, o.u32(fillidx).flush());
|
||||
gen_setstate(output, eof_rule ? fill : stmts, fillidx);
|
||||
}
|
||||
|
||||
if (opts->fill_use) {
|
||||
@@ -446,7 +407,7 @@ static void gen_fill(Output &output, CodeList *stmts, const DFA &dfa,
|
||||
}
|
||||
}
|
||||
if (opts->fFlag) {
|
||||
output.block().fill_goto[fillidx] = goto_fill;
|
||||
output.block().fill_goto.push_back(goto_fill);
|
||||
}
|
||||
|
||||
if (opts->fill_check && fill->head) {
|
||||
@@ -468,8 +429,7 @@ void gen_fill_and_label(Output &output, CodeList *stmts, const DFA &dfa, const S
|
||||
const bool need_fill_label = need_fill_on_trans || (need_fill_in_state && opts->fFlag);
|
||||
|
||||
if (need_fill_label) {
|
||||
++output.block().fill_index;
|
||||
output.block().fill_state = s->label->index;
|
||||
++output.block().fill_index_end;
|
||||
}
|
||||
|
||||
if (need_fill_in_state) {
|
||||
@@ -485,8 +445,8 @@ void gen_fill_and_label(Output &output, CodeList *stmts, const DFA &dfa, const S
|
||||
gen_settags(output, stmts, dfa, s->go.tags, opts->stadfa /* delayed */);
|
||||
}
|
||||
|
||||
if (need_fill_label && !opts->loop_switch) {
|
||||
const char *flabel = gen_fill_label(output, output.block().fill_index - 1);
|
||||
if (need_fill_label) {
|
||||
const char *flabel = gen_fill_label(output, output.block().fill_index_end - 1);
|
||||
append(stmts, code_slabel(output.allocator, flabel));
|
||||
}
|
||||
}
|
||||
@@ -515,14 +475,8 @@ void gen_goto(Output &output, const DFA &dfa, CodeList *stmts, const State *from
|
||||
|
||||
if (!jump.elide) {
|
||||
jump.to->label->used = true;
|
||||
if (!opts->loop_switch) {
|
||||
text = o.cstr("goto ").str(opts->labelPrefix).label(*jump.to->label).flush();
|
||||
append(stmts, code_stmt(alc, text));
|
||||
} else {
|
||||
text = o.str(opts->yystate).cstr(" = ").label(*jump.to->label).flush();
|
||||
append(stmts, code_stmt(alc, text));
|
||||
append(stmts, code_stmt(alc, "continue"));
|
||||
}
|
||||
text = o.cstr("goto ").str(opts->labelPrefix).label(*jump.to->label).flush();
|
||||
append(stmts, code_stmt(alc, text));
|
||||
}
|
||||
else {
|
||||
// Goto can be elided, because control flow "falls through" to the
|
||||
@@ -723,7 +677,7 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
|
||||
|
||||
CodeList *varops = code_list(alc);
|
||||
CodeList *fixops = code_list(alc);
|
||||
CodeList *trailops = code_list(alc);
|
||||
CodeList *fixtrailops = code_list(alc);
|
||||
CodeList *fixpostops = code_list(alc);
|
||||
std::string negtag;
|
||||
|
||||
@@ -741,9 +695,9 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
|
||||
if (trailing(tag)) {
|
||||
const bool notag = dfa.oldstyle_ctxmarker;
|
||||
if (generic) {
|
||||
gen_restorectx(output, trailops, notag ? "" : expr);
|
||||
gen_restorectx(output, varops, notag ? "" : expr);
|
||||
} else {
|
||||
gen_assign(output, trailops, opts->yycursor,
|
||||
gen_assign(output, varops, opts->yycursor,
|
||||
notag ? opts->yyctxmarker : expr);
|
||||
}
|
||||
} else {
|
||||
@@ -762,9 +716,9 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
|
||||
DASSERT(tag.toplevel);
|
||||
if (generic) {
|
||||
if (!fixed_on_cursor) {
|
||||
gen_restorectx(output, trailops, base);
|
||||
gen_restorectx(output, fixtrailops, base);
|
||||
}
|
||||
gen_shift(output, trailops, -dist, "", false /* unused */);
|
||||
gen_shift(output, fixtrailops, -dist, "", false /* unused */);
|
||||
} else {
|
||||
if (!fixed_on_cursor) {
|
||||
o.str(opts->yycursor).cstr(" = ").str(base);
|
||||
@@ -772,7 +726,7 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
|
||||
} else if (dist > 0) {
|
||||
o.str(opts->yycursor).cstr(" -= ").i32(dist);
|
||||
}
|
||||
append(trailops, code_stmt(alc, o.flush()));
|
||||
append(fixtrailops, code_stmt(alc, o.flush()));
|
||||
}
|
||||
} else {
|
||||
DASSERT(!fintags.empty());
|
||||
@@ -824,11 +778,9 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
|
||||
}
|
||||
}
|
||||
|
||||
// Variable tags must be set before fixed tags which depend on them. Trailing context
|
||||
// is updated after all tags, because fixed tags may depend on the rightmost position.
|
||||
append(stmts, varops);
|
||||
append(stmts, fixtrailops);
|
||||
append(stmts, fixops);
|
||||
append(stmts, trailops);
|
||||
|
||||
if (!negtag.empty()) {
|
||||
// With generic API there is no explicit negative NULL value, so it is
|
||||
|
||||
@@ -334,31 +334,6 @@ static void render_func(RenderContext &rctx, const CodeFunc *func)
|
||||
++rctx.line;
|
||||
}
|
||||
|
||||
static void render_loop(RenderContext &rctx, const CodeList *loop)
|
||||
{
|
||||
std::ostringstream &os = rctx.os;
|
||||
const opt_t *opts = rctx.opts;
|
||||
|
||||
os << indent(rctx.ind, opts->indString);
|
||||
switch (opts->lang) {
|
||||
case LANG_C:
|
||||
os << "for (;;) {";
|
||||
break;
|
||||
case LANG_GO:
|
||||
os << "for {";
|
||||
break;
|
||||
}
|
||||
os << std::endl;
|
||||
++rctx.line;
|
||||
|
||||
++rctx.ind;
|
||||
render_list(rctx, loop);
|
||||
--rctx.ind;
|
||||
|
||||
os << indent(rctx.ind, opts->indString) << "}" << std::endl;
|
||||
++rctx.line;
|
||||
}
|
||||
|
||||
static inline void yych_conv(std::ostream &os, const opt_t *opts)
|
||||
{
|
||||
if (opts->yychConversion) {
|
||||
@@ -534,9 +509,6 @@ void render(RenderContext &rctx, const Code *code)
|
||||
case CODE_FUNC:
|
||||
render_func(rctx, &code->func);
|
||||
break;
|
||||
case CODE_LOOP:
|
||||
render_loop(rctx, code->loop);
|
||||
break;
|
||||
case CODE_TEXT_RAW:
|
||||
os << code->text << std::endl;
|
||||
line += count_lines_text(code->text) + 1;
|
||||
@@ -604,7 +576,6 @@ void render(RenderContext &rctx, const Code *code)
|
||||
case CODE_MAXNMATCH:
|
||||
case CODE_YYCH:
|
||||
case CODE_YYACCEPT:
|
||||
case CODE_YYSTATE:
|
||||
case CODE_COND_ENUM:
|
||||
case CODE_COND_GOTO:
|
||||
case CODE_COND_TABLE:
|
||||
|
||||
@@ -204,14 +204,6 @@ void compile(Scanner &input, Output &output, Opt &opts)
|
||||
|
||||
output.total_opts = accum_opts ? accum_opts : rblocks.last_opts();
|
||||
|
||||
// For special targets (skeleton and .dot) merge header into the output file.
|
||||
if (globopts->target != TARGET_CODE && output.need_header) {
|
||||
output.need_header = false;
|
||||
blocks_t &cblocks = output.cblocks, &hblocks = output.hblocks;
|
||||
cblocks.insert(cblocks.end(), hblocks.begin(), hblocks.end());
|
||||
hblocks.clear();
|
||||
}
|
||||
|
||||
if (globopts->target == TARGET_SKELETON) {
|
||||
output.wdelay_stmt(0, emit_skeleton_epilog(output));
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ namespace re2c {
|
||||
|
||||
class Scanner;
|
||||
struct Opt;
|
||||
struct Output;
|
||||
class Output;
|
||||
|
||||
void compile(Scanner &input, Output &output, Opt &opts);
|
||||
|
||||
|
||||
@@ -97,10 +97,8 @@ enum CodeKind {
|
||||
CODE_MAXNMATCH,
|
||||
CODE_YYCH,
|
||||
CODE_YYACCEPT,
|
||||
CODE_YYSTATE,
|
||||
CODE_VAR,
|
||||
CODE_STMT,
|
||||
CODE_LOOP,
|
||||
CODE_TEXT,
|
||||
CODE_TEXT_RAW,
|
||||
CODE_RAW,
|
||||
|
||||
+1
-1
@@ -219,7 +219,7 @@ void generate_versions(ctx_t &ctx)
|
||||
const tagver_t v = history(tag) ? vs[t] : TAGVER_ZERO;
|
||||
newver_t x = {t, v, h};
|
||||
const tagver_t
|
||||
n = maxver + 1,
|
||||
n = (maxver + 1) * (h0 == TAGVER_BOTTOM ? -1 : 1),
|
||||
m = newvers.insert(std::make_pair(x, n)).first->second;
|
||||
if (n == m) ++maxver;
|
||||
|
||||
|
||||
+14
-7
@@ -485,9 +485,14 @@ void reserve_buffers(ctx_t &ctx)
|
||||
kbufs.indegree = alc.alloct<uint32_t>(n);
|
||||
|
||||
if (!stadfa) {
|
||||
kbufs.x2y = alc.alloct<tagver_t>(n);
|
||||
kbufs.y2x = alc.alloct<tagver_t>(n);
|
||||
kbufs.x2t = alc.alloct<size_t>(n);
|
||||
const size_t m = 2 * n + 1;
|
||||
|
||||
// point to the center (zero index) of each buffer
|
||||
// indexes in range [-N .. N] must be valid, where N is capacity
|
||||
kbufs.x2y = alc.alloct<tagver_t>(m) + n;
|
||||
kbufs.y2x = alc.alloct<tagver_t>(m) + n;
|
||||
kbufs.x2t = alc.alloct<size_t>(m) + n;
|
||||
|
||||
kbufs.backup_actions = alc.alloct<tcmd_t>(n);
|
||||
}
|
||||
}
|
||||
@@ -644,8 +649,8 @@ bool kernel_map_t<ctx_t, regless>::operator()(const kernel_t *x, const kernel_t
|
||||
|
||||
// map tag versions of one kernel to that of another
|
||||
// and check that lookahead versions (if any) coincide
|
||||
std::fill(x2y, x2y + max, TAGVER_ZERO);
|
||||
std::fill(y2x, y2x + max, TAGVER_ZERO);
|
||||
std::fill(x2y - max, x2y + max, TAGVER_ZERO);
|
||||
std::fill(y2x - max, y2x + max, TAGVER_ZERO);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const tagver_t
|
||||
*xvs = ctx.dc_tagvertbl[x->tvers[i]],
|
||||
@@ -686,13 +691,15 @@ bool kernel_map_t<ctx_t, regless>::operator()(const kernel_t *x, const kernel_t
|
||||
// fix LHS of 'save' commands to reuse old version
|
||||
// see note [save(X), copy(Y,X) optimization]
|
||||
for (a = *pacts; a; a = a->next) {
|
||||
const tagver_t yv = a->lhs, xv = y2x[yv];
|
||||
const tagver_t
|
||||
yv = a->lhs * (a->history[0] == TAGVER_BOTTOM ? -1 : 1),
|
||||
xv = y2x[yv];
|
||||
a->lhs = abs(xv);
|
||||
y2x[yv] = x2y[xv] = TAGVER_ZERO;
|
||||
}
|
||||
|
||||
// create 'copy' commands
|
||||
for (tagver_t xv = 0; xv < max; ++xv) {
|
||||
for (tagver_t xv = -max; xv < max; ++xv) {
|
||||
const tagver_t yv = x2y[xv], axv = abs(xv), ayv = abs(yv);
|
||||
if (yv != TAGVER_ZERO && xv != yv && !fixed(tags[x2t[xv]])) {
|
||||
DASSERT(axv != ayv);
|
||||
|
||||
+4
-35
@@ -16,6 +16,10 @@ static void fix_conopt(conopt_t &glob)
|
||||
glob.iFlag = true;
|
||||
}
|
||||
|
||||
if (!glob.lookahead) {
|
||||
glob.eager_skip = true;
|
||||
}
|
||||
|
||||
// append directory separator '/' to all paths that do not have it
|
||||
for (size_t i = 0; i < glob.incpaths.size(); ++i) {
|
||||
std::string &p = glob.incpaths[i];
|
||||
@@ -25,13 +29,6 @@ static void fix_conopt(conopt_t &glob)
|
||||
}
|
||||
}
|
||||
|
||||
if (!glob.lookahead || glob.loop_switch) {
|
||||
// for loop-switch enable eager-skip always (not only in cases when
|
||||
// YYFILL labels are used) to avoid special handling of initial state
|
||||
// when there are transitions into it.
|
||||
glob.eager_skip = true;
|
||||
}
|
||||
|
||||
if (!glob.dep_file.empty() && glob.output_file.empty()) {
|
||||
error("cannot generate dep file, output file not specified");
|
||||
exit(1);
|
||||
@@ -123,7 +120,6 @@ static void fix_mutopt(const conopt_t &glob, const mutopt_t &defaults,
|
||||
real.yych = defaults.yych;
|
||||
real.bEmitYYCh = defaults.bEmitYYCh;
|
||||
real.yychConversion = defaults.yychConversion;
|
||||
real.yystate = defaults.yystate;
|
||||
real.fill = defaults.fill;
|
||||
real.fill_use = defaults.fill_use;
|
||||
real.fill_check = defaults.fill_check;
|
||||
@@ -252,14 +248,6 @@ static void fix_mutopt(const conopt_t &glob, const mutopt_t &defaults,
|
||||
if (real.fill_naked) {
|
||||
real.fill_arg_use = false;
|
||||
}
|
||||
if (glob.loop_switch) {
|
||||
// With --loop-switch there is no `goto`.
|
||||
real.yyctable = defaults.yyctable;
|
||||
real.condDivider = defaults.condDivider;
|
||||
real.condDividerParam = defaults.condDividerParam;
|
||||
real.condGoto = defaults.condGoto;
|
||||
real.condGotoParam = defaults.condGotoParam;
|
||||
}
|
||||
|
||||
// errors
|
||||
if (glob.target == TARGET_SKELETON && glob.lang != LANG_C) {
|
||||
@@ -322,25 +310,6 @@ static void fix_mutopt(const conopt_t &glob, const mutopt_t &defaults,
|
||||
error("storable state requires YYFILL to be enabled");
|
||||
exit(1);
|
||||
}
|
||||
if (glob.loop_switch) {
|
||||
if (real.gFlag) {
|
||||
error("cannot combine loop switch and computed gotos");
|
||||
exit(1);
|
||||
}
|
||||
if (real.bFlag) {
|
||||
// TODO: generate bitmaps before the joined loop/switch for all conditions.
|
||||
error("bitmaps with loop switch are not supported");
|
||||
exit(1);
|
||||
}
|
||||
if (!glob.lookahead) {
|
||||
// The problem here is that TDFA(0) may have initial register operations that
|
||||
// should be executed on DFA entry. With loop/switch these operations would
|
||||
// need to go in a special initial state (they can't go before the `yystate`
|
||||
// loop because that would not work with start conditions).
|
||||
error("TDFA(0) with loop switch is not supported");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Opt::Opt(const conopt_t &globopts)
|
||||
|
||||
+1
-3
@@ -70,12 +70,11 @@ class Msg;
|
||||
CONSTOPT (posix_prectable_alg_t, posix_prectable, POSIX_PRECTABLE_COMPLEX) \
|
||||
CONSTOPT (fixed_tags_t, fixed_tags, FIXTAG_ALL) \
|
||||
CONSTOPT (bool, lookahead, true) \
|
||||
CONSTOPT (bool, eager_skip, false) \
|
||||
CONSTOPT (bool, optimize_tags, true) \
|
||||
CONSTOPT (bool, backward, false) \
|
||||
CONSTOPT (bool, stadfa, false) \
|
||||
CONSTOPT (bool, nested_negative_tags, true) \
|
||||
CONSTOPT (bool, eager_skip, false) \
|
||||
CONSTOPT (bool, loop_switch, false) \
|
||||
/* debug */ \
|
||||
CONSTOPT (bool, dump_nfa, false) \
|
||||
CONSTOPT (bool, dump_dfa_raw, false) \
|
||||
@@ -137,7 +136,6 @@ class Msg;
|
||||
MUTOPT (bool, yybmHexTable, false) \
|
||||
MUTOPT (bool, gFlag, false) \
|
||||
MUTOPT (bool, case_ranges, false) \
|
||||
MUTOPT (std::string, yystate, "yystate") \
|
||||
MUTOPT (std::string, yytarget, "yytarget") \
|
||||
MUTOPT (uint32_t, cGotoThreshold, 9) \
|
||||
MUTOPT (uint32_t, eof, NOEOF) \
|
||||
|
||||
@@ -167,8 +167,6 @@ opt_long:
|
||||
"no-generation-date" end { globopts.bNoGenerationDate = true; goto opt; }
|
||||
"no-version" end { globopts.version = false; goto opt; }
|
||||
"skeleton" end { globopts.target = TARGET_SKELETON; goto opt; }
|
||||
"eager-skip" end { globopts.eager_skip = true; goto opt; }
|
||||
"loop-switch" end { globopts.loop_switch = true; goto opt; }
|
||||
|
||||
"bit-vectors" end { opts.set_bFlag (true); goto opt; }
|
||||
"debug-output" end { opts.set_dFlag (true); goto opt; }
|
||||
@@ -211,6 +209,7 @@ opt_long:
|
||||
"fixed-tags" end { NEXT_ARG("--fixed-tags", opt_fixed_tags); }
|
||||
"no-lookahead" end { globopts.lookahead = false; goto opt; }
|
||||
"no-optimize-tags" end { globopts.optimize_tags = false; goto opt; }
|
||||
"eager-skip" end { globopts.eager_skip = true; goto opt; }
|
||||
"stadfa" end { globopts.stadfa = true; goto opt; }
|
||||
|
||||
// debug options
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace re2c {
|
||||
|
||||
struct AST;
|
||||
struct loc_t;
|
||||
class Msg;
|
||||
struct Msg;
|
||||
|
||||
typedef std::map<std::string, const AST*> symtab_t;
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
namespace re2c {
|
||||
|
||||
struct SemAct;
|
||||
template <class Ty> class free_list;
|
||||
template <class _Ty> class free_list;
|
||||
|
||||
struct ASTChar {
|
||||
uint32_t chr;
|
||||
|
||||
+2
-8
@@ -189,7 +189,7 @@ loop:
|
||||
}
|
||||
|
||||
"/*!types:re2c" {
|
||||
out.cond_enum_autogen = false;
|
||||
out.cond_enum_in_hdr = out.in_header();
|
||||
out.warn_condition_order = false; // see note [condition order]
|
||||
uint32_t allow = DCONF_FORMAT | DCONF_SEPARATOR;
|
||||
if (!lex_block(out, CODE_COND_ENUM, opts->topIndent, allow)) return INPUT_ERROR;
|
||||
@@ -202,12 +202,6 @@ loop:
|
||||
msg.error(cur_loc(), "`getstate:re2c` without `-f --storable-state` option");
|
||||
return INPUT_ERROR;
|
||||
}
|
||||
if (opts->loop_switch) {
|
||||
msg.error(cur_loc(), "`getstate:re2c` is incompatible with the --loop-switch "
|
||||
"option, as it requires cross-block transitions that are unsupported "
|
||||
"without the `goto` statement");
|
||||
return INPUT_ERROR;
|
||||
}
|
||||
if (!lex_block(out, CODE_STATE_GOTO, opts->topIndent, 0)) return INPUT_ERROR;
|
||||
goto next;
|
||||
}
|
||||
@@ -215,7 +209,7 @@ loop:
|
||||
"/*!header:re2c:on" {
|
||||
out.wraw(tok, ptr);
|
||||
out.header_mode(true);
|
||||
out.need_header = true;
|
||||
out.need_header = opts->target == TARGET_CODE;
|
||||
if (!lex_block_end(out)) return INPUT_ERROR;
|
||||
goto next;
|
||||
}
|
||||
|
||||
@@ -119,7 +119,6 @@ void Scanner::lex_conf(Opt &opts)
|
||||
return;
|
||||
}
|
||||
"variable:yytarget" { opts.set_yytarget (lex_conf_string ()); return; }
|
||||
"variable:yystate" { opts.set_yystate (lex_conf_string ()); return; }
|
||||
|
||||
"define:YYCURSOR" { opts.set_yycursor (lex_conf_string ()); return; }
|
||||
"define:YYMARKER" { opts.set_yymarker (lex_conf_string ()); return; }
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
namespace re2c {
|
||||
|
||||
class Msg;
|
||||
struct Output;
|
||||
class Output;
|
||||
struct AST;
|
||||
struct ASTChar;
|
||||
struct BlockNameList;
|
||||
|
||||
@@ -163,8 +163,10 @@ static void find_fixed_tags(RESpec &spec, std::vector<StackItem> &stack,
|
||||
l.tag = re->tag.idx;
|
||||
l.dist_to_tag = 0;
|
||||
}
|
||||
// Trailing context is not special: tags are fixed on the rightmost cursor
|
||||
// position, and trailing context is just another tag.
|
||||
|
||||
if (trailing(tag)) {
|
||||
l.dist_to_tag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ namespace re2c {
|
||||
|
||||
struct AST;
|
||||
struct ASTRule;
|
||||
class Msg;
|
||||
struct Msg;
|
||||
struct Rule;
|
||||
struct opt_t;
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ static void emit_skeleton_defines(Output &output, CodeList *code, const DFA &dfa
|
||||
append(code, code_textraw(alc, "#define YYSHIFT(o) cursor += o"));
|
||||
append(code, code_textraw(alc, "#define YYLESSTHAN(n) (limit - cursor) < n"));
|
||||
append(code, code_textraw(alc, opts->eof == NOEOF
|
||||
? "#define YYFILL(n) { goto loop_end; }"
|
||||
? "#define YYFILL(n) { break; }"
|
||||
: "#define YYFILL(n) 1 /* fail */"));
|
||||
append(code, code_newline(alc));
|
||||
}
|
||||
@@ -610,17 +610,8 @@ static void emit_skeleton_function_lex(Output &output, CodeList *code, DFA &dfa)
|
||||
|
||||
append(block, code_textraw(alc, ""));
|
||||
|
||||
// Don't use `for` loops or `while` loops: the generated code may contain an
|
||||
// inner loop if the --loop-switch option is used, and then `continue` and
|
||||
// `break` statements may result in unexpected control flow. Use `goto` loop.
|
||||
append(block, code_stmt(alc, "i = 0"));
|
||||
append(block, code_slabel(alc, "loop"));
|
||||
|
||||
block2 = code_list(alc);
|
||||
append(block2, code_stmt(alc, "goto loop_end"));
|
||||
append(block, code_if_then_else(alc,
|
||||
"!(status == 0 && cursor < eof && i < keys_count)", block2, NULL));
|
||||
|
||||
append(block, code_text(alc,
|
||||
"for (i = 0; status == 0 && cursor < eof && i < keys_count;) {"));
|
||||
block2 = code_list(alc);
|
||||
append(block2, code_stmt(alc, "token = cursor"));
|
||||
if (dfa.need_backup) {
|
||||
@@ -633,9 +624,6 @@ static void emit_skeleton_function_lex(Output &output, CodeList *code, DFA &dfa)
|
||||
if (dfa.need_accept) {
|
||||
append(block2, code_stmt(alc, "unsigned int yyaccept = 0"));
|
||||
}
|
||||
if (opts->loop_switch) {
|
||||
append(block2, code_stmt(alc, o.cstr("unsigned int yystate = 0").flush()));
|
||||
}
|
||||
// autogenerated stag variables
|
||||
if (!dfa.stagnames.empty()) {
|
||||
text = o.cstr("\n").str(indent(2, opts->indString))
|
||||
@@ -688,20 +676,11 @@ static void emit_skeleton_function_lex(Output &output, CodeList *code, DFA &dfa)
|
||||
}
|
||||
append(block2, code_textraw(alc, ""));
|
||||
|
||||
if (!opts->loop_switch) {
|
||||
gen_dfa_as_blocks_with_labels(output, dfa, block2);
|
||||
} else {
|
||||
// With loop/switch there are no labels, and each block has its own state switch.
|
||||
// Restart state counter from zero so that cases start from zero.
|
||||
output.label_counter = 0;
|
||||
CodeCases *cases = code_cases(alc);
|
||||
gen_dfa_as_switch_cases(output, dfa, cases);
|
||||
wrap_dfas_in_loop_switch(output, block2, cases);
|
||||
}
|
||||
dfa.emit_body(output, block2);
|
||||
append(block2, code_textraw(alc, ""));
|
||||
|
||||
append(block, code_block(alc, block2, CodeBlock::WRAPPED));
|
||||
append(block, code_slabel(alc, "loop_end"));
|
||||
append(block, code_block(alc, block2, CodeBlock::INDENTED));
|
||||
append(block, code_text(alc, "}"));
|
||||
|
||||
if_code = code_list(alc);
|
||||
|
||||
@@ -858,7 +837,7 @@ void emit_skeleton_action(Output &output, CodeList *code, const DFA &dfa, size_t
|
||||
|
||||
append(code, code_block(alc, hangafter, CodeBlock::INDENTED));
|
||||
|
||||
append(code, code_stmt(alc, "goto loop"));
|
||||
append(code, code_stmt(alc, "continue"));
|
||||
}
|
||||
|
||||
} // namespace re2c
|
||||
|
||||
@@ -343,8 +343,8 @@ static void write_keys(const path_t &path, Skeleton &skel, size_t width)
|
||||
tval = tags[tver];
|
||||
if (tval != Skeleton::DEFTAG) tval -= tag.dist;
|
||||
} else {
|
||||
// fixed-length tag based on the rightmost position
|
||||
tval = f - tag.dist;
|
||||
// fixed-length tag based on cursor
|
||||
tval = matched - tag.dist;
|
||||
}
|
||||
*k++ = to_le(static_cast<key_t>(tval));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef _RE2C_UTIL_FIXED_ALLOCATOR_
|
||||
#define _RE2C_UTIL_FIXED_ALLOCATOR_
|
||||
|
||||
#include <stddef.h>
|
||||
#include "src/util/c99_stdint.h"
|
||||
#include <vector> // slab queue
|
||||
|
||||
|
||||
@@ -6,25 +6,25 @@
|
||||
|
||||
namespace re2c {
|
||||
|
||||
template<class Ty>
|
||||
class free_list: protected std::set<Ty>
|
||||
template<class _Ty>
|
||||
class free_list: protected std::set<_Ty>
|
||||
{
|
||||
public:
|
||||
typedef typename std::set<Ty>::iterator iterator;
|
||||
typedef typename std::set<Ty>::size_type size_type;
|
||||
typedef typename std::set<Ty>::key_type key_type;
|
||||
typedef typename std::set<_Ty>::iterator iterator;
|
||||
typedef typename std::set<_Ty>::size_type size_type;
|
||||
typedef typename std::set<_Ty>::key_type key_type;
|
||||
|
||||
free_list(): in_clear(false)
|
||||
{
|
||||
}
|
||||
|
||||
using std::set<Ty>::insert;
|
||||
using std::set<_Ty>::insert;
|
||||
|
||||
size_type erase(const key_type& key)
|
||||
{
|
||||
if (!in_clear)
|
||||
{
|
||||
return std::set<Ty>::erase(key);
|
||||
return std::set<_Ty>::erase(key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
std::set<Ty>::clear();
|
||||
std::set<_Ty>::clear();
|
||||
|
||||
in_clear = false;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef _RE2C_UTIL_STRING_UTILS_
|
||||
#define _RE2C_UTIL_STRING_UTILS_
|
||||
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#ifndef _POSIX_SOURCE
|
||||
#define _POSIX_SOURCE 1 // for fdopen
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <time.h>
|
||||
#include "src/util/temp_file.h"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef _RE2C_UTIL_UNIQ_VECTOR_
|
||||
#define _RE2C_UTIL_UNIQ_VECTOR_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#line 1 "bug152.re"
|
||||
// re2c $INPUT -o $OUTPUT -c
|
||||
#line 5 "bug152.c"
|
||||
enum YYCONDTYPE {
|
||||
};
|
||||
#line 2 "bug152.re"
|
||||
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --case-ranges --loop-switch -i
|
||||
|
||||
int lex(const char *YYCURSOR) { // C/C++ code
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *YYCURSOR;
|
||||
++YYCURSOR;
|
||||
switch (yych) {
|
||||
case 'A' ... 'Z':
|
||||
case 'a' ... 'z':
|
||||
yystate = 3;
|
||||
continue;
|
||||
default:
|
||||
yystate = 1;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return 1; }
|
||||
case 3:
|
||||
yych = *YYCURSOR;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
switch (yych) {
|
||||
case '0' ... '9':
|
||||
case 'A' ... 'Z':
|
||||
case 'a' ... 'z':
|
||||
++YYCURSOR;
|
||||
yystate = 3;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 5:
|
||||
{ return 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //
|
||||
//
|
||||
int main() { // C/C++ code
|
||||
return lex("qwerty42"); //
|
||||
} //
|
||||
@@ -1,18 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --case-ranges --loop-switch -i
|
||||
|
||||
int lex(const char *YYCURSOR) { // C/C++ code
|
||||
/*!re2c
|
||||
re2c:define:YYCTYPE = char; // configurations
|
||||
re2c:yyfill:enable = 0; //
|
||||
//
|
||||
alpha = [a-zA-Z]; // named definitions
|
||||
ident = alpha (alpha | [0-9])*; //
|
||||
//
|
||||
ident { return 0; } // rules
|
||||
* { return 1; } //
|
||||
*/
|
||||
} //
|
||||
//
|
||||
int main() { // C/C++ code
|
||||
return lex("qwerty42"); //
|
||||
} //
|
||||
@@ -1,121 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define YYMAXFILL 1
|
||||
|
||||
|
||||
// expect YYMAXFILL-padded string
|
||||
static int lex(const char *str, unsigned int len)
|
||||
{
|
||||
const char *YYCURSOR = str, *YYLIMIT = str + len + YYMAXFILL;
|
||||
int count = 0;
|
||||
|
||||
loop:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
if (YYLIMIT <= YYCURSOR) return -1;
|
||||
yych = *YYCURSOR;
|
||||
++YYCURSOR;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 1;
|
||||
continue;
|
||||
case ' ':
|
||||
yystate = 5;
|
||||
continue;
|
||||
case '\'':
|
||||
yystate = 8;
|
||||
continue;
|
||||
default:
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return YYCURSOR + YYMAXFILL - 1 == YYLIMIT ? count : -1; }
|
||||
case 3:
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
{ return -1; }
|
||||
case 5:
|
||||
if (YYLIMIT <= YYCURSOR) return -1;
|
||||
yych = *YYCURSOR;
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++YYCURSOR;
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
case 7:
|
||||
{ goto loop; }
|
||||
case 8:
|
||||
if (YYLIMIT <= YYCURSOR) return -1;
|
||||
yych = *YYCURSOR;
|
||||
yystate = 9;
|
||||
continue;
|
||||
case 9:
|
||||
++YYCURSOR;
|
||||
switch (yych) {
|
||||
case '\'':
|
||||
yystate = 10;
|
||||
continue;
|
||||
case '\\':
|
||||
yystate = 12;
|
||||
continue;
|
||||
default:
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
case 10:
|
||||
yystate = 11;
|
||||
continue;
|
||||
case 11:
|
||||
{ ++count; goto loop; }
|
||||
case 12:
|
||||
if (YYLIMIT <= YYCURSOR) return -1;
|
||||
yych = *YYCURSOR;
|
||||
++YYCURSOR;
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// make a copy of the string with YYMAXFILL zeroes at the end
|
||||
static void test(const char *str, unsigned int len, int res)
|
||||
{
|
||||
char *s = (char*) malloc(len + YYMAXFILL);
|
||||
memcpy(s, str, len);
|
||||
memset(s + len, 0, YYMAXFILL);
|
||||
int r = lex(s, len);
|
||||
free(s);
|
||||
assert(r == res);
|
||||
}
|
||||
|
||||
#define TEST(s, r) test(s, sizeof(s) - 1, r)
|
||||
int main()
|
||||
{
|
||||
TEST("", 0);
|
||||
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
|
||||
TEST("'unterminated\\'", -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*!max:re2c*/
|
||||
|
||||
// expect YYMAXFILL-padded string
|
||||
static int lex(const char *str, unsigned int len)
|
||||
{
|
||||
const char *YYCURSOR = str, *YYLIMIT = str + len + YYMAXFILL;
|
||||
int count = 0;
|
||||
|
||||
loop:
|
||||
/*!re2c
|
||||
re2c:api:style = free-form;
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:define:YYFILL = "return -1;";
|
||||
|
||||
* { return -1; }
|
||||
[\x00] { return YYCURSOR + YYMAXFILL - 1 == YYLIMIT ? count : -1; }
|
||||
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
|
||||
[ ]+ { goto loop; }
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
// make a copy of the string with YYMAXFILL zeroes at the end
|
||||
static void test(const char *str, unsigned int len, int res)
|
||||
{
|
||||
char *s = (char*) malloc(len + YYMAXFILL);
|
||||
memcpy(s, str, len);
|
||||
memset(s + len, 0, YYMAXFILL);
|
||||
int r = lex(s, len);
|
||||
free(s);
|
||||
assert(r == res);
|
||||
}
|
||||
|
||||
#define TEST(s, r) test(s, sizeof(s) - 1, r)
|
||||
int main()
|
||||
{
|
||||
TEST("", 0);
|
||||
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
|
||||
TEST("'unterminated\\'", -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
|
||||
// expect a null-terminated string
|
||||
static int lex(const char *str, unsigned int len)
|
||||
{
|
||||
const char *YYCURSOR = str, *YYLIMIT = str + len, *YYMARKER;
|
||||
int count = 0;
|
||||
|
||||
loop:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++YYCURSOR;
|
||||
yystate = 3;
|
||||
continue;
|
||||
case '\'':
|
||||
++YYCURSOR;
|
||||
yystate = 6;
|
||||
continue;
|
||||
default:
|
||||
if (YYLIMIT <= YYCURSOR) {
|
||||
yystate = 12;
|
||||
continue;
|
||||
}
|
||||
++YYCURSOR;
|
||||
yystate = 1;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return -1; }
|
||||
case 3:
|
||||
yych = *YYCURSOR;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++YYCURSOR;
|
||||
yystate = 3;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 5:
|
||||
{ goto loop; }
|
||||
case 6:
|
||||
YYMARKER = YYCURSOR;
|
||||
yych = *YYCURSOR;
|
||||
if (yych >= 0x01) {
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
if (YYLIMIT <= YYCURSOR) {
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
++YYCURSOR;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 7:
|
||||
yych = *YYCURSOR;
|
||||
yystate = 8;
|
||||
continue;
|
||||
case 8:
|
||||
switch (yych) {
|
||||
case '\'':
|
||||
++YYCURSOR;
|
||||
yystate = 9;
|
||||
continue;
|
||||
case '\\':
|
||||
++YYCURSOR;
|
||||
yystate = 11;
|
||||
continue;
|
||||
default:
|
||||
if (YYLIMIT <= YYCURSOR) {
|
||||
yystate = 13;
|
||||
continue;
|
||||
}
|
||||
++YYCURSOR;
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
case 9:
|
||||
yystate = 10;
|
||||
continue;
|
||||
case 10:
|
||||
{ ++count; goto loop; }
|
||||
case 11:
|
||||
yych = *YYCURSOR;
|
||||
if (yych <= 0x00) {
|
||||
if (YYLIMIT <= YYCURSOR) {
|
||||
yystate = 13;
|
||||
continue;
|
||||
}
|
||||
++YYCURSOR;
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
++YYCURSOR;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 12:
|
||||
{ return count; }
|
||||
case 13:
|
||||
YYCURSOR = YYMARKER;
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define TEST(s, r) assert(lex(s, sizeof(s) - 1) == r)
|
||||
int main()
|
||||
{
|
||||
TEST("", 0);
|
||||
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
|
||||
TEST("'unterminated\\'", -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
|
||||
// expect a null-terminated string
|
||||
static int lex(const char *str, unsigned int len)
|
||||
{
|
||||
const char *YYCURSOR = str, *YYLIMIT = str + len, *YYMARKER;
|
||||
int count = 0;
|
||||
|
||||
loop:
|
||||
/*!re2c
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:yyfill:enable = 0;
|
||||
re2c:eof = 0;
|
||||
|
||||
* { return -1; }
|
||||
$ { return count; }
|
||||
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
|
||||
[ ]+ { goto loop; }
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
#define TEST(s, r) assert(lex(s, sizeof(s) - 1) == r)
|
||||
int main()
|
||||
{
|
||||
TEST("", 0);
|
||||
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
|
||||
TEST("'unterminated\\'", -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SIZE 4096
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char buf[SIZE + 1], *lim, *cur, *mar, *tok;
|
||||
int eof;
|
||||
} Input;
|
||||
|
||||
static int fill(Input *in)
|
||||
{
|
||||
if (in->eof) {
|
||||
return 1;
|
||||
}
|
||||
const size_t free = in->tok - in->buf;
|
||||
if (free < 1) {
|
||||
return 2;
|
||||
}
|
||||
memmove(in->buf, in->tok, in->lim - in->tok);
|
||||
in->lim -= free;
|
||||
in->cur -= free;
|
||||
in->mar -= free;
|
||||
in->tok -= free;
|
||||
in->lim += fread(in->lim, 1, free, in->file);
|
||||
in->lim[0] = 0;
|
||||
in->eof |= in->lim < in->buf + SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init(Input *in, FILE *file)
|
||||
{
|
||||
in->file = file;
|
||||
in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
|
||||
in->eof = 0;
|
||||
fill(in);
|
||||
}
|
||||
|
||||
static int lex(Input *in)
|
||||
{
|
||||
int count = 0;
|
||||
loop:
|
||||
in->tok = in->cur;
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *in->cur;
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++in->cur;
|
||||
yystate = 3;
|
||||
continue;
|
||||
case '\'':
|
||||
++in->cur;
|
||||
yystate = 6;
|
||||
continue;
|
||||
default:
|
||||
if (in->lim <= in->cur) {
|
||||
if (fill(in) == 0) {
|
||||
yystate = 0;
|
||||
continue;
|
||||
}
|
||||
yystate = 12;
|
||||
continue;
|
||||
}
|
||||
++in->cur;
|
||||
yystate = 1;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return -1; }
|
||||
case 3:
|
||||
yych = *in->cur;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++in->cur;
|
||||
yystate = 3;
|
||||
continue;
|
||||
default:
|
||||
if (in->lim <= in->cur) {
|
||||
if (fill(in) == 0) {
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 5:
|
||||
{ goto loop; }
|
||||
case 6:
|
||||
in->mar = in->cur;
|
||||
yych = *in->cur;
|
||||
if (yych >= 0x01) {
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
if (in->lim <= in->cur) {
|
||||
if (fill(in) == 0) {
|
||||
yystate = 6;
|
||||
continue;
|
||||
}
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
++in->cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 7:
|
||||
yych = *in->cur;
|
||||
yystate = 8;
|
||||
continue;
|
||||
case 8:
|
||||
switch (yych) {
|
||||
case '\'':
|
||||
++in->cur;
|
||||
yystate = 9;
|
||||
continue;
|
||||
case '\\':
|
||||
++in->cur;
|
||||
yystate = 11;
|
||||
continue;
|
||||
default:
|
||||
if (in->lim <= in->cur) {
|
||||
if (fill(in) == 0) {
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
yystate = 13;
|
||||
continue;
|
||||
}
|
||||
++in->cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
case 9:
|
||||
yystate = 10;
|
||||
continue;
|
||||
case 10:
|
||||
{ ++count; goto loop; }
|
||||
case 11:
|
||||
yych = *in->cur;
|
||||
if (yych <= 0x00) {
|
||||
if (in->lim <= in->cur) {
|
||||
if (fill(in) == 0) {
|
||||
yystate = 11;
|
||||
continue;
|
||||
}
|
||||
yystate = 13;
|
||||
continue;
|
||||
}
|
||||
++in->cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
++in->cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 12:
|
||||
{ return count; }
|
||||
case 13:
|
||||
in->cur = in->mar;
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const char *fname = "input";
|
||||
const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
|
||||
FILE *f;
|
||||
Input in;
|
||||
|
||||
// prepare input file: a few times the size of the buffer,
|
||||
// containing strings with zeroes and escaped quotes
|
||||
f = fopen(fname, "w");
|
||||
for (int i = 0; i < SIZE; ++i) {
|
||||
fwrite(str, 1, sizeof(str) - 1, f);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen(fname, "r");
|
||||
init(&in, f);
|
||||
assert(lex(&in) == SIZE * 3);
|
||||
fclose(f);
|
||||
|
||||
remove(fname);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SIZE 4096
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char buf[SIZE + 1], *lim, *cur, *mar, *tok;
|
||||
int eof;
|
||||
} Input;
|
||||
|
||||
static int fill(Input *in)
|
||||
{
|
||||
if (in->eof) {
|
||||
return 1;
|
||||
}
|
||||
const size_t free = in->tok - in->buf;
|
||||
if (free < 1) {
|
||||
return 2;
|
||||
}
|
||||
memmove(in->buf, in->tok, in->lim - in->tok);
|
||||
in->lim -= free;
|
||||
in->cur -= free;
|
||||
in->mar -= free;
|
||||
in->tok -= free;
|
||||
in->lim += fread(in->lim, 1, free, in->file);
|
||||
in->lim[0] = 0;
|
||||
in->eof |= in->lim < in->buf + SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init(Input *in, FILE *file)
|
||||
{
|
||||
in->file = file;
|
||||
in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
|
||||
in->eof = 0;
|
||||
fill(in);
|
||||
}
|
||||
|
||||
static int lex(Input *in)
|
||||
{
|
||||
int count = 0;
|
||||
loop:
|
||||
in->tok = in->cur;
|
||||
/*!re2c
|
||||
re2c:eof = 0;
|
||||
re2c:api:style = free-form;
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:define:YYCURSOR = in->cur;
|
||||
re2c:define:YYMARKER = in->mar;
|
||||
re2c:define:YYLIMIT = in->lim;
|
||||
re2c:define:YYFILL = "fill(in) == 0";
|
||||
|
||||
* { return -1; }
|
||||
$ { return count; }
|
||||
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
|
||||
[ ]+ { goto loop; }
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const char *fname = "input";
|
||||
const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
|
||||
FILE *f;
|
||||
Input in;
|
||||
|
||||
// prepare input file: a few times the size of the buffer,
|
||||
// containing strings with zeroes and escaped quotes
|
||||
f = fopen(fname, "w");
|
||||
for (int i = 0; i < SIZE; ++i) {
|
||||
fwrite(str, 1, sizeof(str) - 1, f);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen(fname, "r");
|
||||
init(&in, f);
|
||||
assert(lex(&in) == SIZE * 3);
|
||||
fclose(f);
|
||||
|
||||
remove(fname);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define YYMAXFILL 1
|
||||
|
||||
#define SIZE 4096
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char buf[SIZE + YYMAXFILL], *lim, *cur, *mar, *tok;
|
||||
int eof;
|
||||
} Input;
|
||||
|
||||
static int fill(Input *in, size_t need)
|
||||
{
|
||||
if (in->eof) {
|
||||
return 1;
|
||||
}
|
||||
const size_t free = in->tok - in->buf;
|
||||
if (free < need) {
|
||||
return 2;
|
||||
}
|
||||
memmove(in->buf, in->tok, in->lim - in->tok);
|
||||
in->lim -= free;
|
||||
in->cur -= free;
|
||||
in->mar -= free;
|
||||
in->tok -= free;
|
||||
in->lim += fread(in->lim, 1, free, in->file);
|
||||
if (in->lim < in->buf + SIZE) {
|
||||
in->eof = 1;
|
||||
memset(in->lim, 0, YYMAXFILL);
|
||||
in->lim += YYMAXFILL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init(Input *in, FILE *file)
|
||||
{
|
||||
in->file = file;
|
||||
in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
|
||||
in->eof = 0;
|
||||
fill(in, 1);
|
||||
}
|
||||
|
||||
static int lex(Input *in)
|
||||
{
|
||||
int count = 0;
|
||||
loop:
|
||||
in->tok = in->cur;
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
if (in->lim <= in->cur) if (fill(in, 1) != 0) return -1;
|
||||
yych = *in->cur;
|
||||
++in->cur;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 1;
|
||||
continue;
|
||||
case ' ':
|
||||
yystate = 5;
|
||||
continue;
|
||||
case '\'':
|
||||
yystate = 8;
|
||||
continue;
|
||||
default:
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return (in->lim - in->cur == YYMAXFILL - 1) ? count : -1; }
|
||||
case 3:
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
{ return -1; }
|
||||
case 5:
|
||||
if (in->lim <= in->cur) if (fill(in, 1) != 0) return -1;
|
||||
yych = *in->cur;
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++in->cur;
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
case 7:
|
||||
{ goto loop; }
|
||||
case 8:
|
||||
if (in->lim <= in->cur) if (fill(in, 1) != 0) return -1;
|
||||
yych = *in->cur;
|
||||
yystate = 9;
|
||||
continue;
|
||||
case 9:
|
||||
++in->cur;
|
||||
switch (yych) {
|
||||
case '\'':
|
||||
yystate = 10;
|
||||
continue;
|
||||
case '\\':
|
||||
yystate = 12;
|
||||
continue;
|
||||
default:
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
case 10:
|
||||
yystate = 11;
|
||||
continue;
|
||||
case 11:
|
||||
{ ++count; goto loop; }
|
||||
case 12:
|
||||
if (in->lim <= in->cur) if (fill(in, 1) != 0) return -1;
|
||||
yych = *in->cur;
|
||||
++in->cur;
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const char *fname = "input";
|
||||
const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
|
||||
FILE *f;
|
||||
Input in;
|
||||
|
||||
// prepare input file: a few times the size of the buffer,
|
||||
// containing strings with zeroes and escaped quotes
|
||||
f = fopen(fname, "w");
|
||||
for (int i = 0; i < SIZE; ++i) {
|
||||
fwrite(str, 1, sizeof(str) - 1, f);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen(fname, "r");
|
||||
init(&in, f);
|
||||
assert(lex(&in) == SIZE * 3);
|
||||
fclose(f);
|
||||
|
||||
remove(fname);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/*!max:re2c*/
|
||||
#define SIZE 4096
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char buf[SIZE + YYMAXFILL], *lim, *cur, *mar, *tok;
|
||||
int eof;
|
||||
} Input;
|
||||
|
||||
static int fill(Input *in, size_t need)
|
||||
{
|
||||
if (in->eof) {
|
||||
return 1;
|
||||
}
|
||||
const size_t free = in->tok - in->buf;
|
||||
if (free < need) {
|
||||
return 2;
|
||||
}
|
||||
memmove(in->buf, in->tok, in->lim - in->tok);
|
||||
in->lim -= free;
|
||||
in->cur -= free;
|
||||
in->mar -= free;
|
||||
in->tok -= free;
|
||||
in->lim += fread(in->lim, 1, free, in->file);
|
||||
if (in->lim < in->buf + SIZE) {
|
||||
in->eof = 1;
|
||||
memset(in->lim, 0, YYMAXFILL);
|
||||
in->lim += YYMAXFILL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init(Input *in, FILE *file)
|
||||
{
|
||||
in->file = file;
|
||||
in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
|
||||
in->eof = 0;
|
||||
fill(in, 1);
|
||||
}
|
||||
|
||||
static int lex(Input *in)
|
||||
{
|
||||
int count = 0;
|
||||
loop:
|
||||
in->tok = in->cur;
|
||||
/*!re2c
|
||||
re2c:api:style = free-form;
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:define:YYCURSOR = in->cur;
|
||||
re2c:define:YYMARKER = in->mar;
|
||||
re2c:define:YYLIMIT = in->lim;
|
||||
re2c:define:YYFILL = "if (fill(in, @@) != 0) return -1;";
|
||||
|
||||
* { return -1; }
|
||||
[\x00] { return (in->lim - in->cur == YYMAXFILL - 1) ? count : -1; }
|
||||
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
|
||||
[ ]+ { goto loop; }
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const char *fname = "input";
|
||||
const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
|
||||
FILE *f;
|
||||
Input in;
|
||||
|
||||
// prepare input file: a few times the size of the buffer,
|
||||
// containing strings with zeroes and escaped quotes
|
||||
f = fopen(fname, "w");
|
||||
for (int i = 0; i < SIZE; ++i) {
|
||||
fwrite(str, 1, sizeof(str) - 1, f);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen(fname, "r");
|
||||
init(&in, f);
|
||||
assert(lex(&in) == SIZE * 3);
|
||||
fclose(f);
|
||||
|
||||
remove(fname);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// expect a string without terminating null
|
||||
static int lex(const char *str, unsigned int len)
|
||||
{
|
||||
const char *cur = str, *lim = str + len, *mar;
|
||||
int count = 0;
|
||||
|
||||
loop:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = cur < lim ? *cur : 0;
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++cur;
|
||||
yystate = 3;
|
||||
continue;
|
||||
case '\'':
|
||||
++cur;
|
||||
yystate = 6;
|
||||
continue;
|
||||
default:
|
||||
if (cur >= lim) {
|
||||
yystate = 12;
|
||||
continue;
|
||||
}
|
||||
++cur;
|
||||
yystate = 1;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return -1; }
|
||||
case 3:
|
||||
yych = cur < lim ? *cur : 0;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++cur;
|
||||
yystate = 3;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 5:
|
||||
{ goto loop; }
|
||||
case 6:
|
||||
mar = cur;
|
||||
yych = cur < lim ? *cur : 0;
|
||||
if (yych >= 0x01) {
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
if (cur >= lim) {
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
++cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 7:
|
||||
yych = cur < lim ? *cur : 0;
|
||||
yystate = 8;
|
||||
continue;
|
||||
case 8:
|
||||
switch (yych) {
|
||||
case '\'':
|
||||
++cur;
|
||||
yystate = 9;
|
||||
continue;
|
||||
case '\\':
|
||||
++cur;
|
||||
yystate = 11;
|
||||
continue;
|
||||
default:
|
||||
if (cur >= lim) {
|
||||
yystate = 13;
|
||||
continue;
|
||||
}
|
||||
++cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
case 9:
|
||||
yystate = 10;
|
||||
continue;
|
||||
case 10:
|
||||
{ ++count; goto loop; }
|
||||
case 11:
|
||||
yych = cur < lim ? *cur : 0;
|
||||
if (yych <= 0x00) {
|
||||
if (cur >= lim) {
|
||||
yystate = 13;
|
||||
continue;
|
||||
}
|
||||
++cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
++cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 12:
|
||||
{ return count; }
|
||||
case 13:
|
||||
cur = mar;
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// make a copy of the string without terminating null
|
||||
static void test(const char *str, unsigned int len, int res)
|
||||
{
|
||||
char *s = (char*) malloc(len);
|
||||
memcpy(s, str, len);
|
||||
int r = lex(s, len);
|
||||
free(s);
|
||||
assert(r == res);
|
||||
}
|
||||
|
||||
#define TEST(s, r) test(s, sizeof(s) - 1, r)
|
||||
int main()
|
||||
{
|
||||
TEST("", 0);
|
||||
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
|
||||
TEST("'unterminated\\'", -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// expect a string without terminating null
|
||||
static int lex(const char *str, unsigned int len)
|
||||
{
|
||||
const char *cur = str, *lim = str + len, *mar;
|
||||
int count = 0;
|
||||
|
||||
loop:
|
||||
/*!re2c
|
||||
re2c:yyfill:enable = 0;
|
||||
re2c:eof = 0;
|
||||
re2c:flags:input = custom;
|
||||
re2c:api:style = free-form;
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:define:YYLESSTHAN = "cur >= lim";
|
||||
re2c:define:YYPEEK = "cur < lim ? *cur : 0"; // fake null
|
||||
re2c:define:YYSKIP = "++cur;";
|
||||
re2c:define:YYBACKUP = "mar = cur;";
|
||||
re2c:define:YYRESTORE = "cur = mar;";
|
||||
|
||||
* { return -1; }
|
||||
$ { return count; }
|
||||
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
|
||||
[ ]+ { goto loop; }
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
// make a copy of the string without terminating null
|
||||
static void test(const char *str, unsigned int len, int res)
|
||||
{
|
||||
char *s = (char*) malloc(len);
|
||||
memcpy(s, str, len);
|
||||
int r = lex(s, len);
|
||||
free(s);
|
||||
assert(r == res);
|
||||
}
|
||||
|
||||
#define TEST(s, r) test(s, sizeof(s) - 1, r)
|
||||
int main()
|
||||
{
|
||||
TEST("", 0);
|
||||
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
|
||||
TEST("'unterminated\\'", -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// expect a string without terminating null
|
||||
static int lex(const char *str, unsigned int len)
|
||||
{
|
||||
const char *cur = str, *lim = str + len;
|
||||
int count = 0;
|
||||
|
||||
loop:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = cur < lim ? *cur : 0;
|
||||
++cur;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 1;
|
||||
continue;
|
||||
case ' ':
|
||||
yystate = 5;
|
||||
continue;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
yystate = 8;
|
||||
continue;
|
||||
default:
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return count; }
|
||||
case 3:
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
{ return -1; }
|
||||
case 5:
|
||||
yych = cur < lim ? *cur : 0;
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++cur;
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
case 7:
|
||||
{ goto loop; }
|
||||
case 8:
|
||||
yych = cur < lim ? *cur : 0;
|
||||
yystate = 9;
|
||||
continue;
|
||||
case 9:
|
||||
switch (yych) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
++cur;
|
||||
yystate = 8;
|
||||
continue;
|
||||
default:
|
||||
yystate = 10;
|
||||
continue;
|
||||
}
|
||||
case 10:
|
||||
{ ++count; goto loop; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// make a copy of the string without terminating null
|
||||
static void test(const char *str, unsigned int len, int res)
|
||||
{
|
||||
char *s = (char*) malloc(len);
|
||||
memcpy(s, str, len);
|
||||
int r = lex(s, len);
|
||||
free(s);
|
||||
assert(r == res);
|
||||
}
|
||||
|
||||
#define TEST(s, r) test(s, sizeof(s) - 1, r)
|
||||
int main()
|
||||
{
|
||||
TEST("", 0);
|
||||
TEST("one two three ", 3);
|
||||
TEST("f0ur", -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// expect a string without terminating null
|
||||
static int lex(const char *str, unsigned int len)
|
||||
{
|
||||
const char *cur = str, *lim = str + len;
|
||||
int count = 0;
|
||||
|
||||
loop:
|
||||
/*!re2c
|
||||
re2c:yyfill:enable = 0;
|
||||
re2c:flags:input = custom;
|
||||
re2c:api:style = free-form;
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:define:YYLESSTHAN = "cur >= lim";
|
||||
re2c:define:YYPEEK = "cur < lim ? *cur : 0"; // fake null
|
||||
re2c:define:YYSKIP = "++cur;";
|
||||
|
||||
* { return -1; }
|
||||
[\x00] { return count; }
|
||||
[a-z]+ { ++count; goto loop; }
|
||||
[ ]+ { goto loop; }
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
// make a copy of the string without terminating null
|
||||
static void test(const char *str, unsigned int len, int res)
|
||||
{
|
||||
char *s = (char*) malloc(len);
|
||||
memcpy(s, str, len);
|
||||
int r = lex(s, len);
|
||||
free(s);
|
||||
assert(r == res);
|
||||
}
|
||||
|
||||
#define TEST(s, r) test(s, sizeof(s) - 1, r)
|
||||
int main()
|
||||
{
|
||||
TEST("", 0);
|
||||
TEST("one two three ", 3);
|
||||
TEST("f0ur", -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT -i --loop-switch
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
static const uint64_t ERROR = ~0lu;
|
||||
|
||||
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
|
||||
{
|
||||
u = u * BASE + d;
|
||||
if (u > UINT32_MAX) u = ERROR;
|
||||
}
|
||||
|
||||
static uint64_t parse_u32(const char *s)
|
||||
{
|
||||
const char *YYMARKER;
|
||||
uint64_t u = 0;
|
||||
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case '0':
|
||||
yystate = 3;
|
||||
continue;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 1;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return ERROR; }
|
||||
case 3:
|
||||
YYMARKER = s;
|
||||
yych = *s;
|
||||
switch (yych) {
|
||||
case 'B':
|
||||
case 'b':
|
||||
++s;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 'X':
|
||||
case 'x':
|
||||
++s;
|
||||
yystate = 9;
|
||||
continue;
|
||||
default:
|
||||
yystate = 4;
|
||||
continue;
|
||||
}
|
||||
case 4:
|
||||
{ goto oct; }
|
||||
case 5:
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
s -= 1;
|
||||
{ goto dec; }
|
||||
case 7:
|
||||
yych = *s;
|
||||
switch (yych) {
|
||||
case '0':
|
||||
case '1':
|
||||
++s;
|
||||
yystate = 10;
|
||||
continue;
|
||||
default:
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
case 8:
|
||||
s = YYMARKER;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 9:
|
||||
yych = *s;
|
||||
switch (yych) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
++s;
|
||||
yystate = 12;
|
||||
continue;
|
||||
default:
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
case 10:
|
||||
yystate = 11;
|
||||
continue;
|
||||
case 11:
|
||||
s -= 1;
|
||||
{ goto bin; }
|
||||
case 12:
|
||||
yystate = 13;
|
||||
continue;
|
||||
case 13:
|
||||
s -= 1;
|
||||
{ goto hex; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bin:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 1;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return u; }
|
||||
case 3:
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
{ return ERROR; }
|
||||
case 5:
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
{ adddgt<2>(u, s[-1] - '0'); goto bin; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oct:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 1;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return u; }
|
||||
case 3:
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
{ return ERROR; }
|
||||
case 5:
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
{ adddgt<8>(u, s[-1] - '0'); goto oct; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dec:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 1;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return u; }
|
||||
case 3:
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
{ return ERROR; }
|
||||
case 5:
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
{ adddgt<10>(u, s[-1] - '0'); goto dec; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hex:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 1;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
yystate = 5;
|
||||
continue;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
yystate = 9;
|
||||
continue;
|
||||
default:
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return u; }
|
||||
case 3:
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
{ return ERROR; }
|
||||
case 5:
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
{ adddgt<16>(u, s[-1] - '0'); goto hex; }
|
||||
case 7:
|
||||
yystate = 8;
|
||||
continue;
|
||||
case 8:
|
||||
{ adddgt<16>(u, s[-1] - 'A' + 10); goto hex; }
|
||||
case 9:
|
||||
yystate = 10;
|
||||
continue;
|
||||
case 10:
|
||||
{ adddgt<16>(u, s[-1] - 'a' + 10); goto hex; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(parse_u32("1234567890") == 1234567890);
|
||||
assert(parse_u32("0b1101") == 13);
|
||||
assert(parse_u32("0x7Fe") == 2046);
|
||||
assert(parse_u32("0644") == 420);
|
||||
assert(parse_u32("9999999999") == ERROR);
|
||||
assert(parse_u32("") == ERROR);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT -i --loop-switch
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
static const uint64_t ERROR = ~0lu;
|
||||
|
||||
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
|
||||
{
|
||||
u = u * BASE + d;
|
||||
if (u > UINT32_MAX) u = ERROR;
|
||||
}
|
||||
|
||||
static uint64_t parse_u32(const char *s)
|
||||
{
|
||||
const char *YYMARKER;
|
||||
uint64_t u = 0;
|
||||
|
||||
/*!re2c
|
||||
re2c:yyfill:enable = 0;
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:define:YYCURSOR = s;
|
||||
|
||||
end = "\x00";
|
||||
|
||||
'0b' / [01] { goto bin; }
|
||||
"0" { goto oct; }
|
||||
"" / [1-9] { goto dec; }
|
||||
'0x' / [0-9a-fA-F] { goto hex; }
|
||||
* { return ERROR; }
|
||||
*/
|
||||
bin:
|
||||
/*!re2c
|
||||
end { return u; }
|
||||
[01] { adddgt<2>(u, s[-1] - '0'); goto bin; }
|
||||
* { return ERROR; }
|
||||
*/
|
||||
oct:
|
||||
/*!re2c
|
||||
end { return u; }
|
||||
[0-7] { adddgt<8>(u, s[-1] - '0'); goto oct; }
|
||||
* { return ERROR; }
|
||||
*/
|
||||
dec:
|
||||
/*!re2c
|
||||
end { return u; }
|
||||
[0-9] { adddgt<10>(u, s[-1] - '0'); goto dec; }
|
||||
* { return ERROR; }
|
||||
*/
|
||||
hex:
|
||||
/*!re2c
|
||||
end { return u; }
|
||||
[0-9] { adddgt<16>(u, s[-1] - '0'); goto hex; }
|
||||
[a-f] { adddgt<16>(u, s[-1] - 'a' + 10); goto hex; }
|
||||
[A-F] { adddgt<16>(u, s[-1] - 'A' + 10); goto hex; }
|
||||
* { return ERROR; }
|
||||
*/
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(parse_u32("1234567890") == 1234567890);
|
||||
assert(parse_u32("0b1101") == 13);
|
||||
assert(parse_u32("0x7Fe") == 2046);
|
||||
assert(parse_u32("0644") == 420);
|
||||
assert(parse_u32("9999999999") == ERROR);
|
||||
assert(parse_u32("") == ERROR);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT -ci --loop-switch
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
static const uint64_t ERROR = ~0lu;
|
||||
enum YYCONDTYPE {
|
||||
yycinit = 0,
|
||||
yycbin = 14,
|
||||
yycdec = 21,
|
||||
yychex = 28,
|
||||
yycoct = 39,
|
||||
};
|
||||
|
||||
|
||||
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
|
||||
{
|
||||
u = u * BASE + d;
|
||||
if (u > UINT32_MAX) u = ERROR;
|
||||
}
|
||||
|
||||
static uint64_t parse_u32(const char *s)
|
||||
{
|
||||
const char *YYMARKER;
|
||||
int c = yycinit;
|
||||
uint64_t u = 0;
|
||||
|
||||
loop:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = c;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case '0':
|
||||
yystate = 3;
|
||||
continue;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 1;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return ERROR; }
|
||||
case 3:
|
||||
YYMARKER = s;
|
||||
yych = *s;
|
||||
switch (yych) {
|
||||
case 'B':
|
||||
case 'b':
|
||||
++s;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 'X':
|
||||
case 'x':
|
||||
++s;
|
||||
yystate = 9;
|
||||
continue;
|
||||
default:
|
||||
yystate = 4;
|
||||
continue;
|
||||
}
|
||||
case 4:
|
||||
c = yycoct;
|
||||
yystate = yycoct;
|
||||
continue;
|
||||
case 5:
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
s -= 1;
|
||||
c = yycdec;
|
||||
yystate = yycdec;
|
||||
continue;
|
||||
case 7:
|
||||
yych = *s;
|
||||
switch (yych) {
|
||||
case '0':
|
||||
case '1':
|
||||
++s;
|
||||
yystate = 10;
|
||||
continue;
|
||||
default:
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
case 8:
|
||||
s = YYMARKER;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 9:
|
||||
yych = *s;
|
||||
switch (yych) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
++s;
|
||||
yystate = 12;
|
||||
continue;
|
||||
default:
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
case 10:
|
||||
yystate = 11;
|
||||
continue;
|
||||
case 11:
|
||||
s -= 1;
|
||||
c = yycbin;
|
||||
yystate = yycbin;
|
||||
continue;
|
||||
case 12:
|
||||
yystate = 13;
|
||||
continue;
|
||||
case 13:
|
||||
s -= 1;
|
||||
c = yychex;
|
||||
yystate = yychex;
|
||||
continue;
|
||||
case 14:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 15;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
yystate = 19;
|
||||
continue;
|
||||
default:
|
||||
yystate = 17;
|
||||
continue;
|
||||
}
|
||||
case 15:
|
||||
yystate = 16;
|
||||
continue;
|
||||
case 16:
|
||||
{ return u; }
|
||||
case 17:
|
||||
yystate = 18;
|
||||
continue;
|
||||
case 18:
|
||||
{ return ERROR; }
|
||||
case 19:
|
||||
yystate = 20;
|
||||
continue;
|
||||
case 20:
|
||||
{ adddgt<2> (u, s[-1] - '0'); goto loop; }
|
||||
case 21:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 22;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
yystate = 26;
|
||||
continue;
|
||||
default:
|
||||
yystate = 24;
|
||||
continue;
|
||||
}
|
||||
case 22:
|
||||
yystate = 23;
|
||||
continue;
|
||||
case 23:
|
||||
{ return u; }
|
||||
case 24:
|
||||
yystate = 25;
|
||||
continue;
|
||||
case 25:
|
||||
{ return ERROR; }
|
||||
case 26:
|
||||
yystate = 27;
|
||||
continue;
|
||||
case 27:
|
||||
{ adddgt<10>(u, s[-1] - '0'); goto loop; }
|
||||
case 28:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 29;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
yystate = 33;
|
||||
continue;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
yystate = 35;
|
||||
continue;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
yystate = 37;
|
||||
continue;
|
||||
default:
|
||||
yystate = 31;
|
||||
continue;
|
||||
}
|
||||
case 29:
|
||||
yystate = 30;
|
||||
continue;
|
||||
case 30:
|
||||
{ return u; }
|
||||
case 31:
|
||||
yystate = 32;
|
||||
continue;
|
||||
case 32:
|
||||
{ return ERROR; }
|
||||
case 33:
|
||||
yystate = 34;
|
||||
continue;
|
||||
case 34:
|
||||
{ adddgt<16>(u, s[-1] - '0'); goto loop; }
|
||||
case 35:
|
||||
yystate = 36;
|
||||
continue;
|
||||
case 36:
|
||||
{ adddgt<16>(u, s[-1] - 'A' + 10); goto loop; }
|
||||
case 37:
|
||||
yystate = 38;
|
||||
continue;
|
||||
case 38:
|
||||
{ adddgt<16>(u, s[-1] - 'a' + 10); goto loop; }
|
||||
case 39:
|
||||
yych = *s;
|
||||
++s;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 40;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
yystate = 44;
|
||||
continue;
|
||||
default:
|
||||
yystate = 42;
|
||||
continue;
|
||||
}
|
||||
case 40:
|
||||
yystate = 41;
|
||||
continue;
|
||||
case 41:
|
||||
{ return u; }
|
||||
case 42:
|
||||
yystate = 43;
|
||||
continue;
|
||||
case 43:
|
||||
{ return ERROR; }
|
||||
case 44:
|
||||
yystate = 45;
|
||||
continue;
|
||||
case 45:
|
||||
{ adddgt<8> (u, s[-1] - '0'); goto loop; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(parse_u32("1234567890") == 1234567890);
|
||||
assert(parse_u32("0b1101") == 13);
|
||||
assert(parse_u32("0x7Fe") == 2046);
|
||||
assert(parse_u32("0644") == 420);
|
||||
assert(parse_u32("9999999999") == ERROR);
|
||||
assert(parse_u32("") == ERROR);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT -ci --loop-switch
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
static const uint64_t ERROR = ~0lu;
|
||||
/*!types:re2c*/
|
||||
|
||||
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
|
||||
{
|
||||
u = u * BASE + d;
|
||||
if (u > UINT32_MAX) u = ERROR;
|
||||
}
|
||||
|
||||
static uint64_t parse_u32(const char *s)
|
||||
{
|
||||
const char *YYMARKER;
|
||||
int c = yycinit;
|
||||
uint64_t u = 0;
|
||||
|
||||
loop:
|
||||
/*!re2c
|
||||
re2c:yyfill:enable = 0;
|
||||
re2c:api:style = free-form;
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:define:YYCURSOR = s;
|
||||
re2c:define:YYGETCONDITION = "c";
|
||||
re2c:define:YYSETCONDITION = "c = @@;";
|
||||
|
||||
<*> * { return ERROR; }
|
||||
|
||||
<init> '0b' / [01] :=> bin
|
||||
<init> "0" :=> oct
|
||||
<init> "" / [1-9] :=> dec
|
||||
<init> '0x' / [0-9a-fA-F] :=> hex
|
||||
|
||||
<bin, oct, dec, hex> "\x00" { return u; }
|
||||
|
||||
<bin> [01] { adddgt<2> (u, s[-1] - '0'); goto loop; }
|
||||
<oct> [0-7] { adddgt<8> (u, s[-1] - '0'); goto loop; }
|
||||
<dec> [0-9] { adddgt<10>(u, s[-1] - '0'); goto loop; }
|
||||
<hex> [0-9] { adddgt<16>(u, s[-1] - '0'); goto loop; }
|
||||
<hex> [a-f] { adddgt<16>(u, s[-1] - 'a' + 10); goto loop; }
|
||||
<hex> [A-F] { adddgt<16>(u, s[-1] - 'A' + 10); goto loop; }
|
||||
*/
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(parse_u32("1234567890") == 1234567890);
|
||||
assert(parse_u32("0b1101") == 13);
|
||||
assert(parse_u32("0x7Fe") == 2046);
|
||||
assert(parse_u32("0644") == 420);
|
||||
assert(parse_u32("9999999999") == ERROR);
|
||||
assert(parse_u32("") == ERROR);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --input-encoding utf8 --loop-switch -i
|
||||
|
||||
// This example supports multiple input encodings: UTF-8 and UTF-32.
|
||||
// Both lexers are generated from the same rules block, and the use
|
||||
// blocks add only encoding-specific configurations.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
static int lex_utf8(const uint8_t *YYCURSOR)
|
||||
{
|
||||
const uint8_t *YYMARKER;
|
||||
|
||||
{
|
||||
uint8_t yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *YYCURSOR;
|
||||
++YYCURSOR;
|
||||
switch (yych) {
|
||||
case 0xE2:
|
||||
yystate = 3;
|
||||
continue;
|
||||
default:
|
||||
yystate = 1;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return 1; }
|
||||
case 3:
|
||||
YYMARKER = YYCURSOR;
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case 0x88:
|
||||
++YYCURSOR;
|
||||
yystate = 4;
|
||||
continue;
|
||||
default:
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
case 4:
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case 0x80:
|
||||
++YYCURSOR;
|
||||
yystate = 6;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 5:
|
||||
YYCURSOR = YYMARKER;
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 6:
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case 'x':
|
||||
++YYCURSOR;
|
||||
yystate = 7;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 7:
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++YYCURSOR;
|
||||
yystate = 8;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 8:
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case 0xE2:
|
||||
++YYCURSOR;
|
||||
yystate = 9;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 9:
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case 0x88:
|
||||
++YYCURSOR;
|
||||
yystate = 10;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 10:
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case 0x83:
|
||||
++YYCURSOR;
|
||||
yystate = 11;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 11:
|
||||
yych = *YYCURSOR;
|
||||
switch (yych) {
|
||||
case 'y':
|
||||
++YYCURSOR;
|
||||
yystate = 12;
|
||||
continue;
|
||||
default:
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
case 12:
|
||||
yystate = 13;
|
||||
continue;
|
||||
case 13:
|
||||
{ return 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int lex_utf32(const uint32_t *YYCURSOR)
|
||||
{
|
||||
const uint32_t *YYMARKER;
|
||||
|
||||
{
|
||||
uint32_t yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *YYCURSOR;
|
||||
++YYCURSOR;
|
||||
if (yych == 0x00002200) {
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
yystate = 1;
|
||||
continue;
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return 1; }
|
||||
case 3:
|
||||
YYMARKER = YYCURSOR;
|
||||
yych = *YYCURSOR;
|
||||
if (yych != 'x') {
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
++YYCURSOR;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
yych = *YYCURSOR;
|
||||
if (yych == ' ') {
|
||||
++YYCURSOR;
|
||||
yystate = 6;
|
||||
continue;
|
||||
}
|
||||
yystate = 5;
|
||||
continue;
|
||||
case 5:
|
||||
YYCURSOR = YYMARKER;
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 6:
|
||||
yych = *YYCURSOR;
|
||||
if (yych != 0x00002203) {
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
++YYCURSOR;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 7:
|
||||
yych = *YYCURSOR;
|
||||
if (yych != 'y') {
|
||||
yystate = 5;
|
||||
continue;
|
||||
}
|
||||
++YYCURSOR;
|
||||
yystate = 8;
|
||||
continue;
|
||||
case 8:
|
||||
yystate = 9;
|
||||
continue;
|
||||
case 9:
|
||||
{ return 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
static const uint8_t s8[] = // UTF-8
|
||||
{ 0xe2, 0x88, 0x80, 0x78, 0x20, 0xe2, 0x88, 0x83, 0x79 };
|
||||
|
||||
static const uint32_t s32[] = // UTF32
|
||||
{ 0x00002200, 0x00000078, 0x00000020, 0x00002203, 0x00000079 };
|
||||
|
||||
assert(lex_utf8(s8) == 0);
|
||||
assert(lex_utf32(s32) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --input-encoding utf8 --loop-switch -i
|
||||
|
||||
// This example supports multiple input encodings: UTF-8 and UTF-32.
|
||||
// Both lexers are generated from the same rules block, and the use
|
||||
// blocks add only encoding-specific configurations.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*!rules:re2c
|
||||
re2c:yyfill:enable = 0;
|
||||
|
||||
"∀x ∃y" { return 0; }
|
||||
* { return 1; }
|
||||
*/
|
||||
|
||||
static int lex_utf8(const uint8_t *YYCURSOR)
|
||||
{
|
||||
const uint8_t *YYMARKER;
|
||||
/*!use:re2c
|
||||
re2c:define:YYCTYPE = uint8_t;
|
||||
re2c:flags:8 = 1;
|
||||
*/
|
||||
}
|
||||
|
||||
static int lex_utf32(const uint32_t *YYCURSOR)
|
||||
{
|
||||
const uint32_t *YYMARKER;
|
||||
/*!use:re2c
|
||||
re2c:define:YYCTYPE = uint32_t;
|
||||
re2c:flags:8 = 0;
|
||||
re2c:flags:u = 1;
|
||||
*/
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
static const uint8_t s8[] = // UTF-8
|
||||
{ 0xe2, 0x88, 0x80, 0x78, 0x20, 0xe2, 0x88, 0x83, 0x79 };
|
||||
|
||||
static const uint32_t s32[] = // UTF32
|
||||
{ 0x00002200, 0x00000078, 0x00000020, 0x00002203, 0x00000079 };
|
||||
|
||||
assert(lex_utf8(s8) == 0);
|
||||
assert(lex_utf32(s32) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
|
||||
// expect a null-terminated string
|
||||
static int lex(const char *YYCURSOR)
|
||||
{
|
||||
int count = 0;
|
||||
loop:
|
||||
|
||||
{
|
||||
char yych;
|
||||
unsigned int yystate = 0;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case 0:
|
||||
yych = *YYCURSOR;
|
||||
++YYCURSOR;
|
||||
switch (yych) {
|
||||
case 0x00:
|
||||
yystate = 1;
|
||||
continue;
|
||||
case ' ':
|
||||
yystate = 5;
|
||||
continue;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
yystate = 8;
|
||||
continue;
|
||||
default:
|
||||
yystate = 3;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
{ return count; }
|
||||
case 3:
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 4:
|
||||
{ return -1; }
|
||||
case 5:
|
||||
yych = *YYCURSOR;
|
||||
yystate = 6;
|
||||
continue;
|
||||
case 6:
|
||||
switch (yych) {
|
||||
case ' ':
|
||||
++YYCURSOR;
|
||||
yystate = 5;
|
||||
continue;
|
||||
default:
|
||||
yystate = 7;
|
||||
continue;
|
||||
}
|
||||
case 7:
|
||||
{ goto loop; }
|
||||
case 8:
|
||||
yych = *YYCURSOR;
|
||||
yystate = 9;
|
||||
continue;
|
||||
case 9:
|
||||
switch (yych) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
++YYCURSOR;
|
||||
yystate = 8;
|
||||
continue;
|
||||
default:
|
||||
yystate = 10;
|
||||
continue;
|
||||
}
|
||||
case 10:
|
||||
{ ++count; goto loop; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(lex("") == 0);
|
||||
assert(lex("one two three") == 3);
|
||||
assert(lex("f0ur") == -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT --loop-switch -i
|
||||
#include <assert.h>
|
||||
|
||||
// expect a null-terminated string
|
||||
static int lex(const char *YYCURSOR)
|
||||
{
|
||||
int count = 0;
|
||||
loop:
|
||||
/*!re2c
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:yyfill:enable = 0;
|
||||
|
||||
* { return -1; }
|
||||
[\x00] { return count; }
|
||||
[a-z]+ { ++count; goto loop; }
|
||||
[ ]+ { goto loop; }
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(lex("") == 0);
|
||||
assert(lex("one two three") == 3);
|
||||
assert(lex("f0ur") == -1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
/* Generated by re2c */
|
||||
// re2c $INPUT -o $OUTPUT -f --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG 1
|
||||
#define LOG(...) if (DEBUG) fprintf(stderr, __VA_ARGS__);
|
||||
#define BUFSIZE 10
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char buf[BUFSIZE + 1], *lim, *cur, *mar, *tok;
|
||||
unsigned yyaccept;
|
||||
int state;
|
||||
} Input;
|
||||
|
||||
static void init(Input *in, FILE *f)
|
||||
{
|
||||
in->file = f;
|
||||
in->cur = in->mar = in->tok = in->lim = in->buf + BUFSIZE;
|
||||
in->lim[0] = 0; // append sentinel symbol
|
||||
in->yyaccept = 0;
|
||||
in->state = -1;
|
||||
}
|
||||
|
||||
typedef enum {END, READY, WAITING, BAD_PACKET, BIG_PACKET} Status;
|
||||
|
||||
static Status fill(Input *in)
|
||||
{
|
||||
const size_t shift = in->tok - in->buf;
|
||||
const size_t free = BUFSIZE - (in->lim - in->tok);
|
||||
|
||||
if (free < 1) return BIG_PACKET;
|
||||
|
||||
memmove(in->buf, in->tok, BUFSIZE - shift);
|
||||
in->lim -= shift;
|
||||
in->cur -= shift;
|
||||
in->mar -= shift;
|
||||
in->tok -= shift;
|
||||
|
||||
const size_t read = fread(in->lim, 1, free, in->file);
|
||||
in->lim += read;
|
||||
in->lim[0] = 0; // append sentinel symbol
|
||||
|
||||
return READY;
|
||||
}
|
||||
|
||||
static Status lex(Input *in, unsigned int *recv)
|
||||
{
|
||||
char yych;
|
||||
loop:
|
||||
|
||||
|
||||
int yystate = in->state;
|
||||
for (;;) {
|
||||
switch (yystate) {
|
||||
case -1:
|
||||
case 0:
|
||||
yych = *in->cur;
|
||||
switch (yych) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
++in->cur;
|
||||
yystate = 3;
|
||||
continue;
|
||||
default:
|
||||
if (in->lim <= in->cur) {
|
||||
in->state = 10;
|
||||
return WAITING;
|
||||
}
|
||||
++in->cur;
|
||||
yystate = 1;
|
||||
continue;
|
||||
}
|
||||
case 1:
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 2:
|
||||
in->state = 0;
|
||||
{ return BAD_PACKET; }
|
||||
case 3:
|
||||
in->mar = in->cur;
|
||||
yych = *in->cur;
|
||||
switch (yych) {
|
||||
case ';':
|
||||
++in->cur;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
++in->cur;
|
||||
yystate = 6;
|
||||
continue;
|
||||
default:
|
||||
if (in->lim <= in->cur) {
|
||||
in->state = 11;
|
||||
return WAITING;
|
||||
}
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
case 4:
|
||||
yystate = 5;
|
||||
continue;
|
||||
case 5:
|
||||
in->state = 0;
|
||||
{ *recv = *recv + 1; in->tok = in->cur; goto loop; }
|
||||
case 6:
|
||||
yych = *in->cur;
|
||||
yystate = 7;
|
||||
continue;
|
||||
case 7:
|
||||
switch (yych) {
|
||||
case ';':
|
||||
++in->cur;
|
||||
yystate = 4;
|
||||
continue;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
++in->cur;
|
||||
yystate = 6;
|
||||
continue;
|
||||
default:
|
||||
if (in->lim <= in->cur) {
|
||||
in->state = 12;
|
||||
return WAITING;
|
||||
}
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
case 8:
|
||||
in->cur = in->mar;
|
||||
yystate = 2;
|
||||
continue;
|
||||
case 9:
|
||||
in->state = 0;
|
||||
{ return END; }
|
||||
case 10:
|
||||
if (in->lim <= in->cur) {
|
||||
yystate = 9;
|
||||
continue;
|
||||
}
|
||||
yystate = 0;
|
||||
continue;
|
||||
case 11:
|
||||
if (in->lim <= in->cur) {
|
||||
yystate = 2;
|
||||
continue;
|
||||
}
|
||||
yystate = 3;
|
||||
continue;
|
||||
case 12:
|
||||
if (in->lim <= in->cur) {
|
||||
yystate = 8;
|
||||
continue;
|
||||
}
|
||||
yystate = 6;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void test(const char **packets, Status status)
|
||||
{
|
||||
const char *fname = "pipe";
|
||||
FILE *fw = fopen(fname, "w");
|
||||
FILE *fr = fopen(fname, "r");
|
||||
setvbuf(fw, NULL, _IONBF, 0);
|
||||
setvbuf(fr, NULL, _IONBF, 0);
|
||||
|
||||
Input in;
|
||||
init(&in, fr);
|
||||
Status st;
|
||||
unsigned int send = 0, recv = 0;
|
||||
|
||||
for (;;) {
|
||||
st = lex(&in, &recv);
|
||||
if (st == END) {
|
||||
LOG("done: got %u packets\n", recv);
|
||||
break;
|
||||
} else if (st == WAITING) {
|
||||
LOG("waiting...\n");
|
||||
if (*packets) {
|
||||
LOG("sent packet %u\n", send);
|
||||
fprintf(fw, "%s", *packets++);
|
||||
++send;
|
||||
}
|
||||
st = fill(&in);
|
||||
LOG("queue: '%s'\n", in.buf);
|
||||
if (st == BIG_PACKET) {
|
||||
LOG("error: packet too big\n");
|
||||
break;
|
||||
}
|
||||
assert(st == READY);
|
||||
} else {
|
||||
assert(st == BAD_PACKET);
|
||||
LOG("error: ill-formed packet\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOG("\n");
|
||||
assert(st == status);
|
||||
if (st == END) assert(recv == send);
|
||||
|
||||
fclose(fw);
|
||||
fclose(fr);
|
||||
remove(fname);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const char *packets1[] = {0};
|
||||
const char *packets2[] = {"zero;", "one;", "two;", "three;", "four;", 0};
|
||||
const char *packets3[] = {"zer0;", 0};
|
||||
const char *packets4[] = {"goooooooooogle;", 0};
|
||||
|
||||
test(packets1, END);
|
||||
test(packets2, END);
|
||||
test(packets3, BAD_PACKET);
|
||||
test(packets4, BIG_PACKET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT -f --loop-switch -i
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG 1
|
||||
#define LOG(...) if (DEBUG) fprintf(stderr, __VA_ARGS__);
|
||||
#define BUFSIZE 10
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char buf[BUFSIZE + 1], *lim, *cur, *mar, *tok;
|
||||
unsigned yyaccept;
|
||||
int state;
|
||||
} Input;
|
||||
|
||||
static void init(Input *in, FILE *f)
|
||||
{
|
||||
in->file = f;
|
||||
in->cur = in->mar = in->tok = in->lim = in->buf + BUFSIZE;
|
||||
in->lim[0] = 0; // append sentinel symbol
|
||||
in->yyaccept = 0;
|
||||
in->state = -1;
|
||||
}
|
||||
|
||||
typedef enum {END, READY, WAITING, BAD_PACKET, BIG_PACKET} Status;
|
||||
|
||||
static Status fill(Input *in)
|
||||
{
|
||||
const size_t shift = in->tok - in->buf;
|
||||
const size_t free = BUFSIZE - (in->lim - in->tok);
|
||||
|
||||
if (free < 1) return BIG_PACKET;
|
||||
|
||||
memmove(in->buf, in->tok, BUFSIZE - shift);
|
||||
in->lim -= shift;
|
||||
in->cur -= shift;
|
||||
in->mar -= shift;
|
||||
in->tok -= shift;
|
||||
|
||||
const size_t read = fread(in->lim, 1, free, in->file);
|
||||
in->lim += read;
|
||||
in->lim[0] = 0; // append sentinel symbol
|
||||
|
||||
return READY;
|
||||
}
|
||||
|
||||
static Status lex(Input *in, unsigned int *recv)
|
||||
{
|
||||
char yych;
|
||||
loop:
|
||||
/*!re2c
|
||||
re2c:eof = 0;
|
||||
re2c:api:style = free-form;
|
||||
re2c:define:YYCTYPE = "char";
|
||||
re2c:define:YYCURSOR = "in->cur";
|
||||
re2c:define:YYMARKER = "in->mar";
|
||||
re2c:define:YYLIMIT = "in->lim";
|
||||
re2c:define:YYGETSTATE = "in->state";
|
||||
re2c:define:YYSETSTATE = "in->state = @@;";
|
||||
re2c:define:YYFILL = "return WAITING;";
|
||||
|
||||
packet = [a-z]+[;];
|
||||
|
||||
* { return BAD_PACKET; }
|
||||
$ { return END; }
|
||||
packet { *recv = *recv + 1; in->tok = in->cur; goto loop; }
|
||||
*/
|
||||
}
|
||||
|
||||
void test(const char **packets, Status status)
|
||||
{
|
||||
const char *fname = "pipe";
|
||||
FILE *fw = fopen(fname, "w");
|
||||
FILE *fr = fopen(fname, "r");
|
||||
setvbuf(fw, NULL, _IONBF, 0);
|
||||
setvbuf(fr, NULL, _IONBF, 0);
|
||||
|
||||
Input in;
|
||||
init(&in, fr);
|
||||
Status st;
|
||||
unsigned int send = 0, recv = 0;
|
||||
|
||||
for (;;) {
|
||||
st = lex(&in, &recv);
|
||||
if (st == END) {
|
||||
LOG("done: got %u packets\n", recv);
|
||||
break;
|
||||
} else if (st == WAITING) {
|
||||
LOG("waiting...\n");
|
||||
if (*packets) {
|
||||
LOG("sent packet %u\n", send);
|
||||
fprintf(fw, "%s", *packets++);
|
||||
++send;
|
||||
}
|
||||
st = fill(&in);
|
||||
LOG("queue: '%s'\n", in.buf);
|
||||
if (st == BIG_PACKET) {
|
||||
LOG("error: packet too big\n");
|
||||
break;
|
||||
}
|
||||
assert(st == READY);
|
||||
} else {
|
||||
assert(st == BAD_PACKET);
|
||||
LOG("error: ill-formed packet\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOG("\n");
|
||||
assert(st == status);
|
||||
if (st == END) assert(recv == send);
|
||||
|
||||
fclose(fw);
|
||||
fclose(fr);
|
||||
remove(fname);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const char *packets1[] = {0};
|
||||
const char *packets2[] = {"zero;", "one;", "two;", "three;", "four;", 0};
|
||||
const char *packets3[] = {"zer0;", 0};
|
||||
const char *packets4[] = {"goooooooooogle;", 0};
|
||||
|
||||
test(packets1, END);
|
||||
test(packets2, END);
|
||||
test(packets3, BAD_PACKET);
|
||||
test(packets4, BIG_PACKET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
codegen/loop_switch/c/storable_state_error_getstate.re:3:16: error: `getstate:re2c` is incompatible with the --loop-switch option, as it requires cross-block transitions that are unsupported without the `goto` statement
|
||||
@@ -1,3 +0,0 @@
|
||||
// re2c $INPUT -o $OUTPUT -f --loop-switch
|
||||
|
||||
/*!getstate:re2c*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user