Метод main () требуется в публичном классе.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
public static int sum(int num1, int num2, int num3)
{
int total;
total = num1 + num2 + num3;
return total;
}
public static void Main(string[] args)
{
Console.Write("\n\nFunction to calculate the sum of two numbers :\n");
Console.Write("--------------------------------------------------\n");
Console.Write("Enter a number1: ");
int n1 = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter a number2: ");
int n2 = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter a number3: ");
int n3 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("\nThe sum of three numbers is : {0} \n", sum(n1, n2, n3));
}
}
}
Проверьте здесь: https://dotnetfiddle.net/p9E9Rw
Вот демонстрационный лексический анализатор, который должен быть довольно эффективным, но он предполагает, что все исходные данные находятся в единственной строке. Переделка его для обработки буферов умеренно хитра из-за очень длинных маркеров.
type
TLexer = class
private
FData: string;
FTokenStart: PChar;
FCurrPos: PChar;
function GetCurrentToken: string;
public
constructor Create(const AData: string);
function GetNextToken: Boolean;
property CurrentToken: string read GetCurrentToken;
end;
{ TLexer }
constructor TLexer.Create(const AData: string);
begin
FData := AData;
FCurrPos := PChar(FData);
end;
function TLexer.GetCurrentToken: string;
begin
SetString(Result, FTokenStart, FCurrPos - FTokenStart);
end;
function TLexer.GetNextToken: Boolean;
var
cp: PChar;
begin
cp := FCurrPos; // copy to local to permit register allocation
// skip whitespace; this test could be converted to an unsigned int
// subtraction and compare for only a single branch
while (cp^ > #0) and (cp^ <= #32) do
Inc(cp);
// using null terminater for end of file
Result := cp^ <> #0;
if Result then
begin
FTokenStart := cp;
Inc(cp);
while cp^ > #32 do
Inc(cp);
end;
FCurrPos := cp;
end;
Вот хромая реализация задницы очень простого лексического анализатора. Это могло бы дать Вам общее представление.
Отметьте ограничения этого примера - никакая включенная буферизация, никакой Unicode (это - выборка из проекта Delphi 7). Вам, вероятно, были бы нужны те, которые в серьезной реализации.
{ Implements a simpe lexer class. }
unit Simplelexer;
interface
uses Classes, Sysutils, Types, dialogs;
type
ESimpleLexerFinished = class(Exception) end;
TProcTableProc = procedure of object;
// A very simple lexer that can handle numbers, words, symbols - no comment handling
TSimpleLexer = class(TObject)
private
FLineNo: Integer;
Run: Integer;
fOffset: Integer;
fRunOffset: Integer; // helper for fOffset
fTokenPos: Integer;
pSource: PChar;
fProcTable: array[#0..#255] of TProcTableProc;
fUseSimpleStrings: Boolean;
fIgnoreSpaces: Boolean;
procedure MakeMethodTables;
procedure IdentProc;
procedure NewLineProc;
procedure NullProc;
procedure NumberProc;
procedure SpaceProc;
procedure SymbolProc;
procedure UnknownProc;
public
constructor Create;
destructor Destroy; override;
procedure Feed(const S: string);
procedure Next;
function GetToken: string;
function GetLineNo: Integer;
function GetOffset: Integer;
property IgnoreSpaces: boolean read fIgnoreSpaces write fIgnoreSpaces;
property UseSimpleStrings: boolean read fUseSimpleStrings write fUseSimpleStrings;
end;
implementation
{ TSimpleLexer }
constructor TSimpleLexer.Create;
begin
makeMethodTables;
fUseSimpleStrings := false;
fIgnoreSpaces := false;
end;
destructor TSimpleLexer.Destroy;
begin
inherited;
end;
procedure TSimpleLexer.Feed(const S: string);
begin
Run := 0;
FLineNo := 1;
FOffset := 1;
pSource := PChar(S);
end;
procedure TSimpleLexer.Next;
begin
fTokenPos := Run;
foffset := Run - frunOffset + 1;
fProcTable[pSource[Run]];
end;
function TSimpleLexer.GetToken: string;
begin
SetString(Result, (pSource + fTokenPos), Run - fTokenPos);
end;
function TSimpleLexer.GetLineNo: Integer;
begin
Result := FLineNo;
end;
function TSimpleLexer.GetOffset: Integer;
begin
Result := foffset;
end;
procedure TSimpleLexer.MakeMethodTables;
var
I: Char;
begin
for I := #0 to #255 do
case I of
'@', '&', '}', '{', ':', ',', ']', '[', '*',
'^', ')', '(', ';', '/', '=', '-', '+', '#', '>', '<', '$',
'.', '"', #39:
fProcTable[I] := SymbolProc;
#13, #10: fProcTable[I] := NewLineProc;
'A'..'Z', 'a'..'z', '_': fProcTable[I] := IdentProc;
#0: fProcTable[I] := NullProc;
'0'..'9': fProcTable[I] := NumberProc;
#1..#9, #11, #12, #14..#32: fProcTable[I] := SpaceProc;
else
fProcTable[I] := UnknownProc;
end;
end;
procedure TSimpleLexer.UnknownProc;
begin
inc(run);
end;
procedure TSimpleLexer.SymbolProc;
begin
if fUseSimpleStrings then
begin
if pSource[run] = '"' then
begin
Inc(run);
while pSource[run] <> '"' do
begin
Inc(run);
if pSource[run] = #0 then
begin
NullProc;
end;
end;
end;
Inc(run);
end
else
inc(run);
end;
procedure TSimpleLexer.IdentProc;
begin
while pSource[Run] in ['_', 'A'..'Z', 'a'..'z', '0'..'9'] do
Inc(run);
end;
procedure TSimpleLexer.NumberProc;
begin
while pSource[run] in ['0'..'9'] do
inc(run);
end;
procedure TSimpleLexer.SpaceProc;
begin
while pSource[run] in [#1..#9, #11, #12, #14..#32] do
inc(run);
if fIgnoreSpaces then Next;
end;
procedure TSimpleLexer.NewLineProc;
begin
inc(FLineNo);
inc(run);
case pSource[run - 1] of
#13:
if pSource[run] = #10 then inc(run);
end;
foffset := 1;
fRunOffset := run;
end;
procedure TSimpleLexer.NullProc;
begin
raise ESimpleLexerFinished.Create('');
end;
end.
Я сделал лексический анализатор на основе механизма состояния (DFA). Это работает с таблицей и довольно быстро. Но существуют возможные более быстрые опции.
Это также зависит от языка. Простой язык может возможно иметь умный алгоритм.
Таблица является массивом записей каждый содержащий 2 символа и 1 целое число. Для каждого маркера лексический анализатор идет через таблицу, запускающуюся в положении 0:
state := 0;
result := tkNoToken;
while (result = tkNoToken) do begin
if table[state].c1 > table[state].c2 then
result := table[state].value
else if (table[state].c1 <= c) and (c <= table[state].c2) then begin
c := GetNextChar();
state := table[state].value;
end else
Inc(state);
end;
Это просто и работает как очарование.
Если скорость является существенной, пользовательский код является ответом. Проверьте Windows API, который отобразит Ваш файл в память. Можно затем просто использовать указатель на следующий символ, чтобы сделать маркеры, идущие через как требуется.
Это - мой код для того, чтобы сделать отображение:
procedure TMyReader.InitialiseMapping(szFilename : string);
var
// nError : DWORD;
bGood : boolean;
begin
bGood := False;
m_hFile := CreateFile(PChar(szFilename), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
if m_hFile <> INVALID_HANDLE_VALUE then
begin
m_hMap := CreateFileMapping(m_hFile, nil, PAGE_READONLY, 0, 0, nil);
if m_hMap <> 0 then
begin
m_pMemory := MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, 0);
if m_pMemory <> nil then
begin
htlArray := Pointer(Integer(m_pMemory) + m_dwDataPosition);
bGood := True;
end
else
begin
// nError := GetLastError;
end;
end;
end;
if not bGood then
raise Exception.Create('Unable to map token file into memory');
end;
Я думаю, что самое большое узкое место всегда будет получением файла в память. После того как у Вас есть он в памяти (очевидно, не все это сразу, но я работал бы с буферами на вашем месте), фактический парсинг должен быть незначительным.
Скорость всегда будет относительно того, что Вы делаете, после того как она анализируется. Лексический синтаксический анализатор безусловно является самым быстрым методом преобразования в маркеры от текстового потока независимо от размера. TParser в единице классов является великолепным местом для запуска.
Лично ее некоторое время, так как я должен был записать синтаксический анализатор, но другой более датированный все же испытанный и истинный метод должен будет использовать LEX/YACC для создания грамматики затем, имеют его, преобразовывают грамматику в код, который можно использовать для выполнения обработки. DYacc является версией Delphi... не уверенной, если он все еще компилирует или нет, но стоящий взгляда, если Вы хотите сделать вещи старая школа. Книга дракона здесь имела бы большую справку, если можно найти копию.
Это вызывает другой вопрос - Как большой? Дайте нам ключ к разгадке как # строк или # или Мбит (Гбит)? Затем мы будем знать, умещается ли это в памяти, должно быть находящимся на диске и т.д.
При первичной обработке я использовал бы свой WordList (S: Строка; AList: TStringlist);
затем можно получить доступ к каждому маркеру как к Alist[n]... или отсортировать их или что бы то ни было.
Самый быстрый способ написать код состоял бы в том, чтобы, вероятно, создать TStringList и присвоить каждую строку в Вашем текстовом файле к свойству CommaText. По умолчанию пробел является разделителем, таким образом, Вы получите один объект StringList на маркер.
MyStringList.CommaText := s;
for i := 0 to MyStringList.Count - 1 do
begin
// process each token here
end;
Вы, вероятно, получите лучшую производительность путем парсинга каждой строки сами, все же.
Прокрутка Ваше собственное является самым быстрым путем наверняка. Для больше по этой теме, Вы видели исходный код Synedit, который содержит лексические анализаторы (названный маркерами в контексте проекта) приблизительно для любого языка на рынке. Я предлагаю, чтобы Вы взяли один из тех лексических анализаторов как основа и изменили для Вашего собственного использования.