Einzelnen Beitrag anzeigen

Peter666

Registriert seit: 11. Aug 2007
357 Beiträge
 
#10

AW: Einfachen Parser generieren

  Alt 9. Okt 2011, 11:28
Ich schreib mal den derzeitigen "Ist"-Stand:

Eine der größeren Tabellen schaut wie folgt aus:

Code:
descriptor 129 ac3_audio_descriptor [
    sample_rate_code                3
    bsid                            5
    ; bit_rate_code                   6
    bit_rate_limit                  1
    bit_rate_code                   5
    surround_mode                   2
    bsmod                           3
    num_channels                    4
    full_svc                        1
    langcod                         8
    if [num_channels = 0] [
        langcod2                     8
    ]
    if [bsmod < 2] [
        mainid                      3
        reserved                    5   ones
    ]
    else [
        asvcflags                   8
    ]
    textlen                         7
    text_code                       1
    text                            textlen binary
    ; break serves no purpose here
    additional_info                 length  binary


    enum sample_rate_code [
        0   "48 kHz"
        1   "44.1 kHz"
        2   "32 kHz"
        3   "reserved"
        4   "48 or 44.1 kHz"
        5   "48 or 32 kHz"
        6   "44.1 or 32 kHz"
        7   "48 or 44.1 or 32 kHz"
    ]

    enum bit_rate_code [
        0   "32 kbps"
        1   "40 kbps"
        2   "48 kbps"
        3   "56 kbps"
        4   "64 kbps"
        5   "80 kbps"
        6   "96 kbps"
        7   "112 kbps"
        8   "128 kbps"
        9   "160 kbps"
        10  "192 kbps"
        11  "224 kbps"
        12  "256 kbps"
        13  "320 kbps"
        14  "384 kbps"
        15  "448 kbps"
        16  "512 kbps"
        17  "576 kbps"
        18  "640 kbps"
    ]

    enum num_channels [
        0   "1+1"
        1   "1/0"
        2   "2/0"
        3   "3/0"
        4   "2/1"
        5   "3/1"
        6   "2/2"
        7   "3/2"
        8   "1"
        9   "<=2"
        10  "<=3"
        11  "<=4"
        12  "<=5"
        13  "<=6"
        14  "reserved"
        15  "reserved"
    ]

    enum bsmod [
        0   "Main: Complete Main"
        1   "Main: Music and Effects"
        2   "Assoc: Visually Impaired"
        3   "Assoc: Hearing Impaired"
        4   "Assoc: Dialog"
        5   "Assoc: Commentary"
        6   "Assoc: Emergency"
        7   "Assoc: Voice Over or Main: Karaoke"
    ]

    enum surround_mode [
        0   "Not indicated"
        1   "NOT Dolby Surround encoded"
        2   "Dolby Surround encoded"
        3   "reserved"
    ]
]
Was ich bis jetzt habe ist eine einfachere Klasse die mir die Token liefert:
Code:
 TSource = class
  private
    FSource: string;
    FSourceSize: word;
    FSourceIndex: word;
    FSourceLine: word;
    FLineStart: word;
    FToken: string;
    procedure SkipBlanks;
    function DropChar: char;
    function NextChar: char;
    procedure ReadAlpha;
    procedure ReadNumber;

    function GetEOF: Boolean;
  public
    constructor Create(const AFileName: string);
    destructor Destroy; override;
    function NextToken: string;
    property EOF: Boolean read GetEOF;
  end;

...

procedure RemoveAllComments(List: TStringlist);
// Removes all unnecessary lines
var s: string;
  i, j: integer;
begin
  for i := List.count - 1 downto 0 do
  begin
    s := list[i];
    j := pos(';', s);
    if j > 0 then delete(s, j, length(s));
    s := trim(s);
    if s = '' then list.delete(i) else list[i] := s;
  end;
end;

constructor TSource.Create(const AFileName: string);
var list: TStringlist;
begin
  list := TStringlist.Create;
  try
    list.LoadFromFile(AFileName);
    RemoveAllComments(List);
    FSource := list.text;
  finally
    list.free;
  end;
  FSourceSize := length(Fsource);
  FSourceIndex := 1;
  FSourceLine := 1;
  FLineStart := 0;
end;

destructor TSource.Destroy;
begin
  inherited;
end;

function TSource.NextToken: string;
begin
  repeat
    SkipBlanks;
    FToken := DropChar;
    case UpCase(FToken[1]) of
      'A'..'Z', '_': ReadAlpha;
      '0'..'9': ReadNumber;
      '>': if NextChar = '=' then FToken := FToken + DropChar;
      '<': if NextChar = '>' then FToken := FToken + DropChar else begin
          if NextChar = '=' then begin
            FToken := FToken + DropChar;
            if NextChar = '>' then FToken := FToken + DropChar;
          end;
        end;
    end;
    result := FToken;
  until FToken <> '';
end;

procedure TSource.SkipBlanks;
var
  c: char;
begin
  while (FSourceIndex < FSourceSize) do
  begin
    c := FSource[FSourceIndex];
    if c = #13 then inc(FSourceLine);
    if c = #10 then FLineStart := FSourceIndex + 1;
    if c in [#9, #10, #13, ' '] then
      Inc(FSourceIndex)
    else
      exit;
  end;
end;

function TSource.DropChar: char;
begin
  result := NextChar;
  if result <> #0 then
  begin
    inc(FSourceIndex);
    if result = #13 then inc(FSourceLine);
    if result = #10 then FLineStart := FSourceIndex + 1;
  end;
end;

function TSource.NextChar: char;
begin
  if FSourceIndex < FSourceSize then
    result := FSource[FSourceIndex] else result := #0;

end;

procedure TSource.ReadAlpha;
var
  c: char;
begin
  c := NextChar;
  while UpCase(c) in ['A'..'Z', '_'] do begin
    FToken := FToken + c; inc(FSourceIndex);
    ReadNumber;
    c := NextChar;
  end;
end;

procedure TSource.ReadNumber;
var
  c: char;
begin
  c := NextChar;
  while UpCase(c) in ['0'..'9'] do begin
    FToken := FToken + c; inc(FSourceIndex);
    c := NextChar;
  end;
end;

function TSource.GetEOF: Boolean;
begin
  result := FSourceIndex >= FSourceSize;
end;
Schön schaut sicherlich anders aus, aber immerhin ist es leserlich
Jetzt fehlt eigentlich "nur" noch der wichtigste Code der mir einen Baum mit den Variablen inkl. der dazugehörigen Schleifen erstellt. So eine richtige Idee wie ich das wohl am besten erstelle hab ich allerdings nicht.
Mir schwebt eine Liste vor die sowas in der Art beinhaltet:
Code:
 TClassType=(cVar, cWhile,cIf, cElse);
 TScope=integer;

 TSymbol=class
  Name: String;
  ClassType: TClassType;
  ValueAsInteger: Integer;
  ValueAsString: String;
 end;
Wobei bei While If und Else der übernächste Eintrag mit dem aktuellen Symbol verglichen wird, wobei das Symbol dazwischen als Operator verwendet wird.

Vielleicht hat ja jemand eine einfachere Idee?

Peter

Peter
  Mit Zitat antworten Zitat