Exercise 2: A String Spanning Multiple Lines — Possible Solution ==================================================================== SOURCE ------------------------------ var greeting = "line one line two line three"; var next = 1; RESULT ------------------------------ VAR('var', line=1) IDENTIFIER('greeting', line=1) EQUAL('=', line=1) STRING('line one\nline two\nline three', line=1) SEMICOLON(';', line=3) VAR('var', line=4) IDENTIFIER('next', line=4) EQUAL('=', line=4) NUMBER('1', line=4) SEMICOLON(';', line=4) EOF('', line=4) String token's own reported starting line: 1 (correct - where the opening quote is) 'next' identifier's own line, after the multi-line string: 4 (correct) WHY THIS WORKS AS AN ANSWER ------------------------------ The STRING token itself is reported at line 1 - the line where the opening quote appears, not where the string ends - which is the correct, useful convention for error reporting (an error about "the unterminated string" should point at where the string started, not where the file happened to run out). Internally, the string-scanning loop still increments `line` every time it encounters a newline INSIDE the string content, which is why tokenizing correctly resumes at line 4 for the code immediately following the closing quote - the line counter was never paused or confused by string content spanning multiple physical lines. This confirms the chapter's own lexer handles a case it wasn't explicitly demonstrated against, purely because line tracking was built as a general mechanism (increment on every '\n' encountered) rather than something special-cased only for code outside of strings.