From 7fc4021d888b4f16f8fa87c0ea1df68d3806df64 Mon Sep 17 00:00:00 2001 From: Chimrod <> Date: Thu, 28 Sep 2023 09:16:56 +0200 Subject: Renamed the lexer --- lib/UTF16.ml | 214 ----------------------------------------- lib/analyzer.ml | 4 +- lib/expression_parser.messages | 191 ++++++++++++++++++------------------ lib/interpreter.ml | 5 +- lib/lexer.ml | 211 ++++++++++++++++++++++++++++++++++++++++ lib/lexer.mli | 10 ++ 6 files changed, 321 insertions(+), 314 deletions(-) delete mode 100644 lib/UTF16.ml create mode 100644 lib/lexer.ml create mode 100644 lib/lexer.mli diff --git a/lib/UTF16.ml b/lib/UTF16.ml deleted file mode 100644 index e325011..0000000 --- a/lib/UTF16.ml +++ /dev/null @@ -1,214 +0,0 @@ -(** - Lexer using sedlex - *) - -open Tokens - -exception UnclosedQuote of { content : string; line : int } -exception LexError of Lexing.position * string - -let pp_pos out { Lexing.pos_lnum; pos_cnum; pos_bol; _ } = - Format.fprintf out "line %d:%d" pos_lnum (pos_cnum - pos_bol) - -module type Encoding = sig - val lexeme : Sedlexing.lexbuf -> string -end - -(* The comment system is terrible. The same symbol can be used for : - - starting a comment - - inequality operation - In order to manage this, I try to identify the context in a very basic way, - using a flag True False for determining the token to send. -*) -module Bucket = Ephemeron.K1.Bucket - -type bucket = (Sedlexing.lexbuf, int) Bucket.t - -let is_expression : bucket = Bucket.make () - -let incr_level lexbuf = - match Bucket.find is_expression lexbuf with - | None -> Bucket.add is_expression lexbuf 1 - | Some v -> Bucket.add is_expression lexbuf (v + 1) - -let decr_level lexbuf = - match Bucket.find is_expression lexbuf with - | None -> () - | Some v -> - if v > 1 then Bucket.add is_expression lexbuf (v - 1) - else Bucket.remove is_expression lexbuf - -let build_ident lexbuf = - let id = - Sedlexing.lexeme lexbuf |> Idents.of_uchars |> String.uppercase_ascii - in - try - let value = Hashtbl.find Idents.keyword_table id in - let _ = match value with IF | ELIF -> incr_level lexbuf | _ -> () in - value - with Not_found -> IDENT id - -let incr_level lexbuf = - match Bucket.find is_expression lexbuf with - | None -> Bucket.add is_expression lexbuf 1 - | Some v -> Bucket.add is_expression lexbuf (v + 1) - -let wait_balance rule lexbuf = - try[@warning "-52"] rule (Buffer.create 17) lexbuf - with Failure "lexing: empty token" -> - let position, _ = Sedlexing.lexing_positions lexbuf in - let line = position.Lexing.pos_lnum - and content = Sedlexing.lexeme lexbuf |> Idents.of_uchars in - (raise (UnclosedQuote { line; content }) [@warning "+52"]) - -let space = [%sedlex.regexp? ' ' | '\t'] -let eol = [%sedlex.regexp? '\r' | '\n' | "\r\n"] -let coma = [%sedlex.regexp? ','] -let digit = [%sedlex.regexp? '0' .. '9'] -let letters = [%sedlex.regexp? 'a' .. 'z' | 'A' .. 'Z' | '_'] -let spaces = [%sedlex.regexp? Plus space] -let ident = [%sedlex.regexp? ('$' | letters), Star (digit | letters)] -let location_ident = [%sedlex.regexp? letters | digit] -let location_prefix = [%sedlex.regexp? '!' | '$' | '#' | '^'] -let location = [%sedlex.regexp? Opt location_prefix, Plus location_ident] - -let rec read_long_string level buf lexbuf = - match%sedlex lexbuf with - | '{' -> - Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); - read_long_string (level + 1) buf lexbuf - | '}' -> ( - match level with - | 0 -> Buffer.contents buf - | _ -> - Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); - read_long_string (level - 1) buf lexbuf) - | eol -> - Sedlexing.new_line lexbuf; - Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); - read_long_string level buf lexbuf - | any -> - Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); - read_long_string level buf lexbuf - | _ -> raise Not_found - -let rec read_dquoted_string buf lexbuf = - match%sedlex lexbuf with - | "\"\"" -> - Buffer.add_char buf '"'; - read_dquoted_string buf lexbuf - | '"' -> Buffer.contents buf - | any -> - Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); - read_dquoted_string buf lexbuf - | _ -> raise Not_found - -let rec read_quoted_string buf lexbuf = - match%sedlex lexbuf with - | "''" -> - Buffer.add_char buf '\''; - read_quoted_string buf lexbuf - | '\'' -> Buffer.contents buf - | eol -> - Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); - Sedlexing.new_line lexbuf; - read_quoted_string buf lexbuf - | any -> - Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); - read_quoted_string buf lexbuf - | _ -> raise Not_found - -let rec skip_comment lexbuf = - match%sedlex lexbuf with - | '{' -> - let _ = wait_balance (read_long_string 0) lexbuf in - skip_comment lexbuf - | '\'' -> - let _ = wait_balance read_quoted_string lexbuf in - skip_comment lexbuf - | '"' -> - let _ = wait_balance read_dquoted_string lexbuf in - skip_comment lexbuf - | eol -> - (* Ugly hack used in order to put the eol in the front of the next - parsing. *) - Sedlexing.rollback lexbuf; - COMMENT - | any -> skip_comment lexbuf - | _ -> raise Not_found - -(** Main lexer *) -let rec token : (module Encoding.S) -> Sedlexing.lexbuf -> token = - fun (module E : Encoding) lexbuf -> - match%sedlex lexbuf with - | 0Xfeff -> - (* Ignore the BOM *) - token (module E) lexbuf - | '#', Star space, location -> - let ident = E.lexeme lexbuf in - - LOCATION_START ident - | Plus digit -> INTEGER (E.lexeme lexbuf) - | '+' -> PLUS - | '-' -> MINUS - | "+=" -> INCR - | "-=" -> DECR - | "*=" -> MULT_EQUAL - | '/' -> DIV - | '*' -> STAR - | ':' -> - (* We are leaving the block, the comment will be handled again *) - decr_level lexbuf; - COLUMN - | '-', Plus '-', Star (Sub (any, ('\r' | '\n'))) -> LOCATION_END - | '[' -> L_BRACKET - | ']' -> R_BRACKET - | '(' -> - incr_level lexbuf; - L_PAREN - | ')' -> - decr_level lexbuf; - R_PAREN - | '<' -> LT - | '>' -> GT - | coma -> COMA - | eof -> - Bucket.remove is_expression lexbuf; - EOF - | '=' -> - incr_level lexbuf; - EQUAL - | ident -> build_ident lexbuf - | eol -> - Bucket.add is_expression lexbuf 0; - Sedlexing.new_line lexbuf; - EOL - | '&' -> - Bucket.add is_expression lexbuf 0; - AMPERSAND - | '!' -> ( - match Bucket.find is_expression lexbuf with - | Some i when i <> 0 -> EXCLAMATION - | _ -> skip_comment lexbuf) - | spaces -> token (module E) lexbuf - | '\'' -> LITERAL (wait_balance read_quoted_string lexbuf) - | '"' -> LITERAL (wait_balance read_dquoted_string lexbuf) - | '{' -> LITERAL (wait_balance (read_long_string 0) lexbuf) - | _ -> - let position = fst @@ Sedlexing.lexing_positions lexbuf in - let tok = E.lexeme lexbuf in - - let msg = - Format.asprintf "Unexpected character %S at %a" tok pp_pos position - in - - raise @@ LexError (position, msg) - -(** Tokenizer for menhir *) -let lexer : - (module Encoding) -> - Sedlexing.lexbuf -> - unit -> - token * Lexing.position * Lexing.position = - fun (module E : Encoding.S) lexbuf -> - Sedlexing.with_tokenizer (token (module E)) lexbuf diff --git a/lib/analyzer.ml b/lib/analyzer.ml index b422b24..e4fc272 100644 --- a/lib/analyzer.ml +++ b/lib/analyzer.ml @@ -17,7 +17,7 @@ let format_error : Format.formatter -> error -> unit = else Format.fprintf f "Line %d %d:%d %s" start_line start_c end_c e.message (** - Run the QSP parser and apply the analyzer over it. + Run the QSP parser and apply the analyzer over it. See [syntax/S] *) @@ -33,7 +33,7 @@ let parse : Interpreter.Interpreter (Parser.MenhirInterpreter) in fun lexbuf -> IncrementalParser.of_lexbuf lexbuf - (UTF16.lexer (module E)) + (Lexer.lexer (module E)) Parser.Incremental.main |> Result.map_error (fun e -> let message = diff --git a/lib/expression_parser.messages b/lib/expression_parser.messages index 6907c43..e9a83c6 100644 --- a/lib/expression_parser.messages +++ b/lib/expression_parser.messages @@ -2,7 +2,7 @@ main: LOCATION_START EOL IDENT SET ## ## Ends in an error in state: 12. ## -## variable -> IDENT . option(delimited(L_BRACKET,option(expression),R_BRACKET)) [ STAR R_PAREN R_BRACKET PLUS OR MOD MINUS LT INCR GT EXCLAMATION EQUAL EOL ELSE DIV DECR COMA COLUMN AND AMPERSAND ] +## variable -> IDENT . option(delimited(L_BRACKET,option(expression),R_BRACKET)) [ STAR R_PAREN R_BRACKET PLUS OR MULT_EQUAL MOD MINUS LT INCR GT EXCLAMATION EQUAL EOL ELSE DIV DECR COMA COLUMN AND AMPERSAND ] ## ## The known suffix of the stack is as follows: ## IDENT @@ -40,7 +40,7 @@ Unexpected '('. Did you forgot a function before ? main: LOCATION_START EOL IF INTEGER SET ## -## Ends in an error in state: 85. +## Ends in an error in state: 86. ## ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] ## expression -> expression . LT GT expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] @@ -66,11 +66,11 @@ main: LOCATION_START EOL IF INTEGER SET ## IF expression ## -Invalid `IF` condition. You probably missed a ':' +The `IF` expression does not end properly. A `:` is expected before any instruction. main: LOCATION_START EOL COLUMN STAR ## -## Ends in an error in state: 90. +## Ends in an error in state: 91. ## ## line_statement -> COLUMN . IDENT list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## @@ -82,7 +82,7 @@ A location is expected after ':' not an expression main: LOCATION_START EOL ACT INTEGER SET ## -## Ends in an error in state: 94. +## Ends in an error in state: 95. ## ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] ## expression -> expression . LT GT expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] @@ -112,7 +112,7 @@ Invalid `ACT` label. You probably missed a ':' main: LOCATION_START EOL ACT IDENT COLUMN EOL LOCATION_END ## -## Ends in an error in state: 96. +## Ends in an error in state: 97. ## ## line_statement -> ACT expression COLUMN nonempty_list(EOL) . list(line_statement) empty_body END option(ACT) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> ACT expression COLUMN nonempty_list(EOL) . list(line_statement) empty_body END option(ACT) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -132,7 +132,7 @@ If there are nested blocks, the error will points the highest block. main: LOCATION_START EOL IF IDENT COLUMN ELSE R_PAREN ## -## Ends in an error in state: 102. +## Ends in an error in state: 103. ## ## option(preceded(ELSE,instruction)) -> ELSE . instruction [ EOL ELSE AMPERSAND ] ## @@ -144,7 +144,7 @@ Too manies instructions on a single line. main: LOCATION_START EOL IF IDENT COLUMN EOL IDENT AMPERSAND LOCATION_END ## -## Ends in an error in state: 150. +## Ends in an error in state: 151. ## ## line_statement -> IF expression COLUMN nonempty_list(EOL) list(line_statement) . elif_else_body END option(IF) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> IF expression COLUMN nonempty_list(EOL) list(line_statement) . elif_else_body END option(IF) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -156,19 +156,18 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL IDENT AMPERSAND LOCATION_END ## This implies that, although the LR(1) items shown above provide an ## accurate view of the past (what has been recognized so far), they ## may provide an INCOMPLETE view of the future (what was expected next). -## In state 121, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND -## In state 130, spurious reduction of production list(EOL) -> -## In state 131, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) -## In state 126, spurious reduction of production list(line_statement) -> -## In state 127, spurious reduction of production list(line_statement) -> line_statement list(line_statement) +## In state 122, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND +## In state 131, spurious reduction of production list(EOL) -> +## In state 132, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) +## In state 127, spurious reduction of production list(line_statement) -> +## In state 128, spurious reduction of production list(line_statement) -> line_statement list(line_statement) ## -Unclosed statement. -(The error may be above in the code, for example a missing `END` after an `IF`) +Unclosed `IF` block. main: LOCATION_START EOL IF IDENT COLUMN EOL ELSE EOL LOCATION_END ## -## Ends in an error in state: 158. +## Ends in an error in state: 159. ## ## else_ -> ELSE nonempty_list(EOL) . list(line_statement) [ END ] ## @@ -187,7 +186,7 @@ If there are nested blocks, the error will points the highest block. main: LOCATION_START EOL IDENT AMPERSAND END ## -## Ends in an error in state: 170. +## Ends in an error in state: 171. ## ## main -> list(EOL) LOCATION_START nonempty_list(EOL) list(line_statement) . LOCATION_END list(EOL) EOF [ # ] ## @@ -198,11 +197,11 @@ main: LOCATION_START EOL IDENT AMPERSAND END ## This implies that, although the LR(1) items shown above provide an ## accurate view of the past (what has been recognized so far), they ## may provide an INCOMPLETE view of the future (what was expected next). -## In state 121, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND -## In state 130, spurious reduction of production list(EOL) -> -## In state 131, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) -## In state 126, spurious reduction of production list(line_statement) -> -## In state 127, spurious reduction of production list(line_statement) -> line_statement list(line_statement) +## In state 122, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND +## In state 131, spurious reduction of production list(EOL) -> +## In state 132, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) +## In state 127, spurious reduction of production list(line_statement) -> +## In state 128, spurious reduction of production list(line_statement) -> line_statement list(line_statement) ## Unexpected `END`. @@ -222,7 +221,7 @@ Missing location name main: LOCATION_START EOL INTEGER SET ## -## Ends in an error in state: 113. +## Ends in an error in state: 114. ## ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] ## expression -> expression . LT GT expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] @@ -289,7 +288,7 @@ main: LOCATION_START EOL IDENT L_BRACKET STAR ## ## Ends in an error in state: 13. ## -## option(delimited(L_BRACKET,option(expression),R_BRACKET)) -> L_BRACKET . option(expression) R_BRACKET [ STAR R_PAREN R_BRACKET PLUS OR MOD MINUS LT INCR GT EXCLAMATION EQUAL EOL ELSE DIV DECR COMA COLUMN AND AMPERSAND ] +## option(delimited(L_BRACKET,option(expression),R_BRACKET)) -> L_BRACKET . option(expression) R_BRACKET [ STAR R_PAREN R_BRACKET PLUS OR MULT_EQUAL MOD MINUS LT INCR GT EXCLAMATION EQUAL EOL ELSE DIV DECR COMA COLUMN AND AMPERSAND ] ## ## The known suffix of the stack is as follows: ## L_BRACKET @@ -1133,7 +1132,7 @@ main: LOCATION_START EOL SET IDENT STAR main: LOCATION_START EOL SET IDENT DECR STAR ## -## Ends in an error in state: 77. +## Ends in an error in state: 78. ## ## let_assignation -> SET variable assignation_operator . expression [ EOL ELSE AMPERSAND ] ## @@ -1145,7 +1144,7 @@ main: LOCATION_START EOL SET IDENT DECR STAR main: LOCATION_START EOL SET IDENT DECR INTEGER SET ## -## Ends in an error in state: 78. +## Ends in an error in state: 79. ## ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] ## expression -> expression . LT GT expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] @@ -1173,7 +1172,7 @@ main: LOCATION_START EOL SET IDENT DECR INTEGER SET main: LOCATION_START EOL LET STAR ## -## Ends in an error in state: 79. +## Ends in an error in state: 80. ## ## let_assignation -> LET . variable assignation_operator expression [ EOL ELSE AMPERSAND ] ## @@ -1185,7 +1184,7 @@ main: LOCATION_START EOL LET STAR main: LOCATION_START EOL LET IDENT STAR ## -## Ends in an error in state: 80. +## Ends in an error in state: 81. ## ## let_assignation -> LET variable . assignation_operator expression [ EOL ELSE AMPERSAND ] ## @@ -1204,7 +1203,7 @@ main: LOCATION_START EOL LET IDENT STAR main: LOCATION_START EOL LET IDENT DECR STAR ## -## Ends in an error in state: 81. +## Ends in an error in state: 82. ## ## let_assignation -> LET variable assignation_operator . expression [ EOL ELSE AMPERSAND ] ## @@ -1216,7 +1215,7 @@ main: LOCATION_START EOL LET IDENT DECR STAR main: LOCATION_START EOL LET IDENT DECR INTEGER SET ## -## Ends in an error in state: 82. +## Ends in an error in state: 83. ## ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] ## expression -> expression . LT GT expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] @@ -1244,7 +1243,7 @@ main: LOCATION_START EOL LET IDENT DECR INTEGER SET main: LOCATION_START EOL IF STAR ## -## Ends in an error in state: 84. +## Ends in an error in state: 85. ## ## line_statement -> IF . expression COLUMN nonempty_list(EOL) list(line_statement) elif_else_body END option(IF) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> IF . expression COLUMN nonempty_list(EOL) list(line_statement) elif_else_body END option(IF) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1258,7 +1257,7 @@ main: LOCATION_START EOL IF STAR main: LOCATION_START EOL IF IDENT COLUMN R_PAREN ## -## Ends in an error in state: 86. +## Ends in an error in state: 87. ## ## line_statement -> IF expression COLUMN . nonempty_list(EOL) list(line_statement) elif_else_body END option(IF) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> IF expression COLUMN . nonempty_list(EOL) list(line_statement) elif_else_body END option(IF) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1272,7 +1271,7 @@ main: LOCATION_START EOL IF IDENT COLUMN R_PAREN main: LOCATION_START EOL IF IDENT COLUMN EOL LOCATION_END ## -## Ends in an error in state: 87. +## Ends in an error in state: 88. ## ## line_statement -> IF expression COLUMN nonempty_list(EOL) . list(line_statement) elif_else_body END option(IF) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> IF expression COLUMN nonempty_list(EOL) . list(line_statement) elif_else_body END option(IF) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1291,7 +1290,7 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL LOCATION_END main: LOCATION_START EOL COMMENT STAR ## -## Ends in an error in state: 88. +## Ends in an error in state: 89. ## ## line_statement -> COMMENT . nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## @@ -1303,7 +1302,7 @@ main: LOCATION_START EOL COMMENT STAR main: LOCATION_START EOL COLUMN IDENT R_PAREN ## -## Ends in an error in state: 91. +## Ends in an error in state: 92. ## ## line_statement -> COLUMN IDENT . list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## @@ -1315,7 +1314,7 @@ main: LOCATION_START EOL COLUMN IDENT R_PAREN main: LOCATION_START EOL ACT STAR ## -## Ends in an error in state: 93. +## Ends in an error in state: 94. ## ## line_statement -> ACT . expression COLUMN nonempty_list(EOL) list(line_statement) empty_body END option(ACT) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> ACT . expression COLUMN nonempty_list(EOL) list(line_statement) empty_body END option(ACT) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1329,7 +1328,7 @@ main: LOCATION_START EOL ACT STAR main: LOCATION_START EOL ACT IDENT COLUMN R_PAREN ## -## Ends in an error in state: 95. +## Ends in an error in state: 96. ## ## line_statement -> ACT expression COLUMN . nonempty_list(EOL) list(line_statement) empty_body END option(ACT) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> ACT expression COLUMN . nonempty_list(EOL) list(line_statement) empty_body END option(ACT) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1343,7 +1342,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN R_PAREN main: LOCATION_START EOL IDENT R_PAREN ## -## Ends in an error in state: 97. +## Ends in an error in state: 98. ## ## expression -> variable . [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] ## let_assignation -> variable . assignation_operator expression [ EOL ELSE AMPERSAND ] @@ -1363,7 +1362,7 @@ main: LOCATION_START EOL IDENT R_PAREN main: LOCATION_START EOL IDENT DECR STAR ## -## Ends in an error in state: 98. +## Ends in an error in state: 99. ## ## let_assignation -> variable assignation_operator . expression [ EOL ELSE AMPERSAND ] ## @@ -1375,7 +1374,7 @@ main: LOCATION_START EOL IDENT DECR STAR main: LOCATION_START EOL IDENT DECR INTEGER SET ## -## Ends in an error in state: 99. +## Ends in an error in state: 100. ## ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] ## expression -> expression . LT GT expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV AND AMPERSAND ] @@ -1403,7 +1402,7 @@ main: LOCATION_START EOL IDENT DECR INTEGER SET main: LOCATION_START EOL IF IDENT COLUMN COMMENT STAR ## -## Ends in an error in state: 101. +## Ends in an error in state: 102. ## ## inline_action -> onliner(IF) . option(preceded(ELSE,instruction)) [ EOL ELSE AMPERSAND ] ## @@ -1415,7 +1414,7 @@ main: LOCATION_START EOL IF IDENT COLUMN COMMENT STAR main: LOCATION_START EOL KEYWORD STAR ## -## Ends in an error in state: 104. +## Ends in an error in state: 105. ## ## single_instruction -> keyword . qsp_instruction_argument(expression) [ EOL ELSE AMPERSAND ] ## @@ -1427,7 +1426,7 @@ main: LOCATION_START EOL KEYWORD STAR main: LOCATION_START EOL KEYWORD L_PAREN STAR ## -## Ends in an error in state: 105. +## Ends in an error in state: 106. ## ## expression -> L_PAREN . expression R_PAREN [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV COMA AND AMPERSAND ] ## optionnal_delimited(L_PAREN,arguments(expression),R_PAREN) -> L_PAREN . arguments(expression) R_PAREN [ EOL ELSE AMPERSAND ] @@ -1440,7 +1439,7 @@ main: LOCATION_START EOL KEYWORD L_PAREN STAR main: LOCATION_START EOL KEYWORD L_PAREN IDENT COMA IDENT EOL ## -## Ends in an error in state: 106. +## Ends in an error in state: 107. ## ## optionnal_delimited(L_PAREN,arguments(expression),R_PAREN) -> L_PAREN arguments(expression) . R_PAREN [ EOL ELSE AMPERSAND ] ## @@ -1462,7 +1461,7 @@ main: LOCATION_START EOL KEYWORD L_PAREN IDENT COMA IDENT EOL main: LOCATION_START EOL KEYWORD INTEGER SET ## -## Ends in an error in state: 110. +## Ends in an error in state: 111. ## ## arguments(expression) -> expression . COMA separated_nonempty_list(COMA,expression) [ EOL ELSE AMPERSAND ] ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL EOL ELSE DIV COMA AND AMPERSAND ] @@ -1491,7 +1490,7 @@ main: LOCATION_START EOL KEYWORD INTEGER SET main: LOCATION_START EOL ACT IDENT COLUMN EOL IDENT AMPERSAND LOCATION_END ## -## Ends in an error in state: 117. +## Ends in an error in state: 118. ## ## line_statement -> ACT expression COLUMN nonempty_list(EOL) list(line_statement) empty_body . END option(ACT) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> ACT expression COLUMN nonempty_list(EOL) list(line_statement) empty_body . END option(ACT) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1503,19 +1502,19 @@ main: LOCATION_START EOL ACT IDENT COLUMN EOL IDENT AMPERSAND LOCATION_END ## This implies that, although the LR(1) items shown above provide an ## accurate view of the past (what has been recognized so far), they ## may provide an INCOMPLETE view of the future (what was expected next). -## In state 121, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND -## In state 130, spurious reduction of production list(EOL) -> -## In state 131, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) -## In state 126, spurious reduction of production list(line_statement) -> -## In state 127, spurious reduction of production list(line_statement) -> line_statement list(line_statement) -## In state 116, spurious reduction of production empty_body -> +## In state 122, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND +## In state 131, spurious reduction of production list(EOL) -> +## In state 132, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) +## In state 127, spurious reduction of production list(line_statement) -> +## In state 128, spurious reduction of production list(line_statement) -> line_statement list(line_statement) +## In state 117, spurious reduction of production empty_body -> ## main: LOCATION_START EOL ACT IDENT COLUMN EOL END STAR ## -## Ends in an error in state: 118. +## Ends in an error in state: 119. ## ## line_statement -> ACT expression COLUMN nonempty_list(EOL) list(line_statement) empty_body END . option(ACT) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> ACT expression COLUMN nonempty_list(EOL) list(line_statement) empty_body END . option(ACT) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1528,7 +1527,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN EOL END STAR main: LOCATION_START EOL ACT IDENT COLUMN EOL END ACT STAR ## -## Ends in an error in state: 120. +## Ends in an error in state: 121. ## ## line_statement -> ACT expression COLUMN nonempty_list(EOL) list(line_statement) empty_body END option(ACT) . nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> ACT expression COLUMN nonempty_list(EOL) list(line_statement) empty_body END option(ACT) . nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1541,7 +1540,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN EOL END ACT STAR main: LOCATION_START EOL IDENT AMPERSAND R_PAREN ## -## Ends in an error in state: 121. +## Ends in an error in state: 122. ## ## nonempty_list(AMPERSAND) -> AMPERSAND . [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION EOL END ELSE ELIF COMMENT COLUMN AMPERSAND ACT ] ## nonempty_list(AMPERSAND) -> AMPERSAND . nonempty_list(AMPERSAND) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION EOL END ELSE ELIF COMMENT COLUMN AMPERSAND ACT ] @@ -1554,7 +1553,7 @@ main: LOCATION_START EOL IDENT AMPERSAND R_PAREN main: LOCATION_START EOL IDENT AMPERSAND EOL EOF ## -## Ends in an error in state: 126. +## Ends in an error in state: 127. ## ## list(line_statement) -> line_statement . list(line_statement) [ LOCATION_END END ELSE ELIF ] ## @@ -1567,14 +1566,14 @@ main: LOCATION_START EOL IDENT AMPERSAND EOL EOF ## may provide an INCOMPLETE view of the future (what was expected next). ## In state 1, spurious reduction of production list(EOL) -> ## In state 2, spurious reduction of production list(EOL) -> EOL list(EOL) -## In state 131, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) +## In state 132, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) ## main: LOCATION_START EOL IDENT ELSE ## -## Ends in an error in state: 128. +## Ends in an error in state: 129. ## ## line_statement -> instruction . nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> instruction . nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1588,16 +1587,16 @@ main: LOCATION_START EOL IDENT ELSE ## may provide an INCOMPLETE view of the future (what was expected next). ## In state 12, spurious reduction of production option(delimited(L_BRACKET,option(expression),R_BRACKET)) -> ## In state 72, spurious reduction of production variable -> IDENT option(delimited(L_BRACKET,option(expression),R_BRACKET)) -## In state 97, spurious reduction of production expression -> variable -## In state 113, spurious reduction of production single_instruction -> expression -## In state 100, spurious reduction of production instruction -> single_instruction +## In state 98, spurious reduction of production expression -> variable +## In state 114, spurious reduction of production single_instruction -> expression +## In state 101, spurious reduction of production instruction -> single_instruction ## main: LOCATION_START EOL ACT IDENT COLUMN COMMENT STAR ## -## Ends in an error in state: 132. +## Ends in an error in state: 133. ## ## line_statement -> inline_action . nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> inline_action . nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1610,7 +1609,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN COMMENT STAR main: LOCATION_START EOL ACT IDENT COLUMN IDENT AMPERSAND LOCATION_END ## -## Ends in an error in state: 136. +## Ends in an error in state: 137. ## ## final_inline_instruction -> inline_instruction . instruction [ EOL ELSE AMPERSAND ] ## final_inline_instruction -> inline_instruction . inline_action [ EOL ELSE AMPERSAND ] @@ -1625,15 +1624,15 @@ main: LOCATION_START EOL ACT IDENT COLUMN IDENT AMPERSAND LOCATION_END ## This implies that, although the LR(1) items shown above provide an ## accurate view of the past (what has been recognized so far), they ## may provide an INCOMPLETE view of the future (what was expected next). -## In state 121, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND -## In state 147, spurious reduction of production inline_instruction -> inline_instruction single_instruction nonempty_list(AMPERSAND) +## In state 122, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND +## In state 148, spurious reduction of production inline_instruction -> inline_instruction single_instruction nonempty_list(AMPERSAND) ## main: LOCATION_START EOL ACT IDENT COLUMN IF STAR ## -## Ends in an error in state: 137. +## Ends in an error in state: 138. ## ## onliner(IF) -> IF . expression COLUMN final_inline_instruction [ EOL ELSE AMPERSAND ] ## @@ -1645,7 +1644,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN IF STAR main: LOCATION_START EOL ACT IDENT COLUMN IF INTEGER SET ## -## Ends in an error in state: 138. +## Ends in an error in state: 139. ## ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] ## expression -> expression . LT GT expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] @@ -1673,7 +1672,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN IF INTEGER SET main: LOCATION_START EOL ACT IDENT COLUMN ACT STAR ## -## Ends in an error in state: 142. +## Ends in an error in state: 143. ## ## onliner(ACT) -> ACT . expression COLUMN final_inline_instruction [ EOL ELSE AMPERSAND ] ## @@ -1685,7 +1684,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN ACT STAR main: LOCATION_START EOL ACT IDENT COLUMN ACT INTEGER SET ## -## Ends in an error in state: 143. +## Ends in an error in state: 144. ## ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] ## expression -> expression . LT GT expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] @@ -1713,7 +1712,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN ACT INTEGER SET main: LOCATION_START EOL ACT IDENT COLUMN KEYWORD L_PAREN R_PAREN STAR ## -## Ends in an error in state: 146. +## Ends in an error in state: 147. ## ## inline_instruction -> inline_instruction single_instruction . nonempty_list(AMPERSAND) [ STAR SET PLUS OBJ NO MINUS L_PAREN LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION EOL ELSE COMMENT AMPERSAND ACT ] ## instruction -> single_instruction . [ EOL ELSE AMPERSAND ] @@ -1726,7 +1725,7 @@ main: LOCATION_START EOL ACT IDENT COLUMN KEYWORD L_PAREN R_PAREN STAR main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF STAR ## -## Ends in an error in state: 151. +## Ends in an error in state: 152. ## ## elif -> ELIF . expression COLUMN nonempty_list(EOL) list(line_statement) [ END ELSE ELIF ] ## @@ -1738,7 +1737,7 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF STAR main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF INTEGER SET ## -## Ends in an error in state: 152. +## Ends in an error in state: 153. ## ## elif -> ELIF expression . COLUMN nonempty_list(EOL) list(line_statement) [ END ELSE ELIF ] ## expression -> expression . EQUAL expression [ STAR PLUS OR MOD MINUS LT GT EXCLAMATION EQUAL DIV COLUMN AND ] @@ -1762,11 +1761,11 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF INTEGER SET ## ELIF expression ## - +The `ELIF` expression does not end properly. A `:` is expected before any instruction. main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF IDENT COLUMN STAR ## -## Ends in an error in state: 153. +## Ends in an error in state: 154. ## ## elif -> ELIF expression COLUMN . nonempty_list(EOL) list(line_statement) [ END ELSE ELIF ] ## @@ -1778,7 +1777,7 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF IDENT COLUMN STAR main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF IDENT COLUMN EOL LOCATION_END ## -## Ends in an error in state: 154. +## Ends in an error in state: 155. ## ## elif -> ELIF expression COLUMN nonempty_list(EOL) . list(line_statement) [ END ELSE ELIF ] ## @@ -1796,7 +1795,7 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF IDENT COLUMN EOL LOCATION_END main: LOCATION_START EOL IF IDENT COLUMN EOL ELSE STAR ## -## Ends in an error in state: 157. +## Ends in an error in state: 158. ## ## else_ -> ELSE . nonempty_list(EOL) list(line_statement) [ END ] ## @@ -1808,7 +1807,7 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL ELSE STAR main: LOCATION_START EOL IF IDENT COLUMN EOL ELSE EOL IDENT AMPERSAND LOCATION_END ## -## Ends in an error in state: 161. +## Ends in an error in state: 162. ## ## line_statement -> IF expression COLUMN nonempty_list(EOL) list(line_statement) elif_else_body . END option(IF) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> IF expression COLUMN nonempty_list(EOL) list(line_statement) elif_else_body . END option(IF) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1820,20 +1819,20 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL ELSE EOL IDENT AMPERSAND LOCATION_E ## This implies that, although the LR(1) items shown above provide an ## accurate view of the past (what has been recognized so far), they ## may provide an INCOMPLETE view of the future (what was expected next). -## In state 121, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND -## In state 130, spurious reduction of production list(EOL) -> -## In state 131, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) -## In state 126, spurious reduction of production list(line_statement) -> -## In state 127, spurious reduction of production list(line_statement) -> line_statement list(line_statement) -## In state 159, spurious reduction of production else_ -> ELSE nonempty_list(EOL) list(line_statement) -## In state 160, spurious reduction of production elif_else_body -> list(elif) else_ +## In state 122, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND +## In state 131, spurious reduction of production list(EOL) -> +## In state 132, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) +## In state 127, spurious reduction of production list(line_statement) -> +## In state 128, spurious reduction of production list(line_statement) -> line_statement list(line_statement) +## In state 160, spurious reduction of production else_ -> ELSE nonempty_list(EOL) list(line_statement) +## In state 161, spurious reduction of production elif_else_body -> list(elif) else_ ## main: LOCATION_START EOL IF IDENT COLUMN EOL END STAR ## -## Ends in an error in state: 162. +## Ends in an error in state: 163. ## ## line_statement -> IF expression COLUMN nonempty_list(EOL) list(line_statement) elif_else_body END . option(IF) nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> IF expression COLUMN nonempty_list(EOL) list(line_statement) elif_else_body END . option(IF) nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1846,7 +1845,7 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL END STAR main: LOCATION_START EOL IF IDENT COLUMN EOL END IF STAR ## -## Ends in an error in state: 164. +## Ends in an error in state: 165. ## ## line_statement -> IF expression COLUMN nonempty_list(EOL) list(line_statement) elif_else_body END option(IF) . nonempty_list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] ## line_statement -> IF expression COLUMN nonempty_list(EOL) list(line_statement) elif_else_body END option(IF) . nonempty_list(AMPERSAND) list(EOL) [ STAR SET PLUS OBJ NO MINUS L_PAREN LOCATION_END LITERAL LET KEYWORD INTEGER IF IDENT FUNCTION END ELSE ELIF COMMENT COLUMN ACT ] @@ -1859,7 +1858,7 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL END IF STAR main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF IDENT COLUMN EOL IDENT AMPERSAND LOCATION_END ## -## Ends in an error in state: 168. +## Ends in an error in state: 169. ## ## list(elif) -> elif . list(elif) [ END ELSE ] ## @@ -1870,19 +1869,19 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL ELIF IDENT COLUMN EOL IDENT AMPERSA ## This implies that, although the LR(1) items shown above provide an ## accurate view of the past (what has been recognized so far), they ## may provide an INCOMPLETE view of the future (what was expected next). -## In state 121, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND -## In state 130, spurious reduction of production list(EOL) -> -## In state 131, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) -## In state 126, spurious reduction of production list(line_statement) -> -## In state 127, spurious reduction of production list(line_statement) -> line_statement list(line_statement) -## In state 155, spurious reduction of production elif -> ELIF expression COLUMN nonempty_list(EOL) list(line_statement) +## In state 122, spurious reduction of production nonempty_list(AMPERSAND) -> AMPERSAND +## In state 131, spurious reduction of production list(EOL) -> +## In state 132, spurious reduction of production line_statement -> instruction nonempty_list(AMPERSAND) list(EOL) +## In state 127, spurious reduction of production list(line_statement) -> +## In state 128, spurious reduction of production list(line_statement) -> line_statement list(line_statement) +## In state 156, spurious reduction of production elif -> ELIF expression COLUMN nonempty_list(EOL) list(line_statement) ## - +Unclosed `ELIF` block. main: LOCATION_START EOL LOCATION_END STAR ## -## Ends in an error in state: 171. +## Ends in an error in state: 172. ## ## main -> list(EOL) LOCATION_START nonempty_list(EOL) list(line_statement) LOCATION_END . list(EOL) EOF [ # ] ## @@ -1894,7 +1893,7 @@ main: LOCATION_START EOL LOCATION_END STAR main: LOCATION_START EOL LOCATION_END EOL STAR ## -## Ends in an error in state: 172. +## Ends in an error in state: 173. ## ## main -> list(EOL) LOCATION_START nonempty_list(EOL) list(line_statement) LOCATION_END list(EOL) . EOF [ # ] ## diff --git a/lib/interpreter.ml b/lib/interpreter.ml index 346ceb5..7fc0413 100644 --- a/lib/interpreter.ml +++ b/lib/interpreter.ml @@ -5,7 +5,7 @@ Refer to the menhir manual in order to see the values. - The interresting function here is [of_lexer] which return the error code in + The interresting function here is [of_lexbuf] which return the error code in case of invalid syntax. *) @@ -17,7 +17,6 @@ struct code : error_code; start_pos : Lexing.position; end_pos : Lexing.position; - } module E = MenhirLib.ErrorReports @@ -31,6 +30,8 @@ struct let get_parse_error lexbuf env : error = match MI.stack env with | (lazy Nil) -> + (* The parser is in its initial state. We should not get an + error here *) let positions = Sedlexing.lexing_positions lexbuf in range_message positions InvalidSyntax | (lazy (Cons (MI.Element (state, _, start_pos, end_pos), _))) -> diff --git a/lib/lexer.ml b/lib/lexer.ml new file mode 100644 index 0000000..324171f --- /dev/null +++ b/lib/lexer.ml @@ -0,0 +1,211 @@ +(** + Lexer using sedlex + *) + +open Tokens + +exception UnclosedQuote of { content : string; line : int } +exception LexError of Lexing.position * string + +let pp_pos out { Lexing.pos_lnum; pos_cnum; pos_bol; _ } = + Format.fprintf out "line %d:%d" pos_lnum (pos_cnum - pos_bol) + +module type Encoding = sig + val lexeme : Sedlexing.lexbuf -> string +end + +(* The comment system is terrible. The same symbol can be used for : + - starting a comment + - inequality operation + In order to manage this, I try to identify the context in a very basic way, + using a flag True False for determining the token to send. +*) +module Bucket = Ephemeron.K1.Bucket + +type bucket = (Sedlexing.lexbuf, int) Bucket.t + +let is_expression : bucket = Bucket.make () + +let incr_level lexbuf = + match Bucket.find is_expression lexbuf with + | None -> Bucket.add is_expression lexbuf 1 + | Some v -> Bucket.add is_expression lexbuf (v + 1) + +let decr_level lexbuf = + match Bucket.find is_expression lexbuf with + | None -> () + | Some v -> + if v > 1 then Bucket.add is_expression lexbuf (v - 1) + else Bucket.remove is_expression lexbuf + +let build_ident lexbuf = + let id = + Sedlexing.lexeme lexbuf |> Idents.of_uchars |> String.uppercase_ascii + in + try + let value = Hashtbl.find Idents.keyword_table id in + let _ = match value with IF | ELIF -> incr_level lexbuf | _ -> () in + value + with Not_found -> IDENT id + +let incr_level lexbuf = + match Bucket.find is_expression lexbuf with + | None -> Bucket.add is_expression lexbuf 1 + | Some v -> Bucket.add is_expression lexbuf (v + 1) + +let wait_balance rule lexbuf = + try[@warning "-52"] rule (Buffer.create 17) lexbuf + with Failure "lexing: empty token" -> + let position, _ = Sedlexing.lexing_positions lexbuf in + let line = position.Lexing.pos_lnum + and content = Sedlexing.lexeme lexbuf |> Idents.of_uchars in + (raise (UnclosedQuote { line; content }) [@warning "+52"]) + +let space = [%sedlex.regexp? ' ' | '\t'] +let eol = [%sedlex.regexp? '\r' | '\n' | "\r\n"] +let coma = [%sedlex.regexp? ','] +let digit = [%sedlex.regexp? '0' .. '9'] +let letters = [%sedlex.regexp? 'a' .. 'z' | 'A' .. 'Z' | '_'] +let spaces = [%sedlex.regexp? Plus space] +let ident = [%sedlex.regexp? ('$' | letters), Star (digit | letters)] +let location_ident = [%sedlex.regexp? letters | digit] +let location_prefix = [%sedlex.regexp? '!' | '$' | '#' | '^'] +let location = [%sedlex.regexp? Opt location_prefix, Plus location_ident] + +let rec read_long_string level buf lexbuf = + match%sedlex lexbuf with + | '{' -> + Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); + read_long_string (level + 1) buf lexbuf + | '}' -> ( + match level with + | 0 -> Buffer.contents buf + | _ -> + Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); + read_long_string (level - 1) buf lexbuf) + | eol -> + Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); + read_long_string level buf lexbuf + | any -> + Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); + read_long_string level buf lexbuf + | _ -> raise Not_found + +let rec read_dquoted_string buf lexbuf = + match%sedlex lexbuf with + | "\"\"" -> + Buffer.add_char buf '"'; + read_dquoted_string buf lexbuf + | '"' -> Buffer.contents buf + | any -> + Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); + read_dquoted_string buf lexbuf + | _ -> raise Not_found + +let rec read_quoted_string buf lexbuf = + match%sedlex lexbuf with + | "''" -> + Buffer.add_char buf '\''; + read_quoted_string buf lexbuf + | '\'' -> Buffer.contents buf + | eol -> + Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); + read_quoted_string buf lexbuf + | any -> + Buffer.add_string buf (Sedlexing.Utf8.lexeme lexbuf); + read_quoted_string buf lexbuf + | _ -> raise Not_found + +let rec skip_comment lexbuf = + match%sedlex lexbuf with + | '{' -> + let _ = wait_balance (read_long_string 0) lexbuf in + skip_comment lexbuf + | '\'' -> + let _ = wait_balance read_quoted_string lexbuf in + skip_comment lexbuf + | '"' -> + let _ = wait_balance read_dquoted_string lexbuf in + skip_comment lexbuf + | eol -> + (* Ugly hack used in order to put the eol in the front of the next + parsing. *) + Sedlexing.rollback lexbuf; + COMMENT + | any -> skip_comment lexbuf + | _ -> raise Not_found + +(** Main lexer *) +let rec token : (module Encoding.S) -> Sedlexing.lexbuf -> token = + fun (module E : Encoding) lexbuf -> + match%sedlex lexbuf with + | 0Xfeff -> + (* Ignore the BOM *) + token (module E) lexbuf + | '#', Star space, location -> + let ident = E.lexeme lexbuf in + + LOCATION_START ident + | Plus digit -> INTEGER (E.lexeme lexbuf) + | '+' -> PLUS + | '-' -> MINUS + | "+=" -> INCR + | "-=" -> DECR + | "*=" -> MULT_EQUAL + | '/' -> DIV + | '*' -> STAR + | ':' -> + (* We are leaving the block, the comment will be handled again *) + decr_level lexbuf; + COLUMN + | '-', Plus '-', Star (Sub (any, ('\r' | '\n'))) -> LOCATION_END + | '[' -> L_BRACKET + | ']' -> R_BRACKET + | '(' -> + incr_level lexbuf; + L_PAREN + | ')' -> + decr_level lexbuf; + R_PAREN + | '<' -> LT + | '>' -> GT + | coma -> COMA + | eof -> + Bucket.remove is_expression lexbuf; + EOF + | '=' -> + incr_level lexbuf; + EQUAL + | ident -> build_ident lexbuf + | eol -> + Bucket.add is_expression lexbuf 0; + EOL + | '&' -> + Bucket.add is_expression lexbuf 0; + AMPERSAND + | '!' -> ( + match Bucket.find is_expression lexbuf with + | Some i when i <> 0 -> EXCLAMATION + | _ -> skip_comment lexbuf) + | spaces -> token (module E) lexbuf + | '\'' -> LITERAL (wait_balance read_quoted_string lexbuf) + | '"' -> LITERAL (wait_balance read_dquoted_string lexbuf) + | '{' -> LITERAL (wait_balance (read_long_string 0) lexbuf) + | _ -> + let position = fst @@ Sedlexing.lexing_positions lexbuf in + let tok = E.lexeme lexbuf in + + let msg = + Format.asprintf "Unexpected character %S at %a" tok pp_pos position + in + + raise @@ LexError (position, msg) + +(** Tokenizer for menhir *) +let lexer : + (module Encoding) -> + Sedlexing.lexbuf -> + unit -> + token * Lexing.position * Lexing.position = + fun (module E : Encoding.S) lexbuf -> + Sedlexing.with_tokenizer (token (module E)) lexbuf diff --git a/lib/lexer.mli b/lib/lexer.mli new file mode 100644 index 0000000..41c7c11 --- /dev/null +++ b/lib/lexer.mli @@ -0,0 +1,10 @@ +module type Encoding = sig + val lexeme : Sedlexing.lexbuf -> string +end + +val lexer : + (module Encoding) -> + Sedlexing.lexbuf -> + unit -> + Tokens.token * Lexing.position * Lexing.position +(** Apply the lexer to the source *) -- cgit v1.2.3