Вход в систему Scala

Хм ... Я не думаю, что вы можете написать для этого нисходящий парсер без возврата назад, так что это должен быть своего рода парсер с уменьшением сдвига. LR (1) или даже LALR, конечно, будут отлично работать со следующим (специальным) определением языка:

Start -> E1
E1 -> E1 + E1 | E1-E1
E1 -> E2 * E2 | E2 / E2 | E2
E2 -> число | (E1)

Разделение его на E1 и E2 необходимо для сохранения приоритета * и / над + и -.

Но вот как бы я это сделал, если бы мне пришлось писать синтаксический анализатор вручную:

  • Два стека, один хранит узлы дерева в качестве операндов, а другой хранит операторы
  • Читайте ввод слева направо, делайте листовые узлы чисел и помещайте их в стек операндов.
  • Если у вас есть> = 2 операнда в стеке, всплывают 2, объедините их с верхним оператором в стеке операторов и перенесите эту структуру обратно в дерево операндов, , если только
  • Следующий оператор имеет более высокий приоритет, чем тот, который в настоящее время находится на вершине стека.

Это оставляет нам проблему обработки скобок. Одним из элегантных (я думал) решений является сохранение приоритета каждого оператора в виде числа в переменной. Итак, изначально,

  • int plus, minus = 1;
  • int mul, div = 2;

Теперь каждый раз, когда вы видите увеличение левой скобки все эти переменные на 2, и каждый раз, когда вы видите правую скобку, уменьшайте все переменные на 2.

Это гарантирует, что + in 3 * (4 + 5) имеет более высокий приоритет, чем *, и 3 * 4 не будет помещен в стек. Вместо этого он будет ждать 5, нажмите 4 + 5, затем нажмите 3 * (4 + 5).

162
задан George 10 June 2009 в 21:28
поделиться

5 ответов

slf4j wrappers

Most of Scala's logging libraries have been some wrappers around a Java logging framework (slf4j, log4j etc), but as of March 2015, the surviving log libraries are all slf4j. These log libraries provide some sort of log object to which you can call info(...), debug(...), etc. I'm not a big fan of slf4j, but it now seems to be the predominant logging framework. Here's the description of SLF4J:

The Simple Logging Facade for Java or (SLF4J) serves as a simple facade or abstraction for various logging frameworks, e.g. java.util.logging, log4j and logback, allowing the end user to plug in the desired logging framework at deployment time.

The ability to change underlying log library at deployment time brings in unique characteristic to the entire slf4j family of loggers, which you need to be aware of:

  1. classpath as configuration approach. The way slf4j knows which underlying logging library you are using is by loading a class by some name. I've had issues in which slf4j not recognizing my logger when classloader was customized.
  2. Because the simple facade tries to be the common denominator, it's limited only to actual log calls. In other words, the configuration cannot be done via the code.

In a large project, it could actually be convenient to be able to control the logging behavior of transitive dependencies if everyone used slf4j.

Scala Logging

Scala Logging is written by Heiko Seeberger as a successor to his slf4s. It uses macro to expand calls into if expression to avoid potentially expensive log call.

Scala Logging is a convenient and performant logging library wrapping logging libraries like SLF4J and potentially others.

Historical loggers

  • Logula, a Log4J wrapper written by Coda Hale. Used to like this one, but now it's abandoned.
  • configgy, a java.util.logging wrapper that used to be popular in the earlier days of Scala. Now abandoned.
117
ответ дан 23 November 2019 в 21:22
поделиться

Использование slf4j и оболочки - это хорошо, но использование его встроенной интерполяции не работает, когда у вас есть более двух значений для интерполяции, с тех пор вам нужно создать массив значений для интерполяции.

Более похожее на Scala решение - использовать преобразователь или кластер для задержки конкатенации сообщения об ошибке. Хорошим примером этого является регистратор Lift

Log.scala Slf4jLog.scala

, который выглядит так:

class Log4JLogger(val logger: Logger) extends LiftLogger {
  override def trace(msg: => AnyRef) = if (isTraceEnabled) logger.trace(msg)
}

Обратите внимание, что msg является вызовом по имени и не будет оцениваться, если isTraceEnabled не true, поэтому создание красивой строки сообщения не требует затрат. Это работает с механизмом интерполяции slf4j, который требует синтаксического анализа сообщения об ошибке. С помощью этой модели вы можете интерполировать любое количество значений в сообщение об ошибке.

Если у вас есть отдельная черта, которая смешивает этот Log4JLogger с вашим классом, вы можете сделать

trace("The foobar from " + a + " doesn't match the foobar from " +
      b + " and you should reset the baz from " + c")

вместо

info("The foobar from {0} doesn't match the foobar from {1} and you should reset the baz from {c},
     Array(a, b, c))
14
ответ дан 23 November 2019 в 21:22
поделиться

Я немного поработал над чертой Logging в scalax и создал черту, которая также интегрировала MessageFormat на основе .

Тогда все выглядит примерно так:

class Foo extends Loggable {
    info( "Dude, I'm an {0} with {1,number,#}", "Log message", 1234 )
}

Пока нам нравится этот подход.

Реализация:

trait Loggable {

    val logger:Logger = Logging.getLogger(this)

    def checkFormat(msg:String, refs:Seq[Any]):String =
        if (refs.size > 0) msgfmtSeq(msg, refs) else msg 

    def trace(msg:String, refs:Any*) = logger trace checkFormat(msg, refs)

    def trace(t:Throwable, msg:String, refs:Any*) = logger trace (checkFormat(msg, refs), t)

    def info(msg:String, refs:Any*) = logger info checkFormat(msg, refs)

    def info(t:Throwable, msg:String, refs:Any*) = logger info (checkFormat(msg, refs), t)

    def warn(msg:String, refs:Any*) = logger warn checkFormat(msg, refs)

    def warn(t:Throwable, msg:String, refs:Any*) = logger warn (checkFormat(msg, refs), t)

    def critical(msg:String, refs:Any*) = logger error checkFormat(msg, refs)

    def critical(t:Throwable, msg:String, refs:Any*) = logger error (checkFormat(msg, refs), t)

}

/**
 * Note: implementation taken from scalax.logging API
 */
object Logging {  

    def loggerNameForClass(className: String) = {  
        if (className endsWith "$") className.substring(0, className.length - 1)  
        else className  
    }  

    def getLogger(logging: AnyRef) = LoggerFactory.getLogger(loggerNameForClass(logging.getClass.getName))  
}
7
ответ дан 23 November 2019 в 21:22
поделиться

Вам следует взглянуть на библиотеку scalax: http://scalax.scalaforge.org/ В этой библиотеке есть черта Logging, использующая sl4j в качестве бэкэнда. Используя эту черту, вы можете легко регистрироваться (просто используйте поле регистратора в классе, наследующем признак).

4
ответ дан 23 November 2019 в 21:22
поделиться

Еще не пробовал, но Configgy выглядит многообещающим как для конфигурации, так и для ведения журнала:

http://github.com/robey/configgy/tree/master

3
ответ дан 23 November 2019 в 21:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: