diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-18 08:02:20 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-18 08:02:20 +0000 |
| commit | 34a4998658674411ef3b5a392483990467a5d6e2 (patch) | |
| tree | ace5773a4890ffb88d8f3338f9938d4dfa929804 | |
| parent | e7320359c12b97ccb85ebfb06b2540124630df7b (diff) | |
feat(lexer): accept identifiers starting with an underscore
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | AGENTS/CONVENTIONS.md | 2 | ||||
| -rw-r--r-- | doc/language/cpsc-language-overview.7.md | 2 | ||||
| -rw-r--r-- | lib/Lexer/Lexer.cc | 11 | ||||
| -rw-r--r-- | tests/i/underscore-identifiers/case.json | 1 | ||||
| -rw-r--r-- | tests/i/underscore-identifiers/expected.txt | 1 | ||||
| -rw-r--r-- | tests/i/underscore-identifiers/program.cps | 9 | ||||
| -rw-r--r-- | tests/iii/reserved-prefix/case.json | 1 | ||||
| -rw-r--r-- | tests/iii/reserved-prefix/program.cps | 1 |
8 files changed, 26 insertions, 2 deletions
diff --git a/AGENTS/CONVENTIONS.md b/AGENTS/CONVENTIONS.md index 41b049f..598ff76 100644 --- a/AGENTS/CONVENTIONS.md +++ b/AGENTS/CONVENTIONS.md @@ -207,3 +207,5 @@ is an LLVM GlobalVariable and must survive FunctionGen's symbol reset. User MAIN case insensitive, takes no parameters and returns INTEGER; its LLVM name is __cps_main with internal linkage. The generated i32 main wrapper calls it through ExceptionHandler, truncates its result and retains the final uncaught handler. + +Identifiers may begin with an underscore. The case-insensitive `__cps_` prefix is reserved in every user identifier, including EXTERN declarations. diff --git a/doc/language/cpsc-language-overview.7.md b/doc/language/cpsc-language-overview.7.md index ff3d1f0..96fb071 100644 --- a/doc/language/cpsc-language-overview.7.md +++ b/doc/language/cpsc-language-overview.7.md @@ -6,7 +6,7 @@ cpsc-language-overview - supported cpsc pseudocode syntax # DESCRIPTION -Keywords are uppercase and case-sensitive. Identifiers, including built-in function names, are case insensitive. Indentation is for readability; blocks use explicit closing keywords. Identifiers begin with a letter and continue with letters, digits, or underscores. +Keywords are uppercase and case-sensitive. Identifiers, including built-in function names, are case insensitive. Indentation is for readability; blocks use explicit closing keywords. Identifiers begin with a letter or underscore and continue with letters, digits, or underscores. Assign with ASCII `<-`: `Count <- Count + 1`. Compare with `=`, `<>`, `<`, `>`, `<=`, and `>=`. Built-in STRING comparisons compare contents, case-sensitively. Use `+`, `-`, `*`, and `/` for arithmetic; built-in `/` always returns REAL. Use `&` to join strings. diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc index edc77de..9435d04 100644 --- a/lib/Lexer/Lexer.cc +++ b/lib/Lexer/Lexer.cc @@ -124,11 +124,20 @@ int Lexer::readToken() { return IsChar ? tok_char_literal : tok_string_literal; } - if (isalpha(LastChar)) { + if (isalpha(LastChar) || LastChar == '_') { IdentifierStr = static_cast<char>(LastChar); while (isalnum((LastChar = Input.get())) || LastChar == '_') IdentifierStr += static_cast<char>(LastChar); + if (IdentifierStr.size() >= 6) { + std::string Prefix = IdentifierStr.substr(0, 6); + std::transform(Prefix.begin(), Prefix.end(), Prefix.begin(), + [](unsigned char C) { return std::tolower(C); }); + if (Prefix == "__cps_") { + cps::sourceDiagnostic(TokenLine, "error: Reserved runtime identifier at line %d\n", TokenLine); + HadError = true; + } + } if (IdentifierStr == "CONSTANT") return tok_constant; if (IdentifierStr == "INCLUDE") return tok_include; if (IdentifierStr == "INCLUDE_OBJ") return tok_include_obj; diff --git a/tests/i/underscore-identifiers/case.json b/tests/i/underscore-identifiers/case.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/i/underscore-identifiers/case.json @@ -0,0 +1 @@ +{} diff --git a/tests/i/underscore-identifiers/expected.txt b/tests/i/underscore-identifiers/expected.txt new file mode 100644 index 0000000..d81cc07 --- /dev/null +++ b/tests/i/underscore-identifiers/expected.txt @@ -0,0 +1 @@ +42 diff --git a/tests/i/underscore-identifiers/program.cps b/tests/i/underscore-identifiers/program.cps new file mode 100644 index 0000000..60d7b32 --- /dev/null +++ b/tests/i/underscore-identifiers/program.cps @@ -0,0 +1,9 @@ +CLASS _EXP_FOO + _Value : INTEGER +ENDCLASS +FUNCTION _Read(_Arg : INTEGER) RETURNS INTEGER + RETURN _Arg + 1 +ENDFUNCTION +DECLARE _X : _EXP_FOO +_X._Value <- _Read(41) +OUTPUT _X._Value diff --git a/tests/iii/reserved-prefix/case.json b/tests/iii/reserved-prefix/case.json new file mode 100644 index 0000000..a28bf5d --- /dev/null +++ b/tests/iii/reserved-prefix/case.json @@ -0,0 +1 @@ +{"errors":[{"reason":"Reserved runtime identifier","line":1}]} diff --git a/tests/iii/reserved-prefix/program.cps b/tests/iii/reserved-prefix/program.cps new file mode 100644 index 0000000..3a61a6b --- /dev/null +++ b/tests/iii/reserved-prefix/program.cps @@ -0,0 +1 @@ +DECLARE __CpS_user_line : INTEGER |
