summaryrefslogtreecommitdiffhomepage
path: root/src/checkauto.l
diff options
context:
space:
mode:
authorTyge Løvset <[email protected]>2022-01-11 20:51:50 +0100
committerTyge Løvset <[email protected]>2022-01-11 20:51:50 +0100
commitd85a4e9e396688b6b5b29c0ffb07de7ce9013b74 (patch)
tree47b60c3014cedd703b1db850c9a7a111e00b3b7c /src/checkauto.l
parentaf1b2068b39deebfbf723532a2eddc49da61894a (diff)
downloadSTC-modified-d85a4e9e396688b6b5b29c0ffb07de7ce9013b74.tar.gz
STC-modified-d85a4e9e396688b6b5b29c0ffb07de7ce9013b74.zip
Added tinycthread: include/threads.h, src/threads.c. Ex: sptr_threads.c - emulates standard C11 threads library for compilers not supporting C11 threads.h.
Fixed and cleanup of CMake build.
Diffstat (limited to 'src/checkauto.l')
-rw-r--r--src/checkauto.l138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/checkauto.l b/src/checkauto.l
new file mode 100644
index 00000000..5b4a9c68
--- /dev/null
+++ b/src/checkauto.l
@@ -0,0 +1,138 @@
+/* Check for illegal return/break/continue usage inside a STC-lib c_auto* block (RAII).
+ * Copyright Tyge Løvset, (c) 2022.
+ */
+%{
+#include <stdbool.h>
+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;
+int errors = 0, warnings = 0;
+%}
+
+ID [_a-zA-Z][_a-zA-Z0-9]*
+STR \"([^"\\]|\\.)*\"
+
+%option never-interactive noyymore noyywrap nounistd
+%x cmt
+%x prep
+
+%%
+\/\/.* ; // line cmt
+\/\* BEGIN(cmt);
+<cmt>\n ++yylineno;
+<cmt>\*\/ BEGIN(INITIAL);
+<cmt>. ;
+^[ \t]*#.*\\\n { ++yylineno; BEGIN(prep); }
+<prep>.*\\\n ++yylineno;
+<prep>.* BEGIN(INITIAL);
+^[ \t]*#.* ;
+{STR} ;
+'\\?.' ;
+c_foreach |
+c_forpair |
+c_forrange |
+for |
+while |
+switch { block_type |= LOOP; state = BRACES; }
+do { block_type |= LOOP; state = BRACESDONE; }
+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;
+ }
+ }
+if { if (state == BRACESDONE) {
+ if (block_type == AUTO) {
+ printf("%s:%d: warning: 'if' after c_auto* not enclosed in curly braces.\n"
+ " Make sure to enclose 'if - else' statement in { } after c_auto*.\n",
+ fname, yylineno);
+ ++warnings;
+ }
+ state = BRACES;
+ }
+ }
+;[ \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);
+ ++errors;
+ } 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);
+ ++errors;
+ }
+ }
+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);
+ ++errors;
+ }
+ }
+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);
+ ++warnings;
+ }
+ }
+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);
+ ++warnings;
+ }
+ }
+{ID} ;
+\n ++yylineno;
+. ;
+
+%%
+
+#include <string.h>
+
+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;
+ }
+
+ for (int i=1; i<argc; ++i) {
+ if (strcmp(argv[i], "-") == 0) {
+ fname = "<stdin>";
+ yyin = stdin;
+ } else {
+ fname = argv[i];
+ yyin = fopen(fname, "r");
+ }
+ yylineno = 1;
+ braces_lev = 0, block_lev = 0;
+ block_type = 0, state = NORMAL;
+
+ yylex();
+
+ fclose(yyin);
+ }
+
+ if (errors + warnings)
+ printf("%d error%s, %d warning%s.\n", errors, errors == 1? "":"s",
+ warnings, warnings == 1? "":"s");
+ return errors;
+}