<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.7.3">Jekyll</generator><link href="https://mateiw.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://mateiw.github.io/" rel="alternate" type="text/html" /><updated>2018-05-06T20:56:48+00:00</updated><id>https://mateiw.github.io/</id><title type="html">Matei</title><subtitle>Java/Linux dev</subtitle><entry><title type="html">Easy intro to writing a BASIC interpreter (with ANTLR)</title><link href="https://mateiw.github.io/antlr-intro/" rel="alternate" type="text/html" title="Easy intro to writing a BASIC interpreter (with ANTLR)" /><published>2017-11-26T00:00:00+00:00</published><updated>2017-11-26T00:00:00+00:00</updated><id>https://mateiw.github.io/antlr-intro</id><content type="html" xml:base="https://mateiw.github.io/antlr-intro/">&lt;p&gt;Getting started with parsing can be a bit daunting in the beginning. There’s a lot of 
information to be digested before even a simple parser can be written.
This is yet another attempt to present the things in a simple and straightforward manner.
Since I very much believe in learning by doing let’s just try to write a simple BASIC interpreter.&lt;/p&gt;

&lt;h3 id=&quot;the-plan&quot;&gt;The plan&lt;/h3&gt;
&lt;p&gt;Basically we need two things for our very simple interpreter:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The parser. It’s job is to consume a stream of character and create a higher level representation of
our program.&lt;/li&gt;
  &lt;li&gt;The interpreter. It takes the higher representation produced by the parser and executes it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-tools&quot;&gt;The tools&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;A grammar. This defines the structure of our language.&lt;/li&gt;
  &lt;li&gt;A parser generator. We’ll use ANTLR. It’s a popular tool and has good documentation and support.
We’ll use it to generate a parser that can ingest a program with our own defined syntax.&lt;/li&gt;
  &lt;li&gt;ANTLR plugin for Maven to make our life easy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;source-code&quot;&gt;Source code&lt;/h3&gt;

&lt;p&gt;You can find the Git repo for this article at &lt;a href=&quot;https://github.com/mateiw/littlebasic&quot;&gt;https://github.com/mateiw/littlebasic&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-language&quot;&gt;The language&lt;/h3&gt;

&lt;p&gt;BASIC comes in many variants. Since the goal here is just to play with ANTLR we’ll just define our own very simple BASIC dialect.&lt;/p&gt;

&lt;p&gt;An simple program could be like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;REM Greatest common divisor
INPUT &quot;A=&quot; ain
INPUT &quot;B=&quot; bin
a = VAL(ain)
b = VAL(bin)

WHILE b &amp;gt; 0
    t = a MOD b
    a = b
    b = t
END

PRINT &quot;GCD=&quot; + a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Although quite simple it should be enough to cover the basic (no pun intended) concepts.&lt;/p&gt;

&lt;h3 id=&quot;the-grammar&quot;&gt;The grammar&lt;/h3&gt;

&lt;p&gt;To get started we have to to defined the grammar of our toy language. Like a human grammar this will define what words and sentences are acceptable in our language.&lt;/p&gt;

&lt;p&gt;The very first thing we need is a the so called lexer grammar. This is responsible for breaking up the continuous stream of character that constitutes
our program into recognizable tokens like literals, strings, operators, etc.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-antlrv4&quot;&gt;lexer grammar LBTokens; // note &quot;lexer grammar&quot;

// operators
MUL : '*' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
EXP : '^' ;
MOD : 'MOD' ;

// logical
NEQ : '&amp;lt;&amp;gt;' ;
GTE : '&amp;gt;=' ;
LTE : '&amp;lt;=' ;
GT  : '&amp;gt;' ;
LT  : '&amp;lt;' ;
EQ  : '=' ;

// relational
AND : 'AND' | 'and' ;
OR  : 'OR' | 'or' ;
NOT : 'NOT' | 'not' ;

// other
COMMA  : ',' ;
LPAREN : '(' ;
RPAREN : ')' ;

// functions
LEN : 'LEN' | 'len' ;
VAL : 'VAL' | 'val' ;
ISNAN   : 'ISNAN' | 'isnan' ;

// keywords
PRINT   : 'PRINT' | 'print' ;
INPUT   : 'INPUT' | 'input' ;
LET     : 'LET' | 'let' ;
REM     : 'REM' | 'rem' ;
IF      : 'IF' | 'if' ;
THEN    : 'THEN' | 'then' ;
ELSE    : 'ELSE' | 'else' ;
END     : 'END' | 'end';
FOR     : 'FOR' | 'for' ;
WHILE   : 'WHILE' | 'while' ;
REPEAT  : 'REPEAT' | 'repeat' ;
UNTIL   : 'UNTIL' | 'until' ;
STEP    : 'STEP' | 'step' ;
NEXT    : 'NEXT' | 'next' ;
TO      : 'TO' | 'to' ;
CONTINUE    : 'CONTINUE' | 'continue' ;
EXIT    : 'EXIT' | 'EXIT' ;

// comments
COMMENT : REM ~[\r\n]* ;

// literals
ID              : [a-zA-Z]+ ;  // match identifiers
NUMBER          : [0-9]+ ('.' [0-9]+)?;   // match integers
STRINGLITERAL   : '&quot;' ~ [&quot;\r\n]* '&quot;' ;
DOLLAR          : '$' ;
NEWLINE         :'\r'? '\n' ;  // return newlines to parser (end-statement signal)
WS              : [ \t]+ -&amp;gt; skip ; // toss out whitespace
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the most part this is pretty self explanatory.&lt;/p&gt;

&lt;p&gt;The last part, the comments and literals, uses some more interesting tricks.&lt;/p&gt;

&lt;p&gt;In case of the comments we want to keep things simple and only allow one lined comments. So we match any
 line starting with &lt;code class=&quot;highlighter-rouge&quot;&gt;REM&lt;/code&gt; and any character up to newline. &lt;code class=&quot;highlighter-rouge&quot;&gt;~[\r\n]&lt;/code&gt; means any character except &lt;code class=&quot;highlighter-rouge&quot;&gt;\r&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;\n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The numbers should be clear for those familiar with regular expressions. &lt;code class=&quot;highlighter-rouge&quot;&gt;[0-9]+ ('.' [0-9]+)?&lt;/code&gt; means one ore more 
digits followed optionally by &lt;code class=&quot;highlighter-rouge&quot;&gt;.&lt;/code&gt; and one or more decimals.&lt;/p&gt;

&lt;p&gt;Since in our language the spaces and tabs are not significant we just want to ignore them, therefore
&lt;code class=&quot;highlighter-rouge&quot;&gt;[ \t]+  -&amp;gt; skip&lt;/code&gt;. The &lt;code class=&quot;highlighter-rouge&quot;&gt;-&amp;gt; skip&lt;/code&gt; statement is a lexer command that instructs Antlr to, well, skip to the next token.&lt;/p&gt;

&lt;p&gt;Now, with the lexer grammar in place we can proceed to writing the parser grammar. The parser grammar will take the stream of 
tokens produced by the lexer grammar and will try to match them using the following rules.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-antlrv4&quot;&gt;grammar LittleBasic;

// imports the other tokens and the grammar for expressions
import LBExpression, LBTokens;

// a programm is a block followed by an end-of-file
prog: block EOF; 

// the list of accepted statements
statement
    : letstmt
    | printstmt
    | inputstmt
    | ifstmt
    | forstmt
    | whilestmt
    | repeatstmt
    | continuestmt
    | exitstmt
    | COMMENT;

// a block is a list of statementes where each statement is followed by
// either a newline or the end of file
block
    : (statement (NEWLINE+ | EOF))*
    ;

// variable assignation. The LET keyword is optional here
letstmt
    : LET? vardecl EQ expression
    ;

// the name of the variable with an optional suffix
vardecl
    : varname varsuffix?
    ;

// the name of the variable must be a valid identifier
varname
    : ID
    ;

// the only acceptable suffix is the $ sign
varsuffix
    : DOLLAR
    ;

// PRINT expr
printstmt
    : PRINT expression;

// INPUT &quot;something=&quot; var
inputstmt
    : INPUT string vardecl
    ;

// IF expr
// THEN
// ... do smth
// ELSE
// ... something else
// END
ifstmt
    : IF expression NEWLINE* THEN NEWLINE+ block elifstmt* elsestmt? END
    ;

elifstmt
    : ELSE IF expression NEWLINE* THEN NEWLINE+ block
    ;

elsestmt
    : ELSE NEWLINE+ block
    ;

// FOR i = 1 TO 10 
//   .. do smth 
// NEXT
forstmt
    : FOR vardecl EQ expression TO expression (STEP expression)? NEWLINE+ block NEXT
    ;

// WHILE expr
//   .. do smth
// END
whilestmt
    : WHILE expression NEWLINE+ block END
    ;

// REPEAT
//  .. do smth
// UNTIL expr
repeatstmt
    : REPEAT NEWLINE+ block NEWLINE* UNTIL expression
    ;

// CONTINUE in FOR/WHILE
continuestmt
    : CONTINUE
    ;

// EXIT
exitstmt
    : EXIT
    ;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again this should be self explanatory for the most part.&lt;/p&gt;

&lt;h3 id=&quot;generating-the-parser&quot;&gt;Generating the parser&lt;/h3&gt;

&lt;p&gt;Since we’re using Maven it’s just a matter of using the &lt;a href=&quot;http://www.antlr.org/api/maven-plugin/latest/index.html&quot;&gt;ANTLR plugin&lt;/a&gt;.
By default the plugin binds to the &lt;code class=&quot;highlighter-rouge&quot;&gt;generate-sources&lt;/code&gt; phase of Maven lifecycle. It reads the grammar
 files from the &lt;code class=&quot;highlighter-rouge&quot;&gt;src/main/antlr4/basic&lt;/code&gt; directory and then produces &lt;code class=&quot;highlighter-rouge&quot;&gt;.java&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;.tokens&lt;/code&gt; files in the output directory
  &lt;code class=&quot;highlighter-rouge&quot;&gt;target/generated-sources/antlr4&lt;/code&gt;. The generated Java files then become available in the build path.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;nt&quot;&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.antlr&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;antlr4-maven-plugin&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.6&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;libDirectory&amp;gt;&lt;/span&gt;${basedir}/src/main/antlr4/basic&lt;span class=&quot;nt&quot;&gt;&amp;lt;/libDirectory&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;antlr&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;antlr4&lt;span class=&quot;nt&quot;&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-interpreter&quot;&gt;The interpreter&lt;/h3&gt;

&lt;p&gt;With the parsing part now done it’s time to execute our program. Generally there are two ways to approach the problem of
 executing a program. Either compile it into some executable form or use another program to intepret it.&lt;/p&gt;

&lt;p&gt;For the sake of simplicity we’ll use interpreter. Fortunately ANTLR already provides an API to help us with this task.&lt;/p&gt;

&lt;p&gt;After the parsing is done, ANTLR produces a parse tree. As the name suggests it’s a tree representation of the syntax of 
our program. In case of the example above it looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;parse_tree.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Interpreting the code is a matter of walking the parse tree and executing some action for each statement that’s encountered.&lt;/p&gt;

&lt;p&gt;We’re gonna use the &lt;code class=&quot;highlighter-rouge&quot;&gt;LittleBasicBaseVisitor&amp;lt;Value&amp;gt;&lt;/code&gt; class generated by ANTLR. This class implements a &lt;code class=&quot;highlighter-rouge&quot;&gt;visit(tree)&lt;/code&gt; method
 that pretty much does what the name suggests, namely visits each node of the given tree.&lt;/p&gt;

&lt;p&gt;Additionally this class has callback methods that will be invoked for each node. By default these methods don’t do anything
 but we’re free to override them and plug in our own custom logic. To do this we’ll simply extends this class:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LittleBasicVisitor&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LittleBasicBaseVisitor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    
    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;visitProg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LittleBasicParser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ProgContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ....&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        
    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;visitString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LittleBasicParser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;StringContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can add here all our interpreter logic. Calling &lt;code class=&quot;highlighter-rouge&quot;&gt;LittleBasicVisitor.visit(tree)&lt;/code&gt; will invoke our custom logic for
 each statement that is encountered by the visitor.&lt;/p&gt;

&lt;p&gt;We won’t go into the details of how the interpreter implementation. Just take a look at the &lt;code class=&quot;highlighter-rouge&quot;&gt;LittleBasicVisitor&lt;/code&gt; class. Since it’s just a toy interpreter the code should be
 quite self explanatory.&lt;/p&gt;

&lt;h3 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h3&gt;

&lt;p&gt;Now that we have the grammars and the interpreter let’s see how to make the various parts work together.&lt;/p&gt;

&lt;p&gt;In the &lt;code class=&quot;highlighter-rouge&quot;&gt;Interpreter&lt;/code&gt; class you’ll find this code:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InputStream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;progrIn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// wrap the input stream&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ANTLRInputStream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ANTLRInputStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;progrIn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// initialize the lexer with the input stream&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LittleBasicLexer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lexer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LittleBasicLexer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// initialize the tokens stream with the lexer&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;CommonTokenStream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tokens&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CommonTokenStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// initialize the parser with the tokens stream&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LittleBasicParser&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LittleBasicParser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tokens&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// set the error handling strategy&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setErrorHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BailErrorStrategy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// remove default error listeners&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;removeErrorListeners&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// set our custom error listener&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addErrorListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ErrorListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stderrPrint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// parse the input into a parse tree&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ParseTree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Memory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// init our custom visitor&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;LittleBasicVisitor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LittleBasicVisitor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stdoutPrint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stderrPrint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// visit the parse tree and interpret the program&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;visit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InterpreterException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// handle interpreter errors&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;stderrPrint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParseCancellationException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// handle parser errors&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getCause&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InputMismatchException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;InputMismatchException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputEx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InputMismatchException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getCause&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Utils&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;formatErrorMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;inputEx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getOffendingToken&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;inputEx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getOffendingToken&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getCharPositionInLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt;
                        &lt;span class=&quot;s&quot;&gt;&quot;Syntax error&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;stderrPrint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we have a simple but fully functional Basic interpreter. Go ahead and build the project:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mvn install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and run it:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; LittleBasic.jar /path/to/MyAwesomeProgram.bas
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;</content><author><name></name></author><summary type="html">Getting started with parsing can be a bit daunting in the beginning. There’s a lot of information to be digested before even a simple parser can be written. This is yet another attempt to present the things in a simple and straightforward manner. Since I very much believe in learning by doing let’s just try to write a simple BASIC interpreter.</summary></entry><entry><title type="html">Suse Open Build Service tutorial</title><link href="https://mateiw.github.io/obs-tutorial/" rel="alternate" type="text/html" title="Suse Open Build Service tutorial" /><published>2016-06-30T00:00:00+00:00</published><updated>2016-06-30T00:00:00+00:00</updated><id>https://mateiw.github.io/obs-tutorial</id><content type="html" xml:base="https://mateiw.github.io/obs-tutorial/">&lt;p&gt;Suse’s &lt;a href=&quot;https://build.opensuse.org/&quot;&gt;Open Build Service&lt;/a&gt; (OBS)  is a tool for building and distributing software packages for various Linux distros. The main target is of course OpenSUSE and SLES but there’s also support for RedHat, Debian, Ubuntu and Arch.&lt;/p&gt;

&lt;p&gt;It consists of a web service that takes care of building the packages and publish them to repositories and of a command line tool (osc).&lt;/p&gt;

&lt;p&gt;OpenSuse uses RPM as its packaging format. Building RPMs is possible using the rpmbuild command but the osc command line tool makes it much more convenient to build the package locally or remotely in OBS.&lt;/p&gt;

&lt;p&gt;If building locally osc can pull the build dependencies of the package and prepare an isolated environment where the build will take place. Under the hood it (usually) creates an chroot with all the needed dependencies installed and it executes the rpmbuild in that environment. So no need to fiddle with the packages installed on your machine to make the build work.&lt;/p&gt;

&lt;p&gt;Now let’s see how it works in practice. Let’s build our first package with OBS. Altough some of the steps outlined below can be performed using the web GUI I’ll focus on the command line client utility &lt;code class=&quot;highlighter-rouge&quot;&gt;osc&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;1-sign-up-to-obs-and-install-the-client-tools&quot;&gt;1. Sign up to OBS and install the client tools&lt;/h3&gt;

&lt;p&gt;The first obvious step is to get an account on &lt;a href=&quot;https://build.opensuse.org/&quot;&gt;Open Build Service&lt;/a&gt;. Let’s asume for the rest of the tutorial that your OBS username is &lt;code class=&quot;highlighter-rouge&quot;&gt;obsuser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You will also need the client tools installed. On OpenSuse this is only a matter of running:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~&amp;gt; zypper in osc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you use another distro you may also get &lt;code class=&quot;highlighter-rouge&quot;&gt;osc&lt;/code&gt; from &lt;a href=&quot;http://download.opensuse.org/repositories/openSUSE:/Tools/&quot;&gt;OpenSUSE Tools&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;2-checkout-your-home-project&quot;&gt;2. Checkout your home project&lt;/h3&gt;

&lt;p&gt;Once you log in you can go to your home project. This is created by default by OBS and it has the name &lt;code class=&quot;highlighter-rouge&quot;&gt;home:obsuser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To check it out run:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~&amp;gt; osc checkout home:obsuser
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;3-create-the-package-in-obs&quot;&gt;3. Create the package in OBS&lt;/h3&gt;

&lt;p&gt;Next is of course the package. For the sake of simplicity let’s package &lt;a href=&quot;https://www.mirbsd.org/jupp&quot;&gt;jupp&lt;/a&gt;, a portable version of JOE’s Own Editor. To create the package execute the following in the directory where you’ve checked out your home project:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser&amp;gt; osc meta pkg -e home:obsuser jupp 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will open your text default editor with an empty xml template. Fill in the details of the package like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt; 
&lt;span class=&quot;nt&quot;&gt;&amp;lt;package&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jupp&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;A text editor&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Title of package --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;
    This is the portable version of JOE’s Own Editor, which is currently developed at sourceforge
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- for long description --&amp;gt;&lt;/span&gt; 
. . .
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://www.mirbsd.org/jupp&lt;span class=&quot;nt&quot;&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
. . . 
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/package&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After saving and exiting your editor osc will send the details to OBS.&lt;/p&gt;

&lt;p&gt;Go to the directory that contains &lt;code class=&quot;highlighter-rouge&quot;&gt;home:obsuser&lt;/code&gt; and update the project:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/&amp;gt; osc up 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will create an empty directory home:obsuser/jupp.&lt;/p&gt;

&lt;h3 id=&quot;4-define-repositories&quot;&gt;4. Define repositories&lt;/h3&gt;

&lt;p&gt;You need at least one repository for your project. Usually here you specify a distro version against which you want you package built. In my case I want to build packages for OpenSUSE Leap 42.1.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc meta prj -e home:obsuser
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Define the repository inside the XML. The &lt;path&gt; element points to another OBS project, in this case the project for Leap 42.1.&lt;/path&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt; 
&lt;span class=&quot;nt&quot;&gt;&amp;lt;project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;home:mateialbu&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;title/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;description/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;person&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;userid=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;obsuser&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;maintainer&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;repository&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;openSUSE_Leap_42.1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;path&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;project=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;openSUSE:Leap:42.1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;repository=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;standard&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;arch&amp;gt;&lt;/span&gt;x86_64&lt;span class=&quot;nt&quot;&gt;&amp;lt;/arch&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;arch&amp;gt;&lt;/span&gt;i586&lt;span class=&quot;nt&quot;&gt;&amp;lt;/arch&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/repository&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;5-create-the-spec-file&quot;&gt;5. Create the spec file&lt;/h3&gt;

&lt;p&gt;Now it’s time for the real work. The .spec file contains both metadata and build instructions. This is the central piece of an RPM package.&lt;/p&gt;

&lt;p&gt;So let’s create one for our package. Use you favourite editor to create a file named jupp.spec. At least on OpenSUSE you get a template .spec file where you can fill the details. Paste the following into your file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# spec file for package jupp&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Copyright (c) 2016 SUSE LINUX Products GmbH, Nuernberg, Germany.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# All modifications and additions to the file contributed by third parties&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# remain the property of their copyright owners, unless otherwise agreed&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# upon. The license for this file, and modifications and additions to the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# file, is the same license as for the pristine package itself (unless the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# license for the pristine package is not an Open Source License, in which&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# case the license is the MIT License). An &quot;Open Source License&quot; is a&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# license that conforms to the Open Source Definition (Version 1.9)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# published by the Open Source Initiative.&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Please submit bugfixes or comments via http://bugs.opensuse.org/&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;

Name:           jupp
Version:        3.1jupp28
Release:        0
License:        GPL-1.0
Summary:        A Text Editor
Url:            https://www.mirbsd.org/jupp
Group:          Productivity/Editors/Other
Source:         https://www.mirbsd.org/MirOS/dist/jupp/joe-3.1jupp28.tgz
Conflicts:      joe
BuildRequires:  automake
BuildRequires:  ncurses-devel
BuildRoot:      %&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;_tmppath&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;-%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;version&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-build&lt;/span&gt;

%description
This is the portable version of JOE’s Own Editor, which is currently developed at sourceforge, licenced under the GNU General Public License, Version 1, using autoconf/automake. This version has been enhanced by several functions intended &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;programmers or other professional users, and has a lot of bugs fixed. It is based upon an older version of joe because these behave better overall.

%prep
%setup &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; jupp
chmod +x configure

%build
%configure &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;_prefix&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

make %&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;?_smp_mflags&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

%install
make install &lt;span class=&quot;nv&quot;&gt;DESTDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;buildroot&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; %&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;?_smp_mflags&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;jmacs jpico jstar rjoe&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;ln &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; joe.1.gz %&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;buildroot&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;_mandir&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/man1/&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;.1.gz
&lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;rm &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; %&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;buildroot&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;_datadir&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/lang

%post

%postun

%files
%defattr&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;-,root,root&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;_mandir&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/man1/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
%config %&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;_sysconfdir&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/joe/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
%dir %&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;_sysconfdir&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/joe
%&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;_bindir&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;

%changelog&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A detailed explanation of the .spec file is out of scope of this tutorial but the file is pretty self explanatory.&lt;/p&gt;

&lt;h3 id=&quot;6-test-the-build-locally&quot;&gt;6. Test the build locally&lt;/h3&gt;

&lt;p&gt;To test the spec file, trigger the build locally. In the package directory run:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If everything goes well osc will inform you that the resulted rpm is in:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/var/tmp/build-root/openSUSE_Leap_42.1-x86_64/home/abuild/rpmbuild/RPMS/x86_64/jupp-3.1jupp28-0.x86_64.rpm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;7-add-the-files-to-the-project&quot;&gt;7. Add the files to the project&lt;/h3&gt;

&lt;p&gt;osc works similarly to a VCS like git. Firs you have to add the files:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc add &amp;lt;file&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;or simply&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc addremove 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to add/remove all files in the package dir.&lt;/p&gt;

&lt;h3 id=&quot;8-add-the-changelog&quot;&gt;8. Add the changelog&lt;/h3&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc vc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will open your default editor with a template. Fill the initial message:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;------------------------------------------------------------------- 
Wed Jun 29 13:40:29 UTC 2016 - &amp;lt;user.email&amp;gt;
- Initial version of the package
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A new file jupp.changes will be written in the package directory.&lt;/p&gt;

&lt;p&gt;To check the status before committing run:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;osc status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To add jupp.changes do a:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc add jupp.changes 
A    jupp.changes 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now finally everything ready to commit:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc commit 
Sending    joe-3.1jupp28.tgz 
Sending    jupp.spec 
Sending    jupp.changes 
Transmitting file data .. 
Committed revision 1.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;9-check-the-build-status&quot;&gt;9. Check the build status&lt;/h3&gt;

&lt;p&gt;After you commit OBS will schedule the build. To check the status you can either go to the web interface or use osc:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc results
openSUSE_Leap_42.1   x86_64     finished*
openSUSE_Leap_42.1   i586       succeeded
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;10-download-and-install-the-package&quot;&gt;10. Download and install the package&lt;/h3&gt;

&lt;p&gt;You can download and install the package from the web interface. Go to the package page and look for the aptly named “Download package” link. On OpenSuse you’ll get the option to use One Click Install.&lt;/p&gt;

&lt;p&gt;If you prefer the command line another option is to use add the repository and install the package. First get the repo url:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; osc repourls 
http://download.opensuse.org/repositories/home:/obsuser/openSUSE_Leap_42.1/home:obsuser.repo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then simply add the repository using zypper and install the package:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myuser@linux:~/home:obsuser/jupp&amp;gt; sudo zypper ar http://download.opensuse.org/repositories/home:/obsuser/openSUSE_Leap_42.1/home:obsuser.repo
Repository 'home:obsuser (openSUSE_Leap_42.1)' successfully added 
Enabled     : Yes
Autorefresh : No
GPG Check   : Yes
Priority    : 99
URI         : http://download.opensuse.org/repositories/home:/obsuser/openSUSE_Leap_42.1/ 

myuser@linux:~/home:obsuser/jupp&amp;gt; sudo zypper ref
. . . 
myuser@linux:~/home:obsuser/jupp&amp;gt; sudo zypper in jupp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And voila! You have jupp installed on your machine.&lt;/p&gt;

&lt;h3 id=&quot;further-resources&quot;&gt;Further resources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.opensuse.org/openSUSE:Build_Service_Tutorial&quot;&gt;OpenSuse’s Build Service Tutorial&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.opensuse.org/openSUSE:Build_Service_Tips_and_Tricks&quot;&gt;Build Service Tips and Tricks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/index.html&quot;&gt;Fedora’s RPM Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><summary type="html">Suse’s Open Build Service (OBS) is a tool for building and distributing software packages for various Linux distros. The main target is of course OpenSUSE and SLES but there’s also support for RedHat, Debian, Ubuntu and Arch.</summary></entry></feed>