From 390e99e911c46ad59ecb966bffb275c9cba92fe1 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 28 Dec 2021 18:36:37 +0100 Subject: Some renaming of new features in previous commit. --- autocheck.ll | 101 -------------------------------------------------- build_autocheck.sh | 5 --- buildcheck.sh | 5 +++ checkauto.ll | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ docs/ccommon_api.md | 16 ++++---- include/stc/ccommon.h | 1 + 6 files changed, 115 insertions(+), 114 deletions(-) delete mode 100644 autocheck.ll delete mode 100644 build_autocheck.sh create mode 100644 buildcheck.sh create mode 100644 checkauto.ll diff --git a/autocheck.ll b/autocheck.ll deleted file mode 100644 index 9b090b1c..00000000 --- a/autocheck.ll +++ /dev/null @@ -1,101 +0,0 @@ -/* Check for illegal return/break/continue usage inside a STC-lib c_auto* block (RAII). - * Copyright Tyge Løvset, (c) 2021. - */ -%{ -#include -enum { LOOP=1<<0, AUTO=1<<1 }; -enum { NORMAL, BRACES, BRACESDONE }; -static int braces_lev = 0, block_lev = 0; -static int state = NORMAL; -static unsigned int block[64] = {0}, block_type = 0; -const char* fname; -%} - -ID [_a-zA-Z][_a-zA-Z0-9]* -STR \"([^"\\]|\\.)*\" - -%option never-interactive noyymore noyywrap nounistd -%x cmt -%x prep - -%% -\/\/.* ; // line cmt -\/\* BEGIN(cmt); -\n ++yylineno; -\*\/ BEGIN(INITIAL); -. ; -^[ \t]*#.*\\\n { ++yylineno; BEGIN(prep); } -.*\\\n ++yylineno; -.*\n { ++yylineno; BEGIN(INITIAL); } -^[ \t]*#.* ; -{STR} ; -'\\?.' ; -c_foreach | -c_forrange | -for | -while | -switch { block_type |= LOOP; state = BRACES; } -do { block_type |= LOOP; state = BRACESDONE; } -if { state = BRACES; } -c_autovar | -c_autoscope | -c_autodefer | -c_auto { block_type = AUTO; state = BRACES; } -\( { if (state == BRACES) ++braces_lev; } -\) { if (state == BRACES && --braces_lev == 0) { - state = BRACESDONE; - } - } -;[ \t]*else ; -; { if (state == BRACESDONE) { - block_type = block[block_lev]; - state = NORMAL; - } - } -\{ { if (state != BRACES) { block[++block_lev] = block_type; state = NORMAL; } } -\} { if (state != BRACES) block_type = block[--block_lev]; } -return { if (block_type == AUTO) { - printf("%s:%d: error: 'return' used inside a c_auto* scope.\n" - " Use 'c_exitauto' to exit the current c_auto* scope.\n", fname, yylineno); - } else if (block_type & AUTO) { - printf("%s:%d: error: 'return' used in a loop inside a c_auto* scope.\n" - " Use 'break' to exit loops, then 'c_exitauto' to exit c_auto*.\n", fname, yylineno); - } - } -break { if (block_type == AUTO) - printf("%s:%d: error: 'break' used inside a c_auto* scope.\n" - " Use 'c_exitauto' to exit the current c_auto* scope.\n", fname, yylineno); - } -continue { if (block_type == AUTO) - printf("%s:%d: warning: 'continue' used inside a c_auto* scope.\n" - " It will only break out of the current c_auto* scope.\n" - " Use 'c_exitauto' instead to make it explicit.\n", fname, yylineno); - } -c_exitauto { if (block_type != AUTO) - printf("%s:%d: warning: 'c_exitauto' used outside a c_auto* scope.\n" - " Did you mean 'continue' instead?", fname, yylineno); - } -{ID} ; -\n ++yylineno; -. ; - -%% - -#include - -int main(int argc, char **argv) -{ - if (argc == 1 || strcmp(argv[1], "--help") == 0) { - printf("usage: %s [--help] {C-file | -}\n", argv[0]); - return 0; - } - if (strcmp(argv[1], "-") == 0) { - fname = ""; - yyin = stdin; - } else { - fname = argv[1]; - yyin = fopen(fname, "r"); - } - - yylex(); -} diff --git a/build_autocheck.sh b/build_autocheck.sh deleted file mode 100644 index 96ec7d4d..00000000 --- a/build_autocheck.sh +++ /dev/null @@ -1,5 +0,0 @@ -if [ "$OS" = "Windows_NT" ]; then EXE=.exe; fi -flex autocheck.ll -gcc -O2 lex.yy.c -o autocheck$EXE -rm lex.yy.c -strip autocheck$EXE diff --git a/buildcheck.sh b/buildcheck.sh new file mode 100644 index 00000000..5a1b2e93 --- /dev/null +++ b/buildcheck.sh @@ -0,0 +1,5 @@ +if [ "$OS" = "Windows_NT" ]; then EXE=.exe; fi +flex checkauto.ll +gcc -O2 lex.yy.c -o checkauto$EXE +rm lex.yy.c +strip checkauto$EXE diff --git a/checkauto.ll b/checkauto.ll new file mode 100644 index 00000000..a2822d9b --- /dev/null +++ b/checkauto.ll @@ -0,0 +1,101 @@ +/* Check for illegal return/break/continue usage inside a STC-lib c_auto* block (RAII). + * Copyright Tyge Løvset, (c) 2021. + */ +%{ +#include +enum { LOOP=1<<0, AUTO=1<<1 }; +enum { NORMAL, BRACES, BRACESDONE }; +static int braces_lev = 0, block_lev = 0; +static int state = NORMAL; +static unsigned int block[64] = {0}, block_type = 0; +const char* fname; +%} + +ID [_a-zA-Z][_a-zA-Z0-9]* +STR \"([^"\\]|\\.)*\" + +%option never-interactive noyymore noyywrap nounistd +%x cmt +%x prep + +%% +\/\/.* ; // line cmt +\/\* BEGIN(cmt); +\n ++yylineno; +\*\/ BEGIN(INITIAL); +. ; +^[ \t]*#.*\\\n { ++yylineno; BEGIN(prep); } +.*\\\n ++yylineno; +.*\n { ++yylineno; BEGIN(INITIAL); } +^[ \t]*#.* ; +{STR} ; +'\\?.' ; +c_foreach | +c_forrange | +for | +while | +switch { block_type |= LOOP; state = BRACES; } +do { block_type |= LOOP; state = BRACESDONE; } +if { state = BRACES; } +c_autovar | +c_autoscope | +c_autodefer | +c_auto { block_type = AUTO; state = BRACES; } +\( { if (state == BRACES) ++braces_lev; } +\) { if (state == BRACES && --braces_lev == 0) { + state = BRACESDONE; + } + } +;[ \t]*else ; +; { if (state == BRACESDONE) { + block_type = block[block_lev]; + state = NORMAL; + } + } +\{ { if (state != BRACES) { block[++block_lev] = block_type; state = NORMAL; } } +\} { if (state != BRACES) block_type = block[--block_lev]; } +return { if (block_type == AUTO) { + printf("%s:%d: error: 'return' used inside a c_auto* scope.\n" + " Use 'c_breakauto' to exit the current c_auto* scope.\n", fname, yylineno); + } else if (block_type & AUTO) { + printf("%s:%d: error: 'return' used in a loop inside a c_auto* scope.\n" + " Use 'break' to exit loops, then 'c_breakauto' to exit c_auto*.\n", fname, yylineno); + } + } +break { if (block_type == AUTO) + printf("%s:%d: error: 'break' used inside a c_auto* scope.\n" + " Use 'c_breakauto' to exit the current c_auto* scope.\n", fname, yylineno); + } +continue { if (block_type == AUTO) + printf("%s:%d: warning: 'continue' used inside a c_auto* scope.\n" + " It will only break out of the current c_auto* scope.\n" + " Use 'c_breakauto' instead to make it explicit.\n", fname, yylineno); + } +c_breakauto { if (block_type != AUTO) + printf("%s:%d: warning: 'c_breakauto' used outside a c_auto* scope.\n" + " Did you mean 'continue' instead?", fname, yylineno); + } +{ID} ; +\n ++yylineno; +. ; + +%% + +#include + +int main(int argc, char **argv) +{ + if (argc == 1 || strcmp(argv[1], "--help") == 0) { + printf("usage: %s [--help] {C-file | -}\n", argv[0]); + return 0; + } + if (strcmp(argv[1], "-") == 0) { + fname = ""; + yyin = stdin; + } else { + fname = argv[1]; + yyin = fopen(fname, "r"); + } + + yylex(); +} diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 9c872519..bd7029c4 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -6,18 +6,18 @@ The following handy macros are safe to use, i.e. have no side-effects. General ***defer*** mechanics for resource acquisition. These macros allows to specify the release of the resource where the resource acquisition takes place. Makes it easier to verify that resources are released. -**NB**: These macros are one-time executed **for-loops**. Use ***only*** `c_exitauto` in order to break out +**NB**: These macros are one-time executed **for-loops**. Use ***only*** `c_breakauto` in order to break out of these `c_auto*`-blocks! ***Do not*** use `return` or `goto` (or `break`) inside them, as they will prevent the `end`-statement to be executed when leaving scope. This is not particular to the `c_auto*()` macros, as one must always make sure to unwind temporary allocated resources before a `return` in C. -| Usage | Description | -|:---------------------------------------|:---------------------------------------------------| -| `c_auto (Type, var...)` | `c_autovar (Type var=Type_init(), Type_drop(&var))` | -| `c_autovar (Type var=init, end...)` | Declare `var`. Defer `end...` to end of block | -| `c_autoscope (init, end...)` | Execute `init`. Defer `end...` to end of block | -| `c_autodefer (end...)` | Defer `end...` to end of block | -| `c_exitauto;` | Break safely out of a `c_auto*`-block/scope | +| Usage | Description | +|:---------------------------------------|:-----------------------------------------------------| +| `c_auto (Type, var...)` | `c_autovar (Type var=Type_init(), Type_drop(&var))` | +| `c_autovar (Type var=init, end...)` | Declare `var`. Defer `end...` to end of block | +| `c_autoscope (init, end...)` | Execute `init`. Defer `end...` to end of block | +| `c_autodefer (end...)` | Defer `end...` to end of block | +| `c_breakauto;` | Break out of a `c_auto*`-block/scope without memleak | For multiple variables, use either multiple **c_autovar** in sequence, or declare variable outside scope and use **c_autoscope**. Also, **c_auto** support up to 3 variables. diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 8ae0dfae..b2ae7b97 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -169,6 +169,7 @@ STC_INLINE uint64_t c_default_hash(const void* key, size_t len) { #define c_autovar(declvar, ...) for (declvar, *_c_ii = NULL; !_c_ii; ++_c_ii, __VA_ARGS__) #define c_autoscope(init, ...) for (int _c_ii = (init, 0); !_c_ii; ++_c_ii, __VA_ARGS__) #define c_autodefer(...) for (int _c_ii = 0; !_c_ii; ++_c_ii, __VA_ARGS__) +#define c_breakauto continue #define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__) #define c_auto_2(C, a) \ -- cgit v1.2.3