@@ -489,7 +489,21 @@ static Token identifier_token(Lexer* lexer) {
489489 if (len_val + 1 >= capacity ) { capacity *= 2 ; value = safe_realloc (value , capacity ); }
490490 value [len_val ++ ] = c ;
491491 } else if (c == '^' ) {
492- consume_line_continuation (lexer );
492+ /* Only treat '^' as a continuation marker when it is
493+ * immediately followed by a newline (LF/CR) or a comment
494+ * introducer ('!'). Otherwise it's a syntax error per
495+ * the specification.
496+ */
497+ if (lexer -> current + 1 < lexer -> source_len ) {
498+ char next = lexer -> source [lexer -> current + 1 ];
499+ if (next == '\n' || next == '\r' || next == '!' ) {
500+ consume_line_continuation (lexer );
501+ continue ;
502+ }
503+ }
504+ free (value );
505+ advance (lexer ); /* consume the '^' so error token has correct location */
506+ return error_token (lexer , "Invalid line continuation" );
493507 } else {
494508 break ;
495509 }
@@ -546,8 +560,20 @@ static Token number_token(Lexer* lexer, bool is_negative_start) {
546560 while (!is_at_end (lexer )) {
547561 char c = peek (lexer );
548562 if (c == '^' ) {
549- consume_line_continuation (lexer );
550- continue ;
563+ /* Same rule as for identifiers: '^' only allowed as a
564+ * continuation marker when followed immediately by newline
565+ * or comment; otherwise it's a syntax error.
566+ */
567+ if (lexer -> current + 1 < lexer -> source_len ) {
568+ char next = lexer -> source [lexer -> current + 1 ];
569+ if (next == '\n' || next == '\r' || next == '!' ) {
570+ consume_line_continuation (lexer );
571+ continue ;
572+ }
573+ }
574+ free (value );
575+ advance (lexer );
576+ return error_token (lexer , "Invalid line continuation" );
551577 }
552578 if (c == '.' && !has_dot ) {
553579 has_dot = true;
0 commit comments