2014-11-27 4 views
5

Ich benutze ocamllex, um einen Lexer für eine Skriptsprache zu schreiben, aber ich habe einen Konflikt mit meiner Regel für Kommentare.Ist es in ocamllex möglich, eine Regel zu definieren, die auf das nächste Zeichen schaut, ohne es zu verbrauchen?

Ich möchte, dass meine Befehlsargumente nicht in Anführungszeichen gesetzt werden, solange sie nur alphanumerische Zeichen und Schrägstriche "/" enthalten. Zum Beispiel:

echo "quoted argument [email protected]#%" /this/second/argument/is/unquoted 

Zusätzlich einer meiner Voraussetzungen bietet C++ Stil Kommentare mit "//"

//this is a comment 
echo hello world 

Das Problem ist dies Dinge wie

echo foo//comment 

bringt Ich möchte Mein Lexer, um ein "foo" -Token zu produzieren, während auch das "//" unberührt bleibt, um in der nächsten Zeit verbraucht zu werden, frage ich den Lexer nach Token. Ist das möglich? Der Grund dafür ist, dass es möglich ist, dass der Eingabepuffer das Ende des Kommentars noch nicht erreicht hat und ich lieber sofort das "foo" -Token zurückgeben würde, als unnötigerweise zu blockieren, den Kommentar eifrig zu konsumieren.

+0

Wenn Ihr Parser eine Regel hat, die nur 'echo foo' konsumiert, sollte das nicht ausreichen, um das Kommentieren von Kommentaren zu verschieben? – didierc

+0

Auf Lexer-Ebene müssen Sie nur sicherstellen, dass Ihre nicht-quoted Params doppelte Schrägstriche enthalten können, andernfalls müssten Sie die Fälle unterscheiden, wo es passieren könnte, und vielleicht zwei Sätze von Regeln für – didierc

+0

Sie haben oder nicht sollte wahrscheinlich ein kleines Programm zur Verfügung stellen, das das Problem zeigt, so dass wir sehen können, wie man es beheben kann. – didierc

Antwort

5

Hier finden Sie eine kleine Lexer, die nur echo passt, notierte und nicht notierte Strings, Kommentare und druckt die resultierende Token:

{ 
    type token = NEWLINE | ECHO | QUOTED of string | UNQUOTED of string | COMMENT of string 
    exception Eof 

    type state = CODE | LINE_COMMENT 
    let state = ref CODE 
} 

let newline  = '\n' 
let alphanum  = [ 'A'-'Z' 'a'-'z' '0'-'9' '_' ] 
let comment_line = "//"([^ '\n' ]+) 
let space  = [ ' ' '\t' ] 
let quoted  = '"'([^ '"' ]+)'"' 
let unquoted  = ('/'?(alphanum+'/'?)+) 

rule code = parse 
    space+      { code lexbuf } 
| newline      { code lexbuf } 
| "echo"      { ECHO } 
| quoted      { QUOTED (Lexing.lexeme lexbuf) } 
| "//"      { line_comment "" lexbuf } 
| ('/'|alphanum+)    { unquoted (Lexing.lexeme lexbuf) lexbuf } 
| eof       { raise Eof } 

and unquoted buff = parse 
    newline      { UNQUOTED buff } 
| "//"      { state := LINE_COMMENT; if buff = "" then line_comment "" lexbuf else UNQUOTED buff } 
| ('/'|alphanum+)    { unquoted (buff^Lexing.lexeme lexbuf) lexbuf } 
| space+      { UNQUOTED buff } 
| eof       { raise Eof } 

and line_comment buff = parse 
    newline      { state := CODE; COMMENT buff } 
| _       { line_comment (buff^Lexing.lexeme lexbuf) lexbuf } 

{ 

    let lexer lb = 
    match !state with 
     CODE -> code lb 
    | LINE_COMMENT -> line_comment "" lb 

    let _ = 
    try 
     let lexbuf = Lexing.from_channel stdin in 
     while true do 
     let() = 
      match lexer lexbuf with 
      ECHO -> Printf.printf "ECHO\n" 
      | QUOTED s -> Printf.printf "QUOTED(%s)\n" s 
      | UNQUOTED s -> Printf.printf "UNQUOTED(%s)\n" s 
      | COMMENT s -> Printf.printf "COMMENT(%s)\n" s 
      | NEWLINE -> Printf.printf "\n" 
     in flush stdout 
     done 
    with Eof -> exit 0 

} 

Es ist ein Trick, den ich in einem Projekt von mir verwendet, zu überwinden die gleiche Einschränkung in ocamllex (im Vergleich zu dem ursprünglichen Programm C lex, das Muster in "Look-Ahead-Modus" übereinstimmen lässt). Im Grunde spaltet sie die mehrdeutigen Regeln in ihren verschiedenen Radikalen auf und schaltet den Lexer entsprechend auf einen anderen Parser um. Es verfolgt auch den aktuell verwendeten Parser und den nächsten Einstiegspunkt.

In Ihrer Situation müssen nur die Standardzustände (CODE) und der Kommentarmodus (LINE_COMMENT) protokolliert werden. Dies könnte erweitert werden, um bei Bedarf weitere Staaten zu unterstützen.

+1

Das Problem mit dieser Version besteht darin, dass alle Schrägstriche innerhalb eines "unquoted" muct von einem alphanum gefolgt werden. Dies schließt Tokens aus, die mit einem Schrägstrich enden, wie "foo /".Wie du bereits bemerkt hast, musst du aufgrund der Mehrdeutigkeit in der Grammatik ("foo // comment" kann als "foo /" + "/ comment" oder "foo" + "// comment" analysiert werden) immer vorausschauen "/" um zu entscheiden, ob sein Teil von einem "//" ist oder nicht, und um zu entscheiden, wie es zu entschlüsseln ist. – hugomg

+1

Diese Grammatik schließt auch Tokens aus, die mit einem Schrägstrich beginnen. – hugomg

+0

Ich denke, es sollte diesmal funktionieren. – didierc

Verwandte Themen