1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Lexers
class IecST < RegexLexer
tag 'iecst'
title "IEC 61131-3 Structured Text"
desc 'Structured text is a programming language for PLCs (programmable logic controllers).'
filenames '*.awl', '*.scl', '*.st'
mimetypes 'text/x-iecst'
def self.keywords
blocks = %w(
PROGRAM CONFIGURATION INITIAL_STEP INTERFACE FUNCTION_BLOCK FUNCTION ACTION TRANSITION
TYPE STRUCT STEP NAMESPACE LIBRARY CHANNEL FOLDER RESOURCE
VAR_ACCESS VAR_CONFIG VAR_EXTERNAL VAR_GLOBAL VAR_INPUT VAR_IN_OUT VAR_OUTPUT VAR_TEMP VAR
CONST METHOD PROPERTY
CASE FOR IF REPEAT WHILE
)
@keywords ||= Set.new %w(
AT BEGIN BY CONSTANT CONTINUE DO ELSE ELSIF EXIT EXTENDS FROM GET GOTO IMPLEMENTS JMP
NON_RETAIN OF PRIVATE PROTECTED PUBLIC RETAIN RETURN SET TASK THEN TO UNTIL USING WITH
__CATCH __ENDTRY __FINALLY __TRY
) + blocks + blocks.map {|kw| "END_" + kw}
end
def self.types
@types ||= Set.new %w(
ANY ARRAY BOOL BYTE POINTER STRING
DATE DATE_AND_TIME DT TIME TIME_OF_DAY TOD
INT DINT LINT SINT UINT UDINT ULINT USINT
WORD DWORD LWORD
REAL LREAL
)
end
def self.literals
@literals ||= Set.new %w(TRUE FALSE NULL)
end
def self.operators
@operators ||= Set.new %w(AND EQ EXPT GE GT LE LT MOD NE NOT OR XOR)
end
state :whitespace do
# Spaces
rule %r/\s+/m, Text
# // Comments
rule %r((//).*$\n?), Comment::Single
# (* Comments *)
rule %r(\(\*.*?\*\))m, Comment::Multiline
# { Comments }
rule %r(\{.*?\})m, Comment::Special
end
state :root do
mixin :whitespace
rule %r/'[^']+'/, Literal::String::Single
rule %r/"[^"]+"/, Literal::String::Symbol
rule %r/%[IQM][XBWDL][\d.]*|%[IQ][\d.]*/, Name::Variable::Magic
rule %r/\b(?:D|DT|T|TOD)#[\d_shmd:]*/i, Literal::Date
rule %r/\b(?:16#[\d_a-f]+|0x[\d_a-f]+)\b/i, Literal::Number::Hex
rule %r/\b2#[01_]+/, Literal::Number::Bin
rule %r/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, Literal::Number::Float
rule %r/\b[\d.,_]+/, Literal::Number
rule %r/\b[A-Z_]+\b/i do |m|
name = m[0].upcase
if self.class.keywords.include?(name)
token Keyword
elsif self.class.types.include?(name)
token Keyword::Type
elsif self.class.literals.include?(name)
token Literal
elsif self.class.operators.include?(name)
token Operator
else
token Name
end
end
rule %r/S?R?:?=>?|&&?|\*\*?|<[=>]?|>=?|[-:^\/+#]/, Operator
rule %r/\b[a-z_]\w*(?=\s*\()/i, Name::Function
rule %r/\b[a-z_]\w*\b/i, Name
rule %r/[()\[\].,;]/, Punctuation
end
end
end
end
|