Je viens de terminer l'écriture d'un analyseur de date pour mon implémentation ECMAScript. Auparavant, j'avais écrit un compilateur d'expressions régulières et j'étais vraiment impressionné par la façon dont la spécification décrivait le processus. Essentiellement, l'entrée est passée à travers une série de suites qui testent chaque partie de la chaîne. Mon analyseur de date est vaguement basé sur l'idée et je veux vraiment savoir comment il s'appelle.Comment s'appelle cette technique?
Remarque: J'ai seulement quitté le noyau de l'analyseur pour réduire le bruit.
public sealed class DateParser
{
public double Parse()
{
using (var tokens = Tokenize().GetEnumerator())
{
var previous = new Result(ResultType.Success, HandleFirst);
var next = default(Result);
while (true)
{
if (!tokens.MoveNext())
{
return previous.Type == ResultType.Optional ? Complete() : double.NaN;
}
next = previous.Continuation(tokens.Current);
if (next.Type == ResultType.Complete)
{
return Complete();
}
else if (next.Type == ResultType.MustFail)
{
return double.NaN;
}
else if (next.Type == ResultType.CanFail)
{
return previous.Type == ResultType.Optional ? Complete() : double.NaN;
}
previous = next;
}
}
}
private Result HandleFirst(DateToken token)
{
switch (token.Type)
{
case DateTokenType.Integer:
return HandleYear(token);
case DateTokenType.T:
return HandleT(token);
default:
return new Result(ResultType.MustFail, null);
}
}
private Result HandleYear(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 4)
{
_year = double.Parse(token.Value);
return new Result(ResultType.Optional, HandleMonthHyphen);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleMonthHyphen(DateToken token)
{
if (token.Type == DateTokenType.Hyphen)
{
return new Result(ResultType.Success, HandleMonth);
}
return new Result(ResultType.Complete, null);
}
private Result HandleMonth(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 2)
{
_month = double.Parse(token.Value);
if (_month < 1 || _month > 12)
{
_month = null;
return new Result(ResultType.MustFail, null);
}
return new Result(ResultType.Optional, HandleDayHyphen);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleDayHyphen(DateToken token)
{
if (token.Type == DateTokenType.Hyphen)
{
return new Result(ResultType.Success, HandleDay);
}
return new Result(ResultType.CanFail, null);
}
private Result HandleDay(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 2)
{
_day = double.Parse(token.Value);
if (_day < 1 || _day > 31)
{
_day = null;
return new Result(ResultType.MustFail, null);
}
return new Result(ResultType.Optional, HandleT);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleT(DateToken token)
{
if (token.Type == DateTokenType.T)
{
return new Result(ResultType.Success, HandleHour);
}
return new Result(ResultType.CanFail, null);
}
private Result HandleHour(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 2)
{
_hour = double.Parse(token.Value);
if (_hour >= DatePrototype.HoursPerDay)
{
_hour = null;
return new Result(ResultType.MustFail, null);
}
return new Result(ResultType.Success, HandleHourColon);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleHourColon(DateToken token)
{
if (token.Type == DateTokenType.Colon)
{
return new Result(ResultType.Success, HandleMinute);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleMinute(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 2)
{
_minute = double.Parse(token.Value);
if (_minute >= DatePrototype.MinutesPerHour)
{
_minute = null;
return new Result(ResultType.MustFail, null);
}
return new Result(ResultType.Optional, HandleSecondColonOrOffset);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleSecondColonOrOffset(DateToken token)
{
if (token.Type == DateTokenType.Colon)
{
return new Result(ResultType.Success, HandleSecond);
}
else
{
var result = HandleOffset(token);
if (result.Type == ResultType.CanFail)
{
return new Result(ResultType.MustFail, null);
}
return result;
}
}
private Result HandleSecond(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 2)
{
_second = double.Parse(token.Value);
if (_second >= DatePrototype.SecondsPerMinute)
{
_second = null;
return new Result(ResultType.MustFail, null);
}
return new Result(ResultType.Optional, HandleSecondDotOrOffset);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleSecondDotOrOffset(DateToken token)
{
if (token.Type == DateTokenType.Dot)
{
return new Result(ResultType.Success, HandleMillisecond);
}
else
{
var result = HandleOffset(token);
if (result.Type == ResultType.CanFail)
{
return new Result(ResultType.MustFail, null);
}
return result;
}
}
private Result HandleMillisecond(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 3)
{
_millisecond = double.Parse(token.Value);
if (_millisecond >= DatePrototype.MsPerMinute)
{
_millisecond = null;
return new Result(ResultType.MustFail, null);
}
return new Result(ResultType.Optional, HandleOffset);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleOffset(DateToken token)
{
switch (token.Type)
{
case DateTokenType.Z:
_offset = 0.0;
return new Result(ResultType.Success, null);
case DateTokenType.Plus:
_offset = 0.0;
return new Result(ResultType.Success, HandleOffsetHour);
case DateTokenType.Hyphen:
_offset = -0.0;
return new Result(ResultType.Success, HandleOffsetHour);
default:
return new Result(ResultType.CanFail, null);
}
}
private Result HandleOffsetHour(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 2)
{
_offset += double.Parse(token.Value) * DatePrototype.MsPerHour;
return new Result(ResultType.Success, HandleOffsetHourColon);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleOffsetHourColon(DateToken token)
{
if (token.Type == DateTokenType.Colon)
{
return new Result(ResultType.Success, HandleOffsetMinute);
}
return new Result(ResultType.MustFail, null);
}
private Result HandleOffsetMinute(DateToken token)
{
if (token.Type == DateTokenType.Integer && token.Value.Length == 2)
{
_offset += double.Parse(token.Value) * DatePrototype.MsPerMinute;
return new Result(ResultType.Complete, null);
}
return new Result(ResultType.MustFail, null);
}
}
Est-ce un terme général pour le design? Pourrait-il y avoir un terme plus précis que je pourrais utiliser pour guider ma recherche? – ChaosPandion
Oui. Et pourquoi ne pas commencer votre recherche à partir de l'article wikipedia, ou par toute autre stratégie que vous pouvez penser à partir du terme fourni. –
Je vais le faire. L'un des plus grands inconvénients de ne pas avoir d'éducation formelle en informatique est de ne pas connaître le jargon ... Oh et ce putain de papier. :) – ChaosPandion